Skip to main content

Build in a systemd-nspawn container

· 3 min read
Louis
Embeded Linux and Yocto developer

For general information about systemd-nspawn, see:

The container is a directory under /var/lib/machines that systemd boots. One file controls it: the nspawn config (/etc/systemd/nspawn/<name>.nspawn).

Why build in a systemd-nspawn container?​

This guide is for cross-building (e.g. Yocto) against an old distribution without touching the host. systemd-nspawn gives you:

  • an old distribution, in a chroot that systemd manages for you
  • fine control over resources such as CPUs and memory
  • easy access to the journal from the host
  • nothing more than systemd to install

Creation​

Install debootstrap, and one or both of debian-archive-keyring and ubuntu-keyring, depending on which distribution you want.

# cd /var/lib/machines
# debootstrap --include=dbus,libpam-systemd,libnss-systemd,systemd-resolved --components=main,universe <codename> <container-name>

For Debian, use the rolling names ("stable", "testing") or release names ("stretch", "sid"); for Ubuntu, use the code name ("xenial", "zesty"). Code names are listed in /usr/share/debootstrap/scripts, and a table of code names to version numbers is on the Debian releases page.

In my case, I use Debian stable and call the container builder:

# debootstrap --include=dbus,libpam-systemd,libnss-systemd,systemd-resolved stable builder

The container now exists in /var/lib/machines/builder.

Users​

Before using the container, set a password for root and create a normal user.

Create the user with the same uid/gid as the host account (use $ id -u ). Mine is 1337:

# cd /var/lib/machines
# systemd-nspawn -D ./builder
# passwd
# useradd -m build -u 1337 -U -s /bin/bash
# passwd build
# logout

Configure the mount point​

Edit /etc/systemd/nspawn/builder.nspawn (the file name must match the container name in /var/lib/machines/).

[Files]
# mount a host directory, mapping uid/gid so the mount is owned by the
# container's user instead of nobody
Bind=/home/louson/projects/yocto:/home/builder/yocto:idmap

Without the idmap option, the mount point is owned by the user nobody.

Network​

If the host runs systemd-networkd and systemd-resolved, the network is automatic. Enable and start them:

# systemctl enable --now systemd-networkd.service
# systemctl enable --now systemd-resolved.service

Otherwise, either configure the NAT or disable virtual networking:

[Network]
# no virtual ethernet: the container shares the host network
VirtualEthernet=no

Now start and login to the container:

# machinectl start builder
# machinectl login builder

Check the network is up, and update the system.

Further configuration​

Start the container at boot​

You can start the container at boot:

# machinectl enable builder

Control the resources​

A build can easily take your PC down, so limit its usage:

# systemctl set-property systemd-nspawn@builder.service MemoryMax=4G
# systemctl set-property systemd-nspawn@builder.service CPUQuota=400%

Those limitations may also be given in the nspawn configuration file.