nspawn容器的使用
systemd-container是systemd的容器组件。它和LXC对标,比chroot更强大。它虚拟化了文件系统、进程树以及客户系统中的进程间通信。
systemd-container容器有五个限制:
- 仅允许以只读方式访问例如
/sys
,/proc/sys
,/sys/fs/selinux
这样的内核文件系统。 - 禁止修改主机的网络接口以及系统时钟。
- 禁止创建设备节点。
- 禁止重启主机操作系统。
- 禁止加载内核模块。
它的吸引力在于由systemd-nspawn运行的容器将会与systemd组件一同运行在宿主系统上。举例来说,一个容器的日志可以输出到宿主系统的日志中。它的核心控制命令为systemd-nspawn
。
快速开始
在进入容器之前我们都需要一个最基本的根文件系统,对于systemd-nspawn来说,这个文件系统可以是一个raw格式的镜像文件,也可以是一个目录,下面主要以一个目录作为容器的根节点来说明systemd-nspawn的使用方法。
systemd-nspawn可以像chroot一样以一个目录作为根来启动一个容器,并且不需要手动挂载/proc、/run、/dev等目录,退出容器也会自动清理资源,不容易把主机系统弄崩溃。
chroot进入容器目录:systemd-nspawn -D /path-to-rootfs
systemd-nspawn不仅能像chroot一样以一个目录作为一个新系统的根,并且还能以一个完整的系统启动流程来启动一个容器,就像LXC一样。
启动一个完整的系统:systemd-nspawn -bD /path-to-rootfs
以Ubuntu-base为例,在 http://cdimage.ubuntu.com/ubuntu-base/releases/ 下载Ubuntu base版tar包,解包并配置一些初始化文件(例如hosts,hostname,resolv.conf)后,使用systemd-nspawn -D /path-to-ubuntu
命令进入容器,此时可以使用apt
,useradd
等命令,关键是查看当前挂载分区并写入/etc/fstab
中,否则稍后会影响启动。
exit
退出容器后,使用systemd-nspawn -bD /path-to-ubuntu
启动进入容器系统,此时可以和真实系统一样进行操作。除了正常退出容器,还可以使用ctrl
+三下]
操作强制退出。
安装
1 | # Debian |
创建容器
systemd-nspawn可以直接启动容器,就像chroot
一样,而不对容器进行统一化管理。
如果用户希望对容器进行统一的服务化管理,则需要使用machinectl
辅助进行管理,将容器镜像导入machinectl
,它会调用systemd-nspawn启动容器并对容器进行监管。
需要注意的是,对于systemd-nspawn来说,一个镜像(根文件系统)就对应一个可引导的容器,它们之间不是分开管理的。
自行生成镜像
用户可以使用任意的可引导镜像启动一个nspawn容器,举例来说,用户可以使用debootstrap
工具,执行debootstrap --include=systemd stable /var/lib/machines/debian
创建一个基本Debian根文件系统。
然后,用户只需要执行machinectl import-fs 目录 [容器名]
命令将容器的根文件系统目录导入为可用镜像即可。
手动下载镜像
和LXC一样,systemd-nspawn有自己官方的镜像发布站点,用户可以在 Images (nspawn.org) 或 Index of /storage (nspawn.org) 寻找镜像。
在下载镜像Tar包后,用户可以执行machinectl import-tar|import-raw 文件名 容器名 [--read-only]
进行导入。
当然,用户也可以将镜像解包,然后通过machinectl import-fs 目录 [容器名]
命令进行导入。
直接拉取镜像
在拉取镜像之前,需要先创建密钥,具体方法为先创建本地密钥:
1 | sudo gpg --no-default-keyring \ |
然后拉取远程密钥:
1 | sudo gpg --no-default-keyring \ |
然后,用户就可以执行machinectl pull-[tar|raw] https://hub.nspawn.org/storage/发行版/版本/架构/文件名.xz [容器名]
拉取镜像了。
默认会在拉取后或导入后以隐藏镜像保存在/var/lib/machines/
,并创建一个名为容器名
的可写快照,如果不需要快照,可以把容器名设为-
。
也有一种简单的方法,就是使用 nspawn/nspawn 的封装脚本,它会自动导入密钥并进行拉取,使用方法为:
1 | -i|--init 拉取镜像 |
具体可拉取的镜像可以看 https://hub.nspawn.org/storage/list.txt 。
初始化容器
使用systemd-nspawn
命令临时启动一个容器,它的选项影响了容器的初始化配置,一些选项如下:
-M|--machine=
:设置容器名称。此名称还会被设为容器的默认主机名。-D|--directory=
:指定容器根文件系统目录。-b|--boot
:启动容器中的init
进程。--background
:后台启动容器。-U
:启用非特权容器,这和LXC的概念一样。-j
:尝试将容器内的日志收集到宿主机上。-E NAME=VALUE|--setenv=NAME=VALUE
:在启动容器时,设置一些环境变量。--read-only
:只读启动。-x|--ephemeral
:临时模式,在退出容器时抹除任何操作。
执行这条命令设置容器密码:systemd-nspawn -D 根文件系统目录 passwd
然后使用这条命令启动容器即可:systemd-nspawn -D 根文件系统目录 -M 容器名 -b [-U]
统一管理
machinectl
是镜像与容器统一管理命令,它的操作有以下几种:
镜像管理
列出可用镜像machinectl list-images
查看镜像情况machinectl show-image|image-status 镜像名
克隆一个镜像machinectl clone 镜像名 新镜像名
重命名一个镜像machinectl rename 镜像名 新镜像名
把镜像只读化machinectl read-only 镜像名 yes|no
删除镜像machinectl remove 镜像名
一键清除旧版镜像machinectl clean
容器管理
服务化启动容器machinectl start 镜像名
这会启动容器并创建一个systemd-nspawn@容器名.service
服务。
列出容器machinectl list
查看容器状态machinectl show|status 容器名
关机|重启|终止|杀死容器machinectl poweroff|reboot|terminate|kill 容器名
-s|--signal=
:发送的信号。
这等价于systemctl stop systemd-nspawn@容器名
。
登入容器machinectl login 容器名
登入时总是使用/dev/console
。
和LXC一样,登入后会占用一个终端。
在容器中执行命令machinectl shell [用户名@]容器名 [命令]
若没有命令,默认在容器中以指定用户身份启动Shell,这相当于machinectl login
,但是不会进行登录(这意味着没有任何用户变量),而且总是会产生新会话,并且在退出后杀死。-E|--setenv=VAR[=VALUE]
:设置一个环境变量。
容器开机启动
启用:machinectl enable 容器名
这等价于systemctl enable systemd-nspawn@容器名
。
禁用:machinectl disable 容器名
这等价于systemctl disable systemd-nspawn@容器名
。
从主机上拷贝文件machinectl copy-to 容器名 主机路径 [容器路径]
从容器中拷贝文件machinectl copy-from 容器名 容器路径 [主机路径]
临时配置目录映射machinectl bind 容器名 主机路径 [容器路径]
--read-only
:只读映射。--mkdir
:映射时,如果目录不存在则创建。
配置
网络配置
和LXC不同,systemd-nspawn容器可以使用主机的网络命名空间,也就是说,systemd-nspawn容器可以使用主机网络或者私有网络两种模式。
主机网络
systemd-nspawn默认采用这一模式。即容器直接使用主机的网络命名空间,容器共享主机的网络接口,容器将能够访问主机上的所有网络服务,来自容器的数据包将在外部网络中显示为来自主机(即共享同一IP地址)。
仅本地模式
容器仅仅只有本地回环网络,不存在其他任何网络接口。
没什么意义的网络模式,在使用systemd-nspawn
启动容器时,添加选项--private-network
即可。
如果使用machinectl
,创建容器配置/etc/systemd/nspawn/容器名.nspawn
,添加以下内容:
1 | [Network] |
Veth模式
给容器创建一个Veth设备,用于和主机之间通信,容器对外部网络的通信通过NAT实现。这种模式很类似于LXC的默认模式。
在使用systemd-nspawn
启动容器时,添加选项--network-veth
即可。
如果使用machinectl
,创建容器配置/etc/systemd/nspawn/容器名.nspawn
,添加以下内容:
1 | [Network] |
如果使用systemd-networkd,那么主机上的DHCP服务端和客户机上的DHCP客户端的会分别通过/usr/lib/systemd/network/80-container-ve.network
和/usr/lib/systemd/network/80-container-host0.network
文件建立起来,以此实现容器自动分配IP地址。
如果使用其他网络管理工具,可以在容器中配置静态IP,或者手动配置主机和容器上的DHCP服务端和客户端。
如果使用systemd-networkd,NAT将通过/usr/lib/systemd/network/80-container-ve.network
中的IPMasquerade=yes
选项自动完成。
如果使用其他网络管理工具,若想让主机连接外网,需要配置类似iptables -t nat -A POSTROUTING -s 192.168.163.192/28 -j MASQUERADE
这样的NAT规则。
桥接模式
将容器对应的主机端Veth直接桥接到指定的网桥上,网桥应当是一个二层的静态网桥。
在使用systemd-nspawn
启动容器时,添加选项--network-bridge=网桥
即可。
如果使用machinectl
,创建容器配置/etc/systemd/nspawn/容器名.nspawn
,添加以下内容:
1 | [Network] |
端口映射
如果为容器开启了私有网络,那么可以在使用systemd-nspawn
启动容器时,添加选项-p|--port=[协议:]宿主端口[:容器端口]
进行端口映射。
如果使用machinectl
,创建容器配置/etc/systemd/nspawn/容器名.nspawn
,添加以下内容:
1 | [Network] |
专用网卡
直接将主机网卡分配给容器,直到容器停止前,主机都不能使用该网卡。
在使用systemd-nspawn
启动容器时,添加选项--network-interface=设备名
即可。
如果使用machinectl
,创建容器配置/etc/systemd/nspawn/容器名.nspawn
,添加以下内容:
1 | [Network] |
目录映射
在使用systemd-nspawn
启动容器时,添加选项:
--bind=源路径:目标路径[:挂载选项]
:添加目录映射。--bind-ro=源路径:目标路径[:挂载选项]
:添加只读目录映射。--tmpfs=挂载路径[:挂载选项]
:在容器内挂载一个tmpfs内存文件系统。--overlay=|--overlay-ro=
:映射OverlayFS,接受一系列冒号分隔的目录路径列表,最后一个路径表示容器内映射路径。
如果使用machinectl
,创建容器配置/etc/systemd/nspawn/容器名.nspawn
,添加以下内容:
1 | [Files] |
资源限制
使用systemctl set-property systemd-nspawn@容器名 限制项=值
命令对容器使用的资源进行限制。
常用的限制项有:MemoryMax=
:限制内存使用。AllowedCPUs=
:允许使用的CPU核心。CPUQuota=
:最大CPU占用率。