How to auto-start unprivileged lxc containers?

Solution 1:

I'd recommend using the handy @reboot alias in Ubuntu's cron to run lxc-autostart.

As the user that owns the unprivileged container, run crontab -e and add the following line:

@reboot lxc-autostart

Solution 2:

I think I have found a better solution than the ones currently presented here. In part because as far as I can tell cgmanager is dead, in part because my solution doesn't feel like a hacky workaround, but mostly because this discussion still shows up when searching for a solution to the problem. It's pretty simple actually: use systemd user mode.

Granted if you don't use systemd this solution isn't going to help. In that case I'd advice you to figure out if your init system has some way of allowing unpriviliged users to run services at boot and use that as a starting point.

Using systemd user mode to autostart unprivileged lxc containers

I'm assuming you have unprivileged lxc containers working properly and that running lxc-autostart as the container's user works. If so, do the following:

  1. Create the file ~/.config/systemd/user/lxc-autostart.service in the home of whatever user has the lxc containers:
[Unit]
Description="Lxc-autostart for lxc user"

[Service]
Type=oneshot
ExecStart=/usr/bin/lxc-autostart
ExecStop=/usr/bin/lxc-autostart -s
RemainAfterExit=1

[Install]
WantedBy=default.target
  1. Then as that user run:
systemctl --user enable lxc-autostart

(Note, the --user option tells systemctl you're using it in user mode. All of the things I normally do with systemctl, start, stop, statuc, enable, etc, work with --user.)

  1. Then run the following, where $user is the name of the user that has the lxc containers:
sudo loginctl enable-linger $user

This is necessary for systemd to start a systemd user instance for $user at boot. Otherwise it would only start one at the moment $user logs in.

For more information I'd recommend the archlinux wiki systemd/timer page and the systemd man pages.

Accessing a user's systemd instance as root

You can actually start/stop/whatever a user's systemd service as root, however this requires you to set the XDG_RUNTIME_DIR environment variable. Assume $user is the user whose instance you want to access and $uid it's uid, then this is how you'd start the lxc-autostart.service defined above:

sudo -u $user XDG_RUNTIME_DIR=/run/user/$uid systemctl --user start lxc-autostart

You can even use systemd-run to run arbitrary commands as that user in a way that doesn't break lxc. I'm using the following commands to stop/start my containers before/after backup, where $name is the name of the lxc container that's being backed up:

sudo -u $user XDG_RUNTIME_DIR=/run/user/$uid systemd-run --user --wait lxc-stop -n $name
sudo -u $user XDG_RUNTIME_DIR=/run/user/$uid systemd-run --user --scope lxc-start -n $name

(Note that without --wait systemd-run doesn't block until the container is stopped.)


Solution 3:

In case anyone stumbles on to this q&a for the answer to autostarting unprivileged LXC containers (I certainly check back here a lot), here is a solution that works well and which I followed to get it working on my server:

http://blog.lifebloodnetworks.com/?p=2118 by Nicholas J Ingrassellino.

In a nutshell, it involves creating two scripts, and they work together at startup to allow LXC to start the unprivileged containers of each listed user without having to actually log in to the user account; in other words, executing the command as the user with all the CGroups magic intact. In keeping with SO best practice, I'll quote the bones of it here but it's worth reading his original article.

Allow our user account to use the bridge…

echo "$USER veth lxcbr0 1024" | sudo tee -a /etc/lxc/lxc-usernet

Create Upstart script… In /etc/init/lxc-unprivileged.conf add…

description "LXC Unprivileged Containers"
author "Mike Bernson <[email protected]>"

start on started lxc

script
    USERS="[user]"

    for u in $USERS; do
        cgm create all lxc$u
        cgm chown all lxc$u $(id -u $u) $(id -g $u)
        lxc-autostart -L -P /home/$u/.local/share/lxc | while read line;
        do
            set -- $line
            /usr/local/bin/startunprivlxc lxc$u $u $1
            sleep $2
        done
    done
end script

Make sure to replace [user] with your user account.

Create the container start script… In /usr/local/bin/startunprivlxc add…

#!/bin/sh

cgm movepid all $1 $$
sudo -iH -u $2 -- lxc-start -n $3 -d

…and make it executable…

sudo chmod +x /usr/local/bin/startunprivlxc

I'd just like to emphasise that it does appear to work safely, correctly, and doesn't require the root to SSH into the other user accounts.

There is also more on the subject (touching on related gotchas) here: https://gist.github.com/julianlam/4e2bd91d8dedee21ca6f which can be useful in understanding why this is the way it is.


Solution 4:

I've written a small script to work around the issue, just follow the commented instructions.