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.
Our strategy to create an unprivileged container is therefore 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 are:
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 you are able to run:
. /etc/profile.d/lxcuser.sh
It should produce no output; its exit status should be 0.
Don't bother continuing until that works.
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
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, will
describe how to achieve that.
Contact
Please send any questions, comments,
advice etc., to Chris Willing <chris.willing _at_
iinet.net.au>