Unprivileged containers in Slackware©

Part 2 - Running unprivileged containers

In Part 1 of this Unprivileged containers in Slackware article, we discussed how to arrange the system requirements to run unprivileged containers in Slackware. Please ensure the steps in Part 1 have been done before proceeding with anything you find here! In this second part we'll go through the steps to construct and run an unprivileged container in Slackware after which, in Part 3 of this series, we describe a method to provide networking for the container.

Much of the information here on this page is based on Stephane Graber's Introduction to unprivileged containers, one of a series of his excellent blog posts about LXC. Although we'll be concentrating here on how to make unprivileged containers work in the Slackware environment, reading Stephane's introduction first is highly recommended.

Having thoroughly read Stephane's post, you'll be aware that some problems remain when generating an unprivileged container directly with lxc-create. At the moment, when lxc-create is run as an ordinary user, the only valid template is the download template which downloads a premade container suitable for running in unprivileged mode.

There are now two distinct methods we can use to create an unprivileged container, the classic and the modern.

In the classic method, our strategy is to first create an ordinary root privileged container and then convert it to an unprivileged container. Such a container could then itself be made the target for the download template but we won't bother with that here - we'll just create, then run an unprivileged container. The steps involved using the classic method are:

  1. create standard root privileged container
  2. remap that container's owner & group numbers to the user's subuid & subgid
  3. move the container into the user's file space
  4. run the unprivileged container

Step 0 - Check your environment

Before going through these steps in detail, be aware that all steps from Part 1 must have been set up correctly. Ensure that when you run:
    lscgroup
it shows the newly configured control group qwerty (or whatever it was named).

Now the steps for creating an unprivileged container using the classic method:

Step 1 - Create standard root privileged container

As root, or using sudo, create a standard container with some name, say test1, with the following command:
    sudo MIRROR=http://slackware.osuosl.org lxc-create -n test1 -t slackware
This creates a container at /var/lib/lxc/test1 using the template at /usr/share/lxc/templates/lxc-slackware (from Slackware's lxc package). The container will be a minimal version of Slackware -current. Note that it will be owned by root and resides in a root owned part of the file system; we need to change that. You could run the container now (sudo lxc-start -n test1) before proceeding, just to verify its all OK, but that is not generally necessary unless you noticed strange output in the creation process.

Step 2 - Remap uids & gids

The aim of this step is to change all the owner and group ids in the container to the subuid and subgid of the user. Recall that in Part 1, we created the /etc/subuid and /etc/subgid files containing a line something like chris:100000:65536. We therefore want to change all the all uid=0 files in the container to be uid=100000, all uid=1 to be uid=100001, etc. (up to a limit of 65536). Rather than doing this by hand we use the uidmapshift tool which is driven by the container-userns-convert script, available from Serge Hallyn's nsexec files. From there, download container-userns-convert and uidmapshift.c, then compile uidmapshift with:
    gcc -o uidmapshift uidmapshift.c

Near the end of the container-userns-convert , around line 61, change the call to uidmapshift to be ./uidmapshift, then make container-userns-convert executable. We're now ready to do the conversion; run:
    sudo ./container-userns-convert test1 100000
which should quite quickly finish and, if successful, output:
    Container test1 has been converted

Step 3 - Move container to user's filespace

Just as /var/lib/lxc is the default top directory for ordinary containers, the default location for unprivileged user containers is the $HOME/.local/share/lxc directory  - if it doesn't exist, create it with:
    mkdir -p $HOME/.local/share/lxc
and ensure that each directory from $HOME to $HOME/.local/share/lxc have execute bits set e.g. chmod a+x $HOME.

Now copy or move the entire container into the user's file space:
    sudo cp -a /var/lib/lxc/test1 $HOME/.local/share/lxc/
and allow the user to edit the container and its config file with:
    sudo chown chris:users $HOME/.local/share/lxc/test1 $HOME/.local/share/lxc/test1/config
then:
   sudo chmod a+rx $HOME/.local/share/lxc/test1

Edit the config file to change any references to the container's original location, converting them to the new location e.g. change:
    lxc.rootfs = /var/lib/lxc/test1rootfs
to:
    lxc.rootfs = /home/chris/.local/share/lxc/test1/rootfs

and change:
   lxc.mount = /var/lib/lxc/test1/rootfs/etc/fstab
to:
    lxc.mount = /home/chris/.local/share/lxc/test1/rootfs/etc/fstab

Also, if it isn't there already, add the line:
    lxc.mount.auto = proc:mixed sys:ro cgroup
to the config file; then remove the proc and sysfs entries in /home/chris/.local/share/lxc/test1/rootfs/etc/fstab
The need for this may change in future versions of the Slackware template.

Before running the new unprivileged container, it is advisable to disable its klogd facility (else expect 100% cpu utilisation). Disable klogd by editing the file /home/chris/.local/share/lxc/test1/rootfs/etc/rc.d/rc.syslog, commenting out the call to /usr/sbin/klogd -c 3 -x at around line 22.

Step 4 - Run the unprivileged container

The unprivileged container should now start by running (as the ordinary user) the command:
    lxc-start -n test1
(later, lxc-start -n test1 -d may be more convenient but for now, in case of problems, its good to see the output of the container booting up). To then log in to the running container, run, in another terminal:
     lxc-console -n test1
or:
     lxc-attach -n test1

Potential Problems


Next step: Part 3 - Networking unprivileged containers

Having attached or logged into the new container, you may have noticed its minimal collection of software and already thought about how to install more. This will involve downloading software from a remote repository, for which networking of some sort will be needed. The next article, Part 3 - Running unprivileged containers, will describe how to achieve that.


Contact

Please send any questions, comments, advice etc., to Chris Willing <chris.willing _at_ linux.com>