欢迎来到“fedora 中的容器技术”系列!本文是该系列文章中的第一篇,它将说明你可以怎样使用 fedora 中各种可用的容器技术。本文将学习 <code>systemd-nspawn</code> 的相关知识。
<a target="_blank"></a>
systemd 项目认为应当将容器技术变成桌面的基础部分,并且应当和用户的其余系统集成在一起。为此,systemd 提供了 <code>systemd-nspawn</code>,这款工具能够使用多种 linux 技术创建容器。它也提供了一些容器管理工具。
<code>systemd-nspawn</code> 和 <code>chroot</code> 在许多方面都是类似的,但是前者更加强大。它虚拟化了文件系统、进程树以及客户系统中的进程间通信。它的吸引力在于它提供了很多用于管理容器的工具,例如用来管理容器的<code>machinectl</code>。由 <code>systemd-nspawn</code> 运行的容器将会与 systemd 组件一同运行在宿主系统上。举例来说,一个容器的日志可以输出到宿主系统的日志中。
在 fedora 24 上,<code>systemd-nspawn</code> 已经从 systemd 软件包分离出来了,所以你需要安装 <code>systemd-container</code> 软件包。一如往常,你可以使用 <code>dnf install systemd-container</code> 进行安装。
使用 <code>systemd-nspawn</code> 创建一个容器是很容易的。假设你有一个专门为 debian 创造的应用,并且无法在其它发行版中正常运行。那并不是一个问题,我们可以创造一个容器!为了设置容器使用最新版本的 debian(现在是 jessie),你需要挑选一个目录来放置你的系统。我暂时将使用目录 <code>~/debianjessie</code>。
一旦你创建完目录,你需要运行 <code>debootstrap</code>,你可以从 fedora 仓库中安装它。对于 debian jessie,你运行下面的命令来初始化一个 debian 文件系统。
<code>$ debootstrap --arch=amd64 stable ~/debianjessie</code>
以上默认你的架构是 x86_64。如果不是的话,你必须将架构的名称改为 <code>amd64</code>。你可以使用 <code>uname -m</code> 得知你的机器架构。
一旦设置好你的根目录,你就可以使用下面的命令来启动你的容器。
<code>$ systemd-nspawn -bd ~/debianjessie</code>
容器将会在数秒后准备好并运行,当你试图登录时就会注意到:你无法使用你的系统上任何账户。这是因为<code>systemd-nspawn</code> 虚拟化了用户。修复的方法很简单:将之前的命令中的 <code>-b</code> 移除即可。你将直接进入容器的 root 用户的 shell。此时,你只能使用 <code>passwd</code> 命令为 root 设置密码,或者使用 <code>adduser</code> 命令添加一个新用户。一旦设置好密码或添加好用户,你就可以把 <code>-b</code> 标志添加回去然后继续了。你会进入到熟悉的登录控制台,然后你使用设置好的认证信息登录进去。
以上对于任意你想在容器中运行的发行版都适用,但前提是你需要使用正确的包管理器创建系统。对于 fedora,你应使用 dnf 而非 <code>debootstrap</code>。想要设置一个最小化的 fedora 系统,你可以运行下面的命令,要将“/absolute/path/”替换成任何你希望容器存放的位置。
<code>$ sudo dnf --releasever=24 --installroot=/absolute/path/ install systemd passwd dnf fedora-release</code>

如果你尝试启动一个服务,但它绑定了你宿主机正在使用的端口,你将会注意到这个问题:你的容器正在使用和宿主机相同的网络接口。幸运的是,<code>systemd-nspawn</code> 提供了几种可以将网络从宿主机分开的方法。
第一种方法是使用 <code>--private-network</code> 标志,它默认仅创建一个回环设备。这对于你不需要使用网络的环境是非常理想的,例如构建系统和其它持续集成系统。
如果你有多个网络接口设备,你可以使用 <code>--network-interface</code> 标志给容器分配一个接口。想要给我的容器分配 <code>eno1</code>,我会添加选项 <code>--network-interface=eno1</code>。当某个接口分配给一个容器后,宿主机就不能同时使用那个接口了。只有当容器彻底关闭后,宿主机才可以使用那个接口。
对于我们中那些并没有额外的网络设备的人来说,还有其它方法可以访问容器。一种就是使用 <code>--port</code> 选项。这会将容器中的一个端口定向到宿主机。使用格式是 <code>协议:宿主机端口:容器端口</code>,这里的协议可以是 <code>tcp</code>或者 <code>udp</code>,<code>宿主机端口</code> 是宿主机的一个合法端口,<code>容器端口</code> 则是容器中的一个合法端口。你可以省略协议,只指定 <code>宿主机端口:容器端口</code>。我通常的用法类似 <code>--port=2222:22</code>。
你可以使用 <code>--network-veth</code> 启用完全的、仅宿主机模式的网络,这会在宿主机和容器之间创建一个虚拟的网络接口。你也可以使用 <code>--network-bridge</code> 桥接二者的连接。
如果你容器中的系统含有 d-bus,你可以使用 systemd 提供的实用工具来控制并监视你的容器。基础安装的 debian 并不包含 <code>dbus</code>。如果你想在 debian jessie 中使用 <code>dbus</code>,你需要运行命令 <code>apt install dbus</code>。
为了能够轻松地管理容器,systemd 提供了 <code>machinectl</code> 实用工具。使用 <code>machinectl</code>,你可以使用<code>machinectl login name</code> 登录到一个容器中、使用 <code>machinectl status name</code>检查状态、使用<code>machinectl reboot name</code> 启动容器或者使用 <code>machinectl poweroff name</code> 关闭容器。
多数 systemd 命令,例如 <code>journalctl</code>, <code>systemd-analyze</code> 和 <code>systemctl</code>,都支持使用 <code>--machine</code> 选项来指定容器。例如,如果你想查看一个名为 “foobar” 的容器的日志,你可以使用 <code>journalctl --machine=foobar</code>。你也可以使用 <code>systemctl --machine=foobar status service</code> 来查看运行在这个容器中的服务状态。
如果你要使用 selinux 强制模式(fedora 默认模式),你需要为你的容器设置 selinux 环境。想要那样的话,你需要在宿主系统上运行下面两行命令。
<code>$ semanage fcontext -a -t svirt_sandbox_file_t "/path/to/container(/.*)?"</code>
<code>$ restorecon -r /path/to/container/</code>
确保使用你的容器路径替换 “/path/to/container”。对于我的容器 "debianjessie",我会运行下面的命令:
<code>$ semanage fcontext -a -t svirt_sandbox_file_t "/home/johnmh/debianjessie(/.*)?"</code>
<code>$ restorecon -r /home/johnmh/debianjessie/</code>
原文发布时间为:2016-07-28
本文来自云栖社区合作伙伴“linux中国”