Systemd-nspawn: Difference between revisions
(Created page with "[https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html systemd-nspawn] is a simpler alternative to LXC which works well on modern versions of Debian (and, u...") |
m (→Quickstart) |
||
(4 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
[https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html systemd-nspawn] is a simpler alternative to [ |
[https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html systemd-nspawn] is a simpler alternative to [https://wiki.csclub.uwaterloo.ca/Virtualization_(LXC_Containers) LXC] which works well on modern versions of Debian (and, unlike LXC, it does not break very critical systemd services running in containers). For "pet" containers, we should be using systemd-nspawn; for "cattle" containers, [[Podman]] is more appropriate. |
||
Some light reading: |
Some light reading: |
||
Line 73: | Line 73: | ||
<pre> |
<pre> |
||
machinectl shell machine1 |
machinectl shell machine1 |
||
</pre> |
|||
<b>Note</b>: if you see the error <code>sh: 2: exec: : Permission denied</code>, append /bin/bash to the end of the command: |
|||
<pre> |
|||
machinectl shell machine1 /bin/bash |
|||
</pre> |
</pre> |
||
Line 79: | Line 84: | ||
systemctl enable systemd-nspawn@machine1 |
systemctl enable systemd-nspawn@machine1 |
||
</pre> |
</pre> |
||
== Multiple network interfaces == |
|||
Unfortunately systemd does not have a built-in way to create [https://github.com/systemd/systemd/issues/11087 multiple bridged network interfaces]. Thankfully, it's not too difficult to accomplish this using the <code>VirtualEthernetExtra</code> option and a systemd drop-in; the idea is to create some extra veth pairs and then manually attach them to the bridge. |
|||
Let's say you have three bridges on the host: br0, br1 and br2, and you want the container to be attached to all three. Make your nspawn file look like this: |
|||
<pre> |
|||
... |
|||
[Network] |
|||
Bridge=br0 |
|||
# These will be manually bridged to the host |
|||
VirtualEthernetExtra=ve-machine1-1:veth1 |
|||
VirtualEthernetExtra=ve-machine1-2:veth2 |
|||
</pre> |
|||
Now run <code>systemctl edit systemd-nspawn@machine1</code> and paste the following: |
|||
<pre> |
|||
[Service] |
|||
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 master br1 |
|||
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 up |
|||
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 master br2 |
|||
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 up |
|||
</pre> |
|||
In the container, there will be three interfaces: |
|||
* host0, which is attached to br0 on the host |
|||
* veth1, which is attached to br1 on the host |
|||
* veth2, which is attached to br2 on the host |
|||
Make sure you update /etc/network/interfaces in the container accordingly. |
Latest revision as of 16:48, 28 April 2022
systemd-nspawn is a simpler alternative to LXC which works well on modern versions of Debian (and, unlike LXC, it does not break very critical systemd services running in containers). For "pet" containers, we should be using systemd-nspawn; for "cattle" containers, Podman is more appropriate.
Some light reading:
Quickstart
In the example below, we will create a container called 'machine1'.
Create a directory for the rootfs:
mkdir /var/lib/machines/machine1
Or, if you are using an LVM volume, just create a symlink in /var/lib/machines to where the LV is mounted:
ln -s /vm/machine1 /var/lib/machines/machine1
Now bootstrap the rootfs:
debootstrap --variant=minbase --include=systemd,systemd-sysv,systemd-container,iproute2,inetutils-ping,ifupdown,procps,less,nano bullseye /var/lib/machines/machine1 http://mirror.csclub.uwaterloo.ca/debian
Note that the systemd-container
package must be installed in the guest.
Now do a bit of setup in the rootfs:
chroot /var/lib/machines/machine1 # Only do this if you want to use `machinectl login` passwd -d root cat <<EOF >>/etc/securetty pts/0 pts/1 pts/2 pts/3 EOF # set hostname echo machine1 > /etc/hostname # set FQDN nano /etc/hosts # set up network config nano /etc/network/interfaces exit
Now paste the following into /etc/systemd/nspawn/machine1.nspawn:
[Exec] Boot=yes Hostname=machine1 PrivateUsers=no [Network] Bridge=br0
Replace 'br0' by the bridge interface on the host to which the container should be attached (a veth pair will be created when the container starts up).
Also make sure to set 'PrivateUsers=no', because by default systemd-nspawn uses some randomized UID/GID mapping which makes it difficult to migrate the container to a different system.
Now start the container:
systemctl start systemd-nspawn@machine1
Or alternatively, using machinectl
:
machinectl start machine1
To login to a container via an emulated serial console (I don't recommend doing this, since the TTY gets screwed up):
machinectl login machine1
Attach to a running container (similar to lxc-attach
):
machinectl shell machine1
Note: if you see the error sh: 2: exec: : Permission denied
, append /bin/bash to the end of the command:
machinectl shell machine1 /bin/bash
Important: make sure the container starts up at boot:
systemctl enable systemd-nspawn@machine1
Multiple network interfaces
Unfortunately systemd does not have a built-in way to create multiple bridged network interfaces. Thankfully, it's not too difficult to accomplish this using the VirtualEthernetExtra
option and a systemd drop-in; the idea is to create some extra veth pairs and then manually attach them to the bridge.
Let's say you have three bridges on the host: br0, br1 and br2, and you want the container to be attached to all three. Make your nspawn file look like this:
... [Network] Bridge=br0 # These will be manually bridged to the host VirtualEthernetExtra=ve-machine1-1:veth1 VirtualEthernetExtra=ve-machine1-2:veth2
Now run systemctl edit systemd-nspawn@machine1
and paste the following:
[Service] ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 master br1 ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 up ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 master br2 ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 up
In the container, there will be three interfaces:
- host0, which is attached to br0 on the host
- veth1, which is attached to br1 on the host
- veth2, which is attached to br2 on the host
Make sure you update /etc/network/interfaces in the container accordingly.