Developing using a systemd-nspawn container (Linux host only)

/docs/gears/developer/setup/alternate/systemd-nspawn/

Prerequisites

This should work on all 64-bit x86_64 Linux systems that run systemd – that’s most of them at this point – and most (all?) 64-bit ARM Linux systems that run systemd. We have tested this setup on Arch Linux on x86_64 and aarch64 and with Ubuntu on x86_64.

If you use ARM, replace all occurrences of x86_64 in URLs and filenames in this document with aarch64.

Here are the steps:

Make sure systemd-nspawn is installed

Some Linux distros keep this systemd executable in a separate package that you need to first install. For example, on Ubuntu, install it with:

% sudo apt install systemd-container

Optional: btrfs filesystem

systemd-nspawn has built-in extra features when you use the btrfs filesystem. This can make container management much faster and take up less disk space. If you can, we recommend a btrfs partition; if not, that’s fine, too, it will work just fine on other filesystems as well.

Make sure your host allows Linux containers to access the internet

How to do this highly dependent on your networking setup. Here is a setup that works for us on Arch Linux, using systemd-networkd for network management. There are two steps:

  1. Run both IPv4 and IPv6 based iptables on your host, otherwise the UBOS container cannot set up its own firewall and UBOS containers will boot into a degraded state. (That’s not fatal, it just looks ugly and you might not see other problems as easily.) If you aren’t already doing this, on the host:

    % [[ -e /etc/iptables/iptables.rules ]] || sudo cp /etc/iptables/empty.rules /etc/iptables/iptables.rules
    % [[ -e /etc/iptables/ip6tables.rules ]] || sudo cp /etc/iptables/empty.rules /etc/iptables/ip6tables.rules
    % sudo systemctl enable --now iptables ip6tables
    

    This will not actually perform any firewall functionality (the ruleset is empty, unless you set some yourself), but it will allow the UBOS container to set up its own firewall.

  2. Make sure your host network interface forwards traffic from the the containers. Add IPForwarding=1 to the relevant .network file so IP packets will be forwarded from the container to the public internet (e.g. for package downloads). For example, /etc/systemd/network/wired.network should read as follows:

    [Match]
    Name=en*
    
    [Network]
    DHCP=ipv4
    IPForwarding=1
    

    After you make a change to a .network file:

    % sudo systemctl daemon-reload
    % sudo systemctl restart systemd-networkd systemd-resolved
    

Pick a project directory

We recommend you do all your UBOS-related development below a certain directory. Let’s say that directory is ~/ubosdev-nspawn. Create that directory and enter it:

% mkdir ~/ubosdev-nspawn
% cd ~/ubosdev-nspawn

Then create a sub-directory for your project files:

% mkdir projects

Pick a release channel to work on

By default, this setup uses the yellow Release Channel. This is the recommended Release Channel for most application development.

Note

If you want to develop on a Release Channel other than yellow, replace the string yellow with the name of the alternate Release Channel in all commands below.

Download a container image

Download a container image. Go to http://depot.ubosfiles.net/yellow/x86_64/images/index.html and look for the file ubos-develop_yellow_x86_64-container_LATEST.tar.xz.

If you chose a ${CHANNEL} other than yellow, replace the yellow in the above URL, and then the yellow in the filename with the name of the ${CHANNEL} you chose. Also remember to replace x86_64 with aarch64 if you are on ARM.

We will call the name of the downloaded image file ${IMAGE}. Download it into your working directory.

Unpack the container image

If your filesystem is btrfs, create a subvolume that becomes the filesystem for your container:

% sudo btrfs subvol create ubos-develop-yellow

For all other filesystems, simply create a directory that becomes the filesystem for your container:

% mkdir ubos-develop-yellow

Then unpack:

% ( cd ubos-develop-yellow; sudo tar xfJ ../ubos-develop_yellow_x86_64-container_LATEST.tar.xz )

Start the container

In the project directory, run:

% sudo systemd-nspawn -b -n -M ubos-develop-yellow -D ubos-develop-yellow \
   --bind $(pwd)/projects:/home/ubosdev/projects --bind $HOME/.m2:/home/ubosdev/.m2 --bind /dev/fuse \
   --network-zone ubos-yellow

Note

This is a mouthful. You can create yourself a shortcut of you like:

% echo sudo systemd-nspawn -b -n -M ubos-develop-yellow -D ubos-develop-yellow \
   --bind $(pwd)/projects:/home/ubosdev/projects --bind $HOME/.m2:/home/ubosdev/.m2 --bind /dev/fuse \
   --network-zone ubos-yellow \
   > start-container-yellow
% chmod 755 start-container-yellow

and run it as:

% ./start-container-yellow

If your filesystem is btrfs, you can also add flag -x to this invocation. When you do, systemd-nspawn will make all changes in a temporary filesystem instead, and when you quit your container, your unpacked “directory” will still be unchanged.

Open a shell in the container

The shell in which you ran the systemd-nspawn command now shows a login prompt. You can login there as root (with this password, but if you do, we recommend you only use this shell to follow the system log, e.g. with journalctl -f).

To do your development, open up a separate shell and execute:

% sudo machinectl shell ubosdev@ubos-develop-yellow

This essentially does the same thing as if you were to log into your container as user ubosdev from the console or via ssh, but you don’t need to have any credentials set up.

You will execute your build commands in this shell. You can open up as many shells in the container as you like.

Note that your projects directory on the host that you created earlier, is mounted into your container right where you are. You can see the same files there on the host and in the container:

% ls -al projects

That makes sharing files between the host (where you can edit them with the editor of your choice) and the container (where you build and run your code) quite easy.

Shut down the container

When you are done developing, shut down the container with:

^]^]^]

(three control-]’s, in a rapid sequence) in the shell that you ran systemd-nspawn in.