容器技术 Fedora: systemd-nspawn

欢迎来到“容器技术在 Fedora“ 系列! 这是一系列文章中的第一篇,将解释如何使用各种容器技术 Fedora. 第一篇文章将讨论 systemd-nspawn。

什么是容器?

容器是一个用户空间实例,可用于独立于托管容器的系统运行程序或操作系统(称为 主机系统)。 这个想法非常类似于 chroot 或 虚拟机. 在容器中运行的进程由与主机操作系统相同的内核管理,但它们与主机文件系统和其他进程隔离。

什么是 systemd-nspawn?

systemd 项目认为容器技术应该从根本上成为桌面的一部分,并且应该与用户的其他系统集成。 为此,systemd 提供了 systemd-nspawn,一个能够使用各种 Linux 技术创建容器的工具。 它还提供了一些容器管理工具。

在许多方面,systemd-nspawn 类似于 chroot,但功能更强大。 它将来宾系统的文件系统、进程树和进程间通信虚拟化。 它的大部分吸引力在于它提供了许多用于管理容器的工具,例如 machinectl。 systemd-nspawn 运行的容器将与主机系统上运行的 systemd 组件集成。 作为一个 example,可以从主机系统日志中的容器记录日志条目。

在 Fedora 24、systemd-nspawn 已经从 systemd 包中分离出来,所以你需要安装 systemd-container 包。 像往常一样,您可以使用 dnf install systemd-container 来做到这一点。

创建容器

使用 systemd-nspawn 创建容器很容易。 假设您有一个为 Debian 制作的应用程序,但它在其他任何地方都不能很好地运行。 没问题,我们可以做一个容器! 要使用最新版本的 Debian(此时为 Jessie)设置容器,您需要选择一个目录来设置您的系统。我现在将使用 ~/DebianJessie。

创建目录后,您需要运行 debootstrap,您可以从 Fedora 存储库。 对于 Debian Jessie,您可以运行以下命令来初始化 Debian 文件系统。

$ debootstrap --arch=amd64 stable ~/DebianJessie

这假设您的架构是 x86_64。 如果不是,您必须将 amd64 更改为您的架构名称。 你可以使用 uname -m 找到你机器的架构。

设置根目录后,您将使用以下命令启动容器。

$ systemd-nspawn -bD ~/DebianJessie

您将在几秒钟内启动并运行。 当您尝试登录时,您会注意到一些事情:您无法使用系统上的任何帐户。 这是因为 systemd-nspawn 虚拟化了用户。 修复很简单:从上一个命令中删除 -b。 您将直接启动到容器中的根 shell。 从那里,您可以使用 passwd 为 root 设置密码,或者您可以使用 adduser 添加新用户。 完成此操作后,请继续将 -b 标志放回原处。 您将启动到熟悉的登录控制台并使用您设置的凭据登录。

所有这些都适用于您希望在容器中运行的任何发行版,但您需要使用正确的包管理器创建系统。 为了 Fedora,您将使用 DNF 而不是 debootstrap。 设置最小 Fedora 系统,您可以运行以下命令,将绝对路径替换为您希望容器所在的位置。

$ sudo dnf --releasever=24 --installroot=/absolute/path/ install systemd passwd dnf fedora-release

设置网络

如果您尝试启动绑定到主机系统上当前正在使用的端口的服务,您会注意到一个问题。 您的容器使用相同的网络接口。 幸运的是,systemd-nspawn 提供了几种方法来实现与主机分离的网络。

本地网络

第一种方法使用-private-network 标志,默认情况下只创建一个环回设备。 这非常适合不需要联网的环境,例如构建系统和其他持续集成系统。

多个网络接口

如果您有多个网络设备,您可以使用 –network-interface 标志为容器分配一个。 要将 eno1 提供给我的容器,我将添加标志 –network-interface=eno1。 将接口分配给容器时,主机不能同时使用它。 当容器完全关闭时,它将再次可供主机使用。

共享网络接口

对于我们这些没有备用网络设备的人,还有其他选项可以提供对容器的访问。 其中之一是 –port 标志。 这会将容器上的端口转发到主机。 格式为protocol:host:container,其中protocol 是tcp 或udp,host 是主机上的有效端口号,container 是容器上的有效端口。 您可以省略协议并仅指定主机:容器。 我经常使用类似于–port=2222:22 的东西。

您可以使用 –network-veth 标志启用完整的仅主机网络,该标志在主机和容器之间创建虚拟以太网接口。 您还可以使用 –network-bridge 桥接两个连接。

使用 systemd 组件

如果您的容器中的系统有 D-Bus,您可以使用 systemd 提供的实用程序来控制和监视您的容器。 Debian 在基本安装中不包含 dbus。 如果您想将它与 Debian Jessie 一起使用,您需要运行 apt install dbus。

机器控制

为了轻松管理容器,systemd 提供了 machinectl 实用程序。 使用 machinectl,您可以使用 machinectl login name 登录容器,使用 machinectl status name 检查状态,使用 machinectl reboot name 重新启动,或使用 machinectl poweroff name 关闭它。

其他系统命令

大多数 systemd 命令,例如 journalctl、systemd-analyze 和 systemctl,都支持带有 –machine 选项的容器。 为了 example,如果要查看名为“foobar”的容器的日志,可以使用 journalctl –machine=foobar。 您还可以使用 systemctl –machine=foobar status service 查看在此容器中运行的服务的状态。

使用 SELinux

如果您使用 SELinux 强制运行(默认 Fedora),您需要为您的容器设置 SELinux 上下文。 为此,您需要在主机系统上运行以下两个命令。

$ semanage fcontext -a -t svirt_sandbox_file_t "/path/to/container(/.*)?"
$ restorecon -R /path/to/container/

确保将“/path/to/container”替换为容器的路径。 对于我的容器“DebianJessie”,我将运行以下命令:

$ semanage fcontext -a -t svirt_sandbox_file_t "/home/johnmh/DebianJessie(/.*)?"
$ restorecon -R /home/johnmh/DebianJessie/