容器技术 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。 您将直接引导到容器中的 root 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,其中协议为 tcp 或 udp,host 为主机上的有效端口号,container 为容器上的有效端口。 您可以省略协议并仅指定 host:container。 我经常使用类似于 –port=2222:22 的东西。

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

使用 systemd 组件

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

机器控制

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

其他 systemd 命令

大多数 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/