What are Linux Containers
LinuX Containers (LXC) is an OS-level virtualization that allows multiple Linux systems to run on a single physical machine in a multi-tenant arrangement. This type of virtualization is extremely lightweight with every virtual machine (container) being mapped into the booted host OS obviating the need to boot from their own OS image; all the needed resources of the host machine — CPU, the filesystem, system libraries, network access, etc. — are received by containers on a shared basis. Basically, LXC re-uses the same single kernel of the host machine for all hosted containers.
LXC derives its functionality from the modern Linux kernel features cgroups and namespaces introduced with Linux kernel version 2.6.24; initial release of LXC was done in August 2008.
The cgroups (control groups) functionality controls quotas and prioritization of resources (CPU, memory, block I/O, network, etc.) allocated from the underlying host machine, and the namespace feature deals with application isolation.
In this blog, I will show how to use the common LXC commands that would help you quickly get up to speed with LXC.
In my tests, I used Ubuntu 14.04 Desktop as the host OS from which I downloaded and installed the LXC package from the Ubuntu software repository using this command:
sudo apt-get install lxc
The version of the LXC package I used in my tests was 1.0.7-0ubuntu0.1.
In commands below I used privileged container mode with all the commands executed using the root account. You can also create non-privileged containers and run them using non-root user accounts; bear in mind that non-privileged containers are rather limited in the scope of their capabilities and I am not reviewing them in this post.
To avoid the dictate of typing sudo in front of each privileged command, I simply switched to root using this command:
sudo -i
The list of LXC tools available in the LXC package can be quickly produced by typing
lxc-
and hitting the Tab key twice. Here is what I got in my test:
lxc-attach lxc-destroy lxc-start lxc-autostart lxc-device lxc-start-ephemeral lxc-cgroup lxc-execute lxc-stop lxc-checkconfig lxc-freeze lxc-unfreeze lxc-clone lxc-info lxc-unshare lxc-config lxc-ls lxc-usernsexec lxc-console lxc-monitor lxc-wait lxc-create lxc-snapshot
You can get help on every tool by running the tool as a command with the –help flag, e.g.:
lxc-ls --help
In text below, I will sometimes be referring to LXC tools listed above as LXC commands.
Enter the following command:
lxc-ls --fancy
you should see the header of an empty container table as we have not yet created any containers:
NAME STATE IPV4 IPV6 AUTOSTART
Note: you can also use an abbreviated version of the command flags which, for the most part, take the first letter of the full command and use a single dash (‘-‘) in front of it, e.g.
lxc-ls -f
Creating a Container
Let’s create our first LXC container. Enter the following command:
lxc-create --template ubuntu --name C1
Note: You could also use -t and -n short-hand versions of the template and name command flags, respectively.
This command will go ahead and create the C1 container using the ubuntu LXC template. On Ubuntu OS, the LXC templates are located under the /usr/share/lxc/templates folder, and include templates for various Linux distros, including CentOS, Debian , Fedora, Oracle, Ubuntu and many others. In our command, the template ubuntu command flag was mapped to the /usr/share/lxc/templates/lxc-ubuntu template.
When the command completes (it may take a while), you will see the following message:
## # The default user is 'ubuntu' with password 'ubuntu'! # Use the 'sudo' command to run tasks as root in the container. ##
Now, if you issue this command:
lxc-ls -f
You should see our newly created container listed with the STOPPED status.
NAME STATE IPV4 IPV6 AUTOSTART ------------------------------------ C1 STOPPED - - NO
Starting a Container
Let’s start the C1 container we just created. We will use daemon mode which lets you keep your command shell from being requisitioned by the started container’s shell.
lxc-start -n C1 --daemon
Notice how fast the container got started; if you want to get start-up statistics, use the time command as in: time lxc-start -n C1 –daemon
You can harvest some useful information about the running container by executing the following command (substitute your container name for C1):
lxc-info -n C1
Your output details will differ but the nomenclature of fields will be the same :
Name: C1 State: RUNNING PID: 2726 <================== IP: 10.0.3.141 <================== CPU use: 1.09 seconds BlkIO use: 19.21 MiB Memory use: 26.77 MiB Link: vethO9BB2A TX bytes: 1.85 KiB RX bytes: 4.92 KiB Total bytes: 6.77 KiB
Note the PID: 2726 line which lists the LXC system process ID for our container as launched on the host machine. You can use this process ID to kill your container using the kill -9 2726 command, which is, generally, not a good idea; LXC offers your the lxc-stop command for that.
Also note the IP address of the started container: 10.0.3.141, in my case; you can get the running container’s IP address using the lxc-ls -f command as well.
Let’s check disk usage on the host machine by running this command:
df -h
The command will produce output similar to this one:
Filesystem Size Used Avail Use% Mounted on /dev/sda1 26G 5.2G 19G 22% / none 4.0K 0 4.0K 0% /sys/fs/cgroup udev 2.0G 4.0K 2.0G 1% /dev tmpfs 395M 1.4M 394M 1% /run none 5.0M 0 5.0M 0% /run/lock none 2.0G 76K 2.0G 1% /run/shm none 100M 48K 100M 1% /run/user
Now we are going to execute this command in our container.
Connect to the container using the default SSH client; substitute your IP address for one used in the command; the password is ubuntu:
ssh ubuntu@10.0.3.141
You will be dropped at the container’s prompt.
Check disk usage in the container:
df -h
You will get details that, for the most part, match-up those of the host machine; however, the udev FS is gone and some of the file system names are different, e.g. the root (‘/’) file system name is represented by the UUID-based moniker (/disk/by-uuid/e547fcf9-6c1c-4619-856e-d9b4426ac0c5, in my case).
Filesystem Size Used Avail Use% Mounted on /dev/disk/by-uuid/e547fcf9-6c1c-4619-856e-d9b4426ac0c5 26G 5.2G 19G 22% / none 4.0K 0 4.0K 0% /sys/fs/cgroup none 395M 56K 395M 1% /run none 5.0M 0 5.0M 0% /run/lock none 2.0G 0 2.0G 0% /run/shm none 100M 0 100M 0% /run/user
On the host machine, the root file system of our C1 container is mapped to this physical location: /var/lib/lxc/C1/rootfs; so, the default ubuntu user’s home directory is located in /var/lib/lxc/C1/rootfs/home/ubuntu.
Your container is, pretty much, a full blown Ubuntu OS with the apt-get tool pre-installed so that you can start using it to download and configure the needed software; you also have a bunch of useful services that you can list using this command:
service --status-all
In my container, I got these services pre-installed courtesy of the ubuntu template:
console-setup cron killprocs kmod networking ondemand procps rc.local resolvconf rsyslog sendsigs ssh sudo udev umountfs umountnfs.sh umountroot urandom
By default, the container is only visible to the outside world via the SSH port 22.
We are done with the container; disconnect from it by typing in exit.
Cloning
LXC supports cloning out of the box. Cloning is an efficient mechanism for building a cluster of servers or replicating your Dev machine setup to QA to UAT, etc.
Before you start cloning your container, it must be stopped.
You stop the container with this command (use your container name instead of C1):
lxc-stop -n C1
Enter the following command to clone the original C1 container:
lxc-clone -o C1 -n C1_Clone
It might take a while before you get your command prompt back with this message:
Created container C1_Clone as copy of C1
Suspending and Resuming Containers
There are situations where you would like to suspend processing of all requests by your container. For example, you may want to perform intrusion detection activities on machines sitting behind the one you are suspending.
You suspend your container with the lxc-freeze command and resume it with lxc-unfreeze.
First, let’s start our cloned container:
lxc-start -n C1_Clone --daemon
Now, issue this command to suspend the container:
lxc-freeze -n C1_Clone
After executing this command, all processes in the C1_Clone container will be suspended. You won’t be able to connect to a Web server (if any is installed) or SSH server; if you are on the container over an SSH link, your command execution will be suspended and your keystrokes will start getting accumulated in the command buffer where they would sit until you unfreeze the container with the following command:
lxc-unfreeze -n C1_Clone
The above command will re-activate all the processes in the container and they will get busy processing any enqueued commands, e.g. your SSH command buffer will get processed one command at a time.
State Change Monitoring
The LXC system offers you some nice hooks into the container lifecylce by way of the lxc-wait command. You can build your own monitoring systems that leverage this facility.
The lxc-wait command takes the container identified by its name as a parameter, and it is configured to listen (wait) for any of the following container states:
STOPPED, STARTING, RUNNING, STOPPING, ABORTING, FREEZING, FROZEN, THAWED
You can also combine states using the ‘|’ logical operator, e.g. ‘STOPPING | ABORTING’.
Open a new terminal window and enter the following command in it:
sudo lxc-wait -n C1_Clone -s 'STOPPED'
This command will block until the state of the C1_Clone container transitions to STOPPED.
Switch to the original terminal, arrange it on the desktop so that you can see the second terminal.
Stop the C1_Clone container with this command:
lxc-stop -n C1_Clone
You will see that the lxc-wait command in the second terminal gets unblocked upon receiving notification about the target container’s state change.
LXC Web Panel
For the LXC Admin browser-based UI, you can use
the LXC Web Panel.
Signing Off
That’s all the time we have for today – we are done with our overview of Linux Containers.
If you want to, you can go ahead and delete the containers using the lxc-destroy command.
Happy LXC-ing !