Containers have some efficiency advantages but the way they are typically set up can use a lot of space on disk and eat up a lot of ram with duplicate services. Standard Debian or CentOS containers easily require 200-600MB of space each.

Docker and other popular container management systems are oriented towards more enterprise scale operations where containers are frequently set up and torn down with automated cloud orchestration tools.

If we want to have a more PMC take on containers, what we need probably looks more like a few tiny linux matryoshka dolls. Alpine Linux is based on musl (instead of libc), Busybox (instead of GNU-derived toolchain) and OpenRC (instead of systemD) and gives us a bare-bones but very utilitarian base container image in just 16MB. We can, with a little bit of manual effort get this to run in a systemd-nspawn container.

Build a new alpine container

While it's possible to use the standard alpine tools to build a system image, somebody has made a little script that deals with a few small annoyances for us. The script is installed in /usr/sbin so you can just:

sudo alpine-nspawn-install -d /var/lib/machines/my_pmc_container -p alpine_pkg1 -p some_other_package

TIP: systemd-nspawn images are basically just a normal filesystem tree under /var/lib/machines/my_pmc_container. So, in theory, you can do a lot of interaction with the conainer by just having a directory that is writeable from the containing host.

Run the container manually and set a root password

For the first spin-up, we should run this manually to set private users/groups and some basic stuff.

sudo systemd-nspawn -D /var/lib/machines/my_pmc_container -M my_pmc_container --private-users=pick --private-users-ownership=chown

Now you're basically chrooted inside the container (but not really properly booted) so set up a few things:

hostname > /etc/hostname
passwd

You can also create a user or edit any config files that you need for services that will run in the container. When you're done just exit out.

NOTE: if you need to run the container manually again in the future, to set up networking or tweak some settings, use this command since we already have the private users set up and don't need to chown a second time:

sudo systemd-nspawn -D /var/lib/machines/my_pmc_container -M my_pmc_container --private-users=yes

Set up networking

This is the one thing that is slightly fiddly with alpine since it does not magically tie up with systemd on the containing host. We are using a private bridge running on the containing host to route our traffic to the internet. These IP addresses are assigned manually so we should be careful to keep track and not double up by accident. We will use the /etc/hosts file on the containing host as our authoritative record as well as provide us with convenient aliases to proxy or connect via SSH.

Edit /etc/hosts on eik and add a new entry for the container below the last entry with 192.168.0.X:

127.0.0.1   localhost
193.170.194.218eik
192.168.0.10 snac
192.168.0.11 borf
192.168.0.12 my_pmc_container

Now create an nspawn config file on eik in /etc/systemd/nspawn/my_pmc_container.nspawn

[Exec]
PrivateUsers=yes
KillSignal=SIGTERM
[Network]
Bridge=bridge0

Now, go inside the container and edit the /etc/network/interfaces file inside the container:

auto host0
iface host0 inet static
    address 192.168.0.12/24 
    gateway 192.168.0.1      

Start and Enable the container

On eik: sudo machinectl start my_pmc_container

To enable so that the container always comes up when eik boots: sudo machinectl enable my_pmc_container

Connect via ssh

Note, you may need to tweak the ssh configs on the container to allow root logins or use whatever keys setup you prefer.

ssh my_user@my_pmc_container

Optionally - set up an nginx proxy for public service

prolly best to use proxy_pass my_pmc_container

References:

  1. Much of this document was based on this blog post
  2. The arch wiki (as ever) has some very good general docs about systemd-nspawn