apt install systemd-container安装完成后systemd-nspawn和machinectl就可以用了。但是在开始用之前,先修改一些基本配置,方便后续使用。
首先是关于网络这块的配置,默认情况下systemd-nspawn有一个开箱即用的网络:虚拟以太网链接(network-veth)。但是要用这个网络的话,前提是需要将系统的网络管理工具修改为使用systemd-networkd,下面介绍下如何修改。
debian系统默认的网络管理工具是ifupdown,我们先禁用ifupdown的开机自启:
systemctl disable networking然后设置systemd-networkd的开机自启:
systemctl enable systemd-networkd接下来看一下ifupdown的配置:
cat /etc/network/interfaces我这台机器内的配置如下,可以看到基本就是用dhcp来获取ip的:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
auto eth1
iface eth1 inet dhcp
auto eth2
iface eth2 inet6 autoeth0是公网ip,eth1是内网ip,eth2是公网ipv6:

知道目前机器的网络配置后,把这份配置文件重命名保存一下以便在配置systemd-networkd后不会使用它:
mv /etc/network/interfaces /etc/network/interfaces.save接下来配置systemd-networkd,新建eth0.network文件:
nano /etc/systemd/network/eth0.network写入如下配置:
[Match]
Name=eth0
[Network]
DHCP=yes新建eth1.network文件
nano /etc/systemd/network/eth1.network写入如下配置:
[Match]
Name=eth1
[Network]
DHCP=yes新建eth2.network文件:
nano /etc/systemd/network/eth2.network写入如下配置:
[Match]
Name=eth2
[Network]
DHCP=yes做完这些配置之后,重启机器使修改生效:
reboot重新登录到机器内后,现在的虚拟以太网链接(network-veth)就是可用的了,但是我不打算用这个网络,因为用这个网络创建的容器获取到的ip是不固定的,也就是说容器重启后又会获取另外一个与之前不同的ip,这样使用的话太不方便。为了解决这个问题,我们可以自己创建一个网桥,然后让容器都用网桥来联网。
新建br0.netdev文件:
nano /etc/systemd/network/br0.netdev写入如下配置:
[NetDev]
Name=br0
Kind=bridge新建br0.network文件:
nano /etc/systemd/network/br0.network写入如下配置:
[Match]
Name=br0
[Network]
Address=10.50.0.1/24
DHCPServer=yes
IPMasquerade=yes
LLDP=yes
[DHCPServer]
EmitDNS=yes
DNS=8.8.8.8这里着重解释一下br0.network的配置,由于我们的服务器上没有多个公网ip,所以ip地址就用保留地址,然后用IPMasquerade启用nat转发。另外systemd-networkd是有dhcp服务器功能的,使用DHCPServer参数来启动dhcp服务器,为容器自动分配ip地址。做完这些配置之后重启systemd-networkd使其生效:
systemctl restart systemd-networkd网桥创建完成后,现在还需要让systemd-nspawn使用我们刚创建的网桥,编辑systemd-nspawn@服务的配置文件:
systemctl edit systemd-nspawn@覆盖systemd-nspawn@服务默认的启动配置,去掉–network-veth,添加–network-bridge=br0:
[Service]
ExecStart=
ExecStart=systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-bridge=br0 -U --settings=override --machine=%i现在来制作操作系统镜像。这里我用mkosi制作一个debian11的镜像来演示。
不要使用debian官方存储库内的mkosi,因为版本太旧有很多问题,这里安装最新版。先安装mkosi需要用到的依赖:
apt -y install arch-install-scripts btrfs-progs debootstrap dosfstools ovmf e2fsprogs squashfs-tools gnupg python3 tar cryptsetup-bin xfsprogs xz-utils zypper sbsigntool debian-archive-keyring python3-pip git接下来安装mkosi:
python3 -m pip install git+https://github.com/systemd/mkosi.git@v13准备工作目录:
mkdir debian
mkdir debian/mkosi.cache
mkdir debian/mkosi.extra进入工作目录,新建mkosi.default配置文件:
cd debian
nano mkosi.default写入如下配置,修改Password后面的值来设置root密码:
[Distribution]
Distribution=debian
Release=bullseye
[Output]
Format=directory
Output=/var/lib/machines/debian
Bootable=no
Hostname=imlala
[Content]
BasePackages=yes
Packages=locales,tzdata,procps,dialog,iproute2,iputils-ping,lsof,net-tools,nano,curl,git
Password=rootpassword新建mkosi.prepare脚本文件:
nano mkosi.prepare对镜像做一些基本的配置修改,并设置镜像内的systemd-networkd为开机自启:
#!/bin/sh
systemctl enable systemd-networkd
sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen
dpkg-reconfigure --frontend=noninteractive locales
update-locale LANG=en_US.UTF-8
rm -rf /etc/apt/sources.list.d/bullseye-security.list
rm -rf /etc/apt/sources.list.d/bullseye-updates.list给脚本执行权限:
chmod +x mkosi.prepare进入到之前创建好的mkosi.extra目录,这个目录的作用是向镜像内添加文件或者替换文件:
cd mkosi.extra这里替换掉镜像内的存储库配置,创建相应的目录:
mkdir -p etc/apt新建sources.list:
nano etc/apt/sources.list写入如下配置:
deb http://deb.debian.org/debian bullseye main contrib non-free
deb-src http://deb.debian.org/debian bullseye main contrib non-free
deb http://deb.debian.org/debian-security/ bullseye-security main contrib non-free
deb-src http://deb.debian.org/debian-security/ bullseye-security main contrib non-free
deb http://deb.debian.org/debian bullseye-updates main contrib non-free
deb-src http://deb.debian.org/debian bullseye-updates main contrib non-free这是mkosi.extre目录的正确结构:
root@debian-1cpu-1gb-sg-sin1:~/debian/mkosi.extra# tree
.
└── etc
└── apt
└── sources.list回到上级目录执行mkosi命令即可开始构建镜像:
cd ../
mkosi构建完成后即可使用machinectl启动:
machinectl start debian登录到系统内,要登出的话就按键盘组合键ctrl+]]]:
machinectl login debian设置容器开机自启,或者禁用开机自启:
machinectl enable debian
machinectl disable debian重启、关机、杀掉容器:
machinectl reboot debian
machinectl poweroff debian
machinectl kill debian列出全部正在运行的容器,查看某一个容器的状态:
machinectl list
machinectl status下面介绍个比较实用的功能:端口映射(Port mapping)
使用端口映射可以把宿主机的端口映射到容器内的端口,比如容器内装了一个nginx使用了80端口,宿主机有一个8080端口空闲,我们就可以把宿主机的8080端口映射到容器内的80端口,这样通过外部网络就能访问到容器内的nginx服务了。
在之前我们已经通过machinectl启动了一个名为debian的容器,实际上machinectl也是调用的systemd-nspawn@服务,所以要配置某一个容器的端口映射,只需要编辑相应的systemd服务:
systemctl edit systemd-nspawn@debian覆盖配置,添加–port参数,有多个端口就添加多个–port参数:
[Service]
ExecStart=
ExecStart=systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-bridge=br0 --port=tcp:8080:80 -U --settings=override --machine=%i要使配置生效,必须先关闭容器再启动,直接reboot是不行的:
machinectl poweroff debian
machinectl start debian