Containers are the future when it comes to using and shipping applications. But Linux containers or LXC can be used for more than just that. This article covers the use of LXC on a daily basis as well as for production.
Although Containers get their popularity after extensive use of docker by Docker Inc, which is in market since 2013 but linux also have their own Containers from several year from now. These native linux Containers are named LXC(or simply linux container). LXC project has been their since 2008 and is actively being maintained/supported by Cannonical Ltd. It is more of set of tools(more technically API) which gives you interface to create a container using linux namespaces and cgroups(Control Groups). Linux namespaces (mnt,pid,net,ipc,uts, user) is a feature of kernel used for different type of isolation whereas cgroups are used to set limitation over resources(mostly hardware resources like memory and disk size) use by any process.
Mount namespace(mnt): A process views different mount points other than the original system mount point. It creates a separate file system tree associated with different processes, which restricts them from making changes to the root file system.
PID namespace(pid): PID namespace isolates a process ID from the main PID hierarchy. A process inside a PID namespace can have the same PID as a process outside it, and even inside the namespace, you can have different init with PID 1.
UTS namespace: In the UTS (UNIX Timesharing System) namespace, a process can have a different set of domain names and host names than the main system. It uses sethostname() and setdomainname() to do that.
IPC namespace: This is used for inter-process communication resources isolation and POSIX message queues.
User namespace(user): This isolates user and group IDs inside a namespace, which is allowed to have the same UID or GID in the namespace as in the host machine. In your system, unprivileged processes can create user namespaces in which they have full privileges.
Network namespace(net): Inside this namespace, processes can have different network stacks, i.e., different network devices, IP addresses, routing tables, etc.
LXC is a set of tools that make it possible to use these feature and create something that is called as a container. Containers are nothing but a very lightweight VMs with less amount of isolation. This less isolation cause due to absent of hypervisor layer, which make containers to use the same kernel as of host system. But this absence also make container's more widely usable as the overhead of configuring/necessity of hypervisor has gone and now you can select which resources you wish to isolate according to your use. So lets dive into Linux Container space.
Getting Started with LXC
For our demonstration purposes I am using LXC in Ubuntu 16.04. LXC has great support on Ubuntu since LXC project is backed by Cannonical Ltd, which is also the publisher of Ubuntu operating system. But you can also install LXC on any other linux distribution through their official repositories.
In your ubuntu machine install lxc and lxc-templates by using this in your terminal
$sudo apt install lxc lxc-templates
Once you have lxc toolset install you can check your default configuration by
$sudo lxc-checkconfig
Now since we have LXC installed on our ubuntu system, we can now create our first container
$sudo lxc-create -n mycontainer -t ubuntu
This will download a ubuntu container from internet and save it in your storage with name mycontainer. you need to remember -n option, as it will be used at most of the places to give your container name. -t templatename defines the template we want to use. There are many other distribution templates available for lxc. You can find them at /usr/share/lxc/templates.
Fig 1: Available templates for lxc
You can see all available container you have created by using lxc-ls.
Creating a container doesn't mean it is running. To run the container you need to use lxc-start tool.
$lxc-start -n mycontainer
This will start your first container in background. You can check all the running containers by using lxc-ls also with passing option –fancy.
Fig: lxc-ls --fancy output showing state of container with other details
This will show the state of all your containers with little more specs. You can also use lxc-top to list the running container with resources it use.
Fig: lxc-top output
Now to start using your container all you need to do is attach to the container. To get directly access to the container as root without authentication you can use lxc-attach
$sudo lxc-attach -n mycontainer
this is mostly not recommended due to root login, so in place you can use lxc-console
$sudo lxc-console -n mycontainer
this will give you login prompt (default username is ubuntu with password as ubuntu).
To detach from the container just press Ctrl-a followed by q.
If you are using LXC for development or testing purposes then their is high probability that you came across a scenario where you require architecture system different then your current host. LXC has templates for most of the cpu arch like i836, powerpc and armhf etc.
To create the container of different architecture you just need to supply --arch= on lxc-create command. Or you can even view the full list of template and select from them through this command.
$sudo lxc-create --template download --name mycontainer
Fig: lxc-create can also use to select templates on fly.
You can stop a container using lxc-stop or freeze/pause a running container using lxc-freeze and then lxc-unfreeze to unfreeze it. lxc-destroy will delete the container image. To use these tools all you need to do is pass -n containername with these commands.
lxc-console or lxc-attach give you access to the shell inside the container but you did not always want that to happen. Many times you just want to run a single script or command inside the container. For that purpose lxc provides lxc-execute.
$sudo lxc-execute -n mycontainer – ip addr
This will give you the ip address of interfaces inside the container rather then your host.
Lxc also support cloning and snapshotting of container. To clone a container you can use
$sudo lxc-copy -n mycontainer -N newcontainer
To clone your container it must not be in running state. We will discuss the snapshotting in next section.
Configuring Linux Container
Till now we have used lxc tools for general uses. But when you are using containers in production or development environment there is more controls and option you need to make your work done.
To configure a container you must know how to use config file. But first you need to know where is your containers actually in your disk? The answer is at path /var/lib/lxc/yourcontainername*. Inside this path you will find rootfs directory which is the root of your container(also can be called backing store) and a config file.You can change this container’s path while creating container using lxc-create by passing parameter -P newpath or –lxcpath=PATH. You can even create a separate partition and use it as the root filesystem of container. The default backing store which is /var/lib/lxc/containername/rootfs* is called dir backing store. Other available options are lvm, loop, brtfs, zfs,aufs, overlayfs and rbd. With -P option you can only define the path of your containers rootfs but the container will still be dir container.
So to change the backing store you can use -B backingstoretype with lxc-create and lxc-clone (to clone it into another container of different backing store).
A strong feature that lxc come with is container's snapshot capability. You can create a snapshot using *lxc-snapshot *
Snapshot is not supported for dir based container, so before snapshot you have to clone it to container of type aufs or overlayfs.
$sudo lxc-snapshot -n mycontainer
this will save the snapshot with name snap0. Now whenever you do some uncertain changes in your container you can just create a snapshot before it and can restore it later with
$sudo lxc-snapshot -r snap0 -n mycontainer.
To list all snapshot of a Container
$sudo lxc-snapshot -L -n mycontainer
Fig: Basic snapshot operations
To configure your container every container has config file at path /var/lib/lxc/yourcontainer/config. You can use this file for almost every possible changes you can do with lxc including but not limited to networking, setting cgroups limitations, profiling and other common container related configuration. For example you can mount external folder inside container through adding following line in config file of your container
lxc.mount.entry = /mnt/share /root/share none ro,bind 0.0
We will discuss more about config file in next part of this series.
How LXC is different from docker and Vms
LXC (or LXD) is created to replace the work of Vms as they are really heavy to use and can be unmanaged if run in large amount. The only difference it has with Vms is that container have same kernel layer as of host whereas Vms provide full isolation.
So linux container are there to run a whole linux machine (or simply multiple services) inside the isolated environment provided by linux kernel. Whereas docker are replacement of traditional way of running application, by running it in isolated environment i.e docker container are made to run a single application inside there container. LXC container are even capable of nested containerization means you can even run docker or any other container inside lxc container without any issue. In general they don’t care what is running inside them all application will treated same inside the container. We will discuss little more about that comparison in next part also.
So for next part we will discuss about using config file, networking in lxc, a practical application of container, some project extension of lxc and few more topics. Stay tuned!.