介绍

systemd-nspawn是一个类似chroot一样的命令,用来启动一个容器,但是有比chroot更加强大的功能,能够完全虚拟化文件系统、进程树等系统,同时对于容器的网络接口、资源占用进行限制。

systemd-nspawn与docker类似,但又存在一些不同点,这些不同点主要是因为软件设计运行的场景不一样。Docker容器更加注重颗粒化的管理,容器作为最基本的单位,每个容器只运行单一的进程,并且由多个容器组成一个运用,比如如果要通过Docker运行WordPress,还需要配置一个MariaDB或是MySQL容器,这样的架构方便进行集群和批量管理,能弹性的扩展资源,更适合在云计算平台上使用。

相对Docker而言,systemd-nspawn的一些特点,让我觉得在一些场景上,systemd-nspawn更适合个人/单机使用:

  1. systemd-nspawn启动一个容器则会完整的启动整个系统,可以把依赖的服务都集中到一个容器里面
  2. systemd-nspawnsystemd自带组件,而systemd目前作为主流发行版的默认init进程,基本上所有Linux发行版都会自带
  3. 容器内到容器外的无缝对接,使用systemctl加上参数--machine就可以控制容器内的服务,journalctl也支持查看容器内服务的日志
  4. systemd-nspawn可以直接使用现在的文件系统作为容器的rootfs启动,不同于Docker的copy-on-write,这点看似比较傻瓜,却比较实用,特别是个人非常折腾的时候。

配置

容器的配置非常的简单,只要保证容器rootfs存在,就可以启动容器,Debian系容器使用工具debootstrap 下载,Arch对应使用pacstrap安装,由于容器与主机共享内核,容器内部不需要安装内核和内核模块。

容器名称myContainer
服务单元[email protected]
容器根目录/var/lib/machines/myContainer
配置文件/etc/systemd/nspawn/myContainer.nspawn

容器内部包括常见设定,包括root密码、时区、主机名等可以使用systemd-nspawn -D root启动(忽略-b参数)跳过登录过程启动容器,之后进行配置。容器本身运行环境、资源限制则通过.nspawn配置完成,主要的配置包括文件系统还有网络配置。

用户空间隔离:--private-users

这个参数用于隔离用户空间文件的uid/gid,如果不设定这个参数,默认是打开的,即运行时候容器内和容器外,文件拥有者不一样,具体表现为容器内的uid/gid在实际文件系统中会添加一段偏移,容器外可以控制容器内文件,但是如果直接拷贝文件到容器里面,容器内运行的进程是没有读写权限的。

如果启用了--private-users参数,原有文件依旧会保持原有uid/gid,只有在容器内发生读写的时候,产生新的文件才会映射到新的拥有者,通过开启--private-users-chown参数,强行迫使原有文件全部映射到新的用户和用户组。同理,也可以反向操作,将发生偏移的容器内的文件,全部修改回正常的uid/gid

私有网络配置:--private-network

对应配置文件[Network]下的Private,启用这个参数之后,宿主机网络和容器网络将隔离开,只能通过NAT或是桥接方式通讯,设置--network-interface--network-macvlan--network-ipvlan--network-veth都会间接开启私有网络。

--network-interface 参数指定一个网络给容器,这个参数不是共享网卡,而是直接从宿主机中移除这个网卡,并添加到容器中,在停用容器之后才会返回这个网卡。参数对应配置文件中[Network]Interface。注意:不能直接把无线网卡分配给容器,如果要分配无线网卡给容器,无线网卡必须支持命名空间。

--network-macvlan/--network-ipvlan,相当于桥接,网卡的前缀是mv-/iv-macvlan是同个网卡不同MAC地址,ipvlan是同个MAC地址不同IP地址。这两个方法都有一个缺点,那就是无法直接于宿主机通讯,即使处于同一个网段下面。

--network-veth,在主机和容器之间创建一个虚拟网卡,网卡前缀是ve---network-bridge把主机上的桥接网卡映射到容器里面,不能直接指定主机上的物理网卡,必须在主机端建立bridge之后,把这个bridge分配给容器,这个参数会间接启用--network-veth

其他的网络相关参数还有 --network-zone=或是--port,用于批量管理容器网络,后者用于暴露端口到主机,不过都是在开启私有网络并且配置完整的时候可以启用,具体可以去看手册。

要禁用私有网络,设定参数--network-veth=no/--private-network=no或是在配置文件里面添加:

[Network]
Private=no
VirtualEthernet=no

这样子容器于主机共享网络接口。

资源限定

限定容器能占用资源有时候也是非常重要的,这一部分可以参考systemd资源控制

systemctl set-property [email protected] MemoryMax=2G
systemctl set-property [email protected] CPUQuota=200%

容器管理

容器管理使用命令machinectl ,但是实际上也是等同systemctl对应的命令

machinectlsystemctl说明
machinectl listsystemctl list-machines列出正在运行的容器
machinectl login name连接到容器控制台
machinectl status namesystemctl status [email protected]查看容器运行状态
machinectl start namesystemctl start [email protected]启动容器
machinectl poweroff namesystemctl stop [email protected]关闭容器
machinectl reboot namesystemctl restart [email protected]重启容器
machinectl terminate name强行停止容器,在容器没有反应的时候使用
machinectl enable namesystemctl enable [email protected]开机自启
machinectl disable namesystemctl disable [email protected]禁用自启