Linux Containers


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 !

  1. No comments yet.
(will not be published)

*