Running containers with SystemD-nspawn

Linux's own built-in container, acts as a chroot on steroids

Install dependencies

SystemD is already an important part of most Linux systems today.

# apt update
# apt install systemd-container bridge-utils debootstrap

Create the container

Debootstrap is a script that creates a Debian base system with only the most important files to get the OS running.

# debootstrap --include=systemd-container stable /var/lib/machines/debianTest

Set hostname inside container

# echo "debianTest" > /var/lib/machines/debianTest/etc/hostname

Enable IP forwarding on host

# vim /etc/sysctl.conf
net.ipv4.ip_forward=1

Boot the container

# machinectl start debianTest

Run a shell inside the container

Just type exit, logout or CTRL+D when you are done

# machinectl shell debianTest
# exit

Start & enable networkD on the host.

# systemctl start systemd-networkd
# systemctl enable systemd-networkd

And inside the container…

# machinectl shell debianTest /usr/bin/systemctl start systemd-networkd
# machinectl shell debianTest /usr/bin/systemctl enable systemd-networkd

Check status of container with one of the following commands

# machinectl
# machinectl status debianTest
# machinectl show debianTest

Networking VETH (Virtual Ethernet)

By default the containers run on veth interfaces, The network configuration for the nspawn containers can be found in the file /usr/lib/systemd/network/80-container-ve.network.


Forward a port on the host to the container

# mkdir /etc/systemd/nspawn
# vim /etc/systemd/nspawn/debianTest.nspawn

Don’t forget to install ssh in the container if you want this example to work.

[Network]
Port=tcp:222:22

Bridge Networking (buggy!)

For some reason i cant get bridge networking to work so stick with the default NAT solution!

Turn off traditional networking and start using the networkD.

# mv /etc/network/interfaces /etc/network/interfaces.save
# vim/etc/systemd/network/lan0.network
[Match]
Name=br0

[Network]
DHCP=ipv4

Create a bridge device

# vim/etc/systemd/network/br0.netdev
[NetDev]
Name=br0
Kind=bridge
# vim/etc/systemd/network/br0.network
[Match]
Name=enp0s3

[Network]
Bridge=br0

copy the ExecStart line from active configuration

# systemctl cat systemd-nspawn@.service | grep ExecStart

Then append –network-bridge=br0 to the end of the line, it’s important to include the extra ExecStart= line.

# systemctl edit systemd-nspawn@.service
[Service]
ExecStart=
ExecStart=/usr/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth -U --settings=override --machine=%i --network-bridge=br0

Reload the network (or reboot your host to make sure)

# systemctl restart systemd-networkd