User:Cmsigler/Nspawn Configuration Guide

From ArchWiki

My Personal Step-by-step Guide to systemd-nspawn Container Setup, Configuration and Operation

CMS, 2022/03/21

Note: This guide is a work-in-progress. Please use appropriately.
Note: These procedures have been developed and deployed on an Arch Linux installation. Other distributions and environments will require modifications to the steps below. YMMV

Create and set up Arch Linux container

$ sudo pacman -S --needed arch-install-scripts
$ mkdir ~/containers
$ cd ~/containers
$ sudo mkdir ./container_name
$ sudo pacstrap -c ./container_name base [addl. pkgs./groups]
$ sudo systemd-nspawn -D ./container_name
# passwd
# useradd -m -G wheel regularuser
# passwd regularuser
# logout

Configure host for container operation

Configure host networking to support container

$ sudo cp -ip /usr/lib/systemd/network/80-container-vz.network /etc/systemd/network
$ sudo vi /etc/systemd/network/80-container-vz.network
/etc/systemd/network/80-container-vz.network
[Match]
Name=vz-*
Driver=bridge

[Network]
# Default to using a /24 prefix, giving up to 253 addresses per virtual network.
Address=10.10.0.1/24
Address=fd89:abc1:def2:10::1/64
IPMasquerade=both
IPv6PrivacyExtensions=yes
LinkLocalAddressing=yes
LLDP=yes
EmitLLDP=customer-bridge
DHCPServer=no
IPv6SendRA=yes
Note: Configuration of IP masquerading, along with sysctl IP forwarding kernel parameters, is configured by use of IPMasquerade=both in the [Network] section of 80-container-vz.network

Add nftables rule to forward chain to allow forwarding

host_ruleset.nft
table inet inet-local-table {
...
  chain inet-local-forward {
    type filter hook forward priority filter
    policy drop
...
# Accept IP forward for upstream established and related tracked connections
    iif $upstream-if ct state {established, related} accept
# Accept all systemd-nspawn container traffic to be forwarded upstream
    iifname vz-* oif $upstream-if accept
...
  }
}
$ sudo nft flush ruleset
$ sudo nft -f host_ruleset.nft

Configure container for operation

Configure container networking

In container, edit /etc/systemd/network/80-container-host0.network:

/etc/systemd/network/80-container-host0.network
[Match]
Virtualization=container
Name=host0

[Network]
DHCP=no
Address=10.10.0.2/24
Gateway=10.10.0.1
Address=fd89:abc1:def2:10::2/64
Gateway=fd89:abc1:def2:10::1
IPv6PrivacyExtensions=yes
LinkLocalAddressing=yes
LLDP=yes
EmitLLDP=customer-bridge

[DHCP]
UseTimezone=yes

Boot into and set up container

$ sudo systemd-nspawn -b -D ./container_name --network-zone=nspawn0

Log into container as root.

# systemctl enable systemd-networkd
# systemctl start systemd-networkd
# systemctl enable systemd-resolved
# systemctl start systemd-resolved
# systemctl enable sshd
# systemctl start sshd
# reboot
...
[Continue setting up, install additional packages, configure, and/or run your container]
...
# poweroff

Container operation

Set up container to run as a machine

Move container to /var/lib/machines, then create a .nspawn file for operation via machinectl, etc.:

$ sudo mv ./container_name /var/lib/machines
$ sudo vi /etc/systemd/nspawn/container_name.nspawn
/etc/systemd/nspawn/container_name.nspawn
[Exec]
Boot=on
;PrivateUsers=no

[Network]
Zone=nspawn0

Enable and start container

$ sudo machinectl enable container_name
$ sudo machinectl start container_name
$ sudo machinectl login container_name

Use container as base

Using a configured minimal container as the base image for a tailored, single-app container:

  • Configure .nspawn file:
$ sudo vi /etc/systemd/nspawn/single-app_container_name.nspawn
/etc/systemd/nspawn/single-app_container_name.nspawn
[Exec]
Boot=on
;PrivateUsers=no

[Network]
Zone=nspawn0
  • First time only -- Create directories:
$ sudo mkdir /var/lib/machines/single-app_container_name
Note: /var/lib/machines_overlay is non-standard and unmanaged by the system.
$ sudo mkdir /var/lib/machines_overlay
$ sudo chmod 700 /var/lib/machines_overlay
$ sudo mkdir /var/lib/machines_overlay/single-app_container_root
$ sudo mkdir /var/lib/machines_overlay/single-app_container_tmp
  • Each time before starting overlay container, perform overlay mount:
$ sudo mount -t overlay overlay -o lowerdir=/var/lib/machines/base_container_name,upperdir=/var/lib/machines_overlay/single-app_container_root,workdir=/var/lib/machines_overlay/single-app_container_tmp /var/lib/machines/single-app_container_name
  • Start and login to overlay container:
$ sudo machinectl start single-app_container_name
$ sudo machinectl login single-app_container_name
  • Log into single-app container, then use pacman to install desired packages; configure container for operation.
  • When finished, stop overlay container and unmount overlay:
$ sudo machinectl stop single-app_container_name
$ sudo umount /var/lib/machines/single-app_container_name