Fedora 中的容器技术：systemd-nspawn
容器 systemd
欢迎来到“Fedora 中的容器技术”系列！本文是该系列文章中的第一篇，它将说明你可以怎样使用 Fedora 中各种可用的容器技术。本文将学习 `systemd-nspawn` 的相关知识。


![](/data/attachment/album/201607/28/165435z20bv1330q40yvfd.png)


### 容器是什么？


一个容器就是一个用户空间实例，它能够在与托管容器的系统（叫做宿主系统）相隔离的环境中运行一个程序或者一个操作系统。这和 `chroot` 或 [虚拟机](https://en.wikipedia.org/wiki/Virtual_machine) 的思想非常类似。运行在容器中的进程是由与宿主操作系统相同的内核来管理的，但它们是与宿主文件系统以及其它进程隔离开的。


### 什么是 systemd-nspawn？


systemd 项目认为应当将容器技术变成桌面的基础部分，并且应当和用户的其余系统集成在一起。为此，systemd 提供了 `systemd-nspawn`，这款工具能够使用多种 Linux 技术创建容器。它也提供了一些容器管理工具。


`systemd-nspawn` 和 `chroot` 在许多方面都是类似的，但是前者更加强大。它虚拟化了文件系统、进程树以及客户系统中的进程间通信。它的吸引力在于它提供了很多用于管理容器的工具，例如用来管理容器的 `machinectl`。由 `systemd-nspawn` 运行的容器将会与 systemd 组件一同运行在宿主系统上。举例来说，一个容器的日志可以输出到宿主系统的日志中。


在 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 系统，你可以运行下面的命令，要将“/absolute/path/”替换成任何你希望容器存放的位置。



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

```

![](/data/attachment/album/201607/28/165436ermjd0dkkidkm5ir.png)


### 设置网络


如果你尝试启动一个服务，但它绑定了你宿主机正在使用的端口，你将会注意到这个问题：你的容器正在使用和宿主机相同的网络接口。幸运的是，`systemd-nspawn` 提供了几种可以将网络从宿主机分开的方法。


#### 本地网络


第一种方法是使用 `--private-network` 标志，它默认仅创建一个回环设备。这对于你不需要使用网络的环境是非常理想的，例如构建系统和其它持续集成系统。


#### 多个网络接口


如果你有多个网络接口设备，你可以使用 `--network-interface` 标志给容器分配一个接口。想要给我的容器分配 `eno1`，我会添加选项 `--network-interface=eno1`。当某个接口分配给一个容器后，宿主机就不能同时使用那个接口了。只有当容器彻底关闭后，宿主机才可以使用那个接口。


#### 共享网络接口


对于我们中那些并没有额外的网络设备的人来说，还有其它方法可以访问容器。一种就是使用 `--port` 选项。这会将容器中的一个端口定向到宿主机。使用格式是 `协议:宿主机端口:容器端口`，这里的协议可以是 `tcp` 或者 `udp`，`宿主机端口` 是宿主机的一个合法端口，`容器端口` 则是容器中的一个合法端口。你可以省略协议，只指定 `宿主机端口:容器端口`。我通常的用法类似 `--port=2222:22`。


你可以使用 `--network-veth` 启用完全的、仅宿主机模式的网络，这会在宿主机和容器之间创建一个虚拟的网络接口。你也可以使用 `--network-bridge` 桥接二者的连接。


### 使用 systemd 组件


如果你容器中的系统含有 D-Bus，你可以使用 systemd 提供的实用工具来控制并监视你的容器。基础安装的 Debian 并不包含 `dbus`。如果你想在 Debian Jessie 中使用 `dbus`，你需要运行命令 `apt install dbus`。


#### machinectl


为了能够轻松地管理容器，systemd 提供了 `machinectl` 实用工具。使用 `machinectl`，你可以使用 `machinectl login name` 登录到一个容器中、使用 `machinectl status name`检查状态、使用 `machinectl reboot name` 启动容器或者使用 `machinectl poweroff name` 关闭容器。


### 其它 systemd 命令


多数 systemd 命令，例如 `journalctl`, `systemd-analyze` 和 `systemctl`，都支持使用 `--machine` 选项来指定容器。例如，如果你想查看一个名为 “foobar” 的容器的日志，你可以使用 `journalctl --machine=foobar`。你也可以使用 `systemctl --machine=foobar status service` 来查看运行在这个容器中的服务状态。


![](/data/attachment/album/201607/28/165437eqdvpxofq7fiwwxv.png)


### 和 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/

```



---


via: <https://fedoramagazine.org/container-technologies-fedora-systemd-nspawn/>


作者：[John M. Harris, Jr.](https://fedoramagazine.org/container-technologies-fedora-systemd-nspawn/) 译者：[ChrisLeeGit](https://github.com/chrisleegit) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
*Welcome to the “Container technologies in Fedora” series! This is the first article in a series of articles that will explain how you can use the various container technologies available in Fedora. This first article will deal with* systemd-nspawn*.*

## What is a container?

A container is a user-space instance which can be used to run a program or an operating system in isolation from the system hosting the container (called the **host system**). The idea is very similar to a chroot or a [virtual machine](https://en.wikipedia.org/wiki/Virtual_machine). The processes running in a container are managed by the same kernel as the host operating system, but they are isolated from the host file system, and from the other processes.


## What is systemd-nspawn?

The systemd project considers container technologies as something that should fundamentally be part of the desktop and that should integrate with the rest of the user’s systems. To this end, systemd provides *systemd-nspawn*, a tool which is able to create containers using various Linux technologies. It also provides some container management tools.

In many ways, *systemd-nspawn* is similar to *chroot*, but is much more powerful. It virtualizes the file system, process tree, and inter-process communication of the guest system. Much of its appeal lies in the fact that it provides a number of tools, such as *machinectl*, for managing containers. Containers run by *systemd-nspawn* will integrate with the systemd components running on the host system. As an example, journal entries can be logged from a container in the host system’s journal.

In Fedora 24, *systemd-nspawn* has been split out from the systemd package, so you’ll need to install the *systemd-container* package. As usual, you can do that with a *dnf install systemd-container*.

## Creating the container

Creating a container with *systemd-nspawn* is easy. Let’s say you have an application made for Debian, and it doesn’t run well anywhere else. That’s not a problem, we can make a container! To set up a container with the latest version of Debian (at this point in time, Jessie), you need to pick a directory to set up your system in. I’ll be using *~/DebianJessie* for now.

Once the directory has been created, you need to run *debootstrap*, which you can install from the Fedora repositories. For Debian Jessie, you run the following command to initialize a Debian file system.

$ debootstrap --arch=amd64 stable ~/DebianJessie

This assumes your architecture is x86_64. If it isn’t, you must change *amd64* to the name of your architecture. You can find your machine’s architecture with *uname -m*.

Once your root directory is set up, you will start your container with the following command.

$ systemd-nspawn -bD ~/DebianJessie

You’ll be up and running within seconds. You’ll notice something as soon as you try to log in: you can’t use any accounts on your system. This is because *systemd-nspawn* virtualizes users. The fix is simple: remove *-b* from the previous command. You’ll boot directly to the root shell in the container. From there, you can just use *passwd* to set a password for root, or you can use *adduser* to add a new user. As soon as you’re done with that, go ahead and put the *-b* flag back. You’ll boot to the familiar login console and you log in with the credentials you set.

All of this applies for any distribution you would want to run in the container, but you need to create the system using the correct package manager. For Fedora, you would use DNF instead of *debootstrap*. To set up a minimal Fedora system, you can run the following command, replacing the absolute path with wherever you want the container to be.

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

## Setting up the network

You’ll notice an issue if you attempt to start a service that binds to a port currently in use on your host system. Your container is using the same network interface. Luckily, *systemd-nspawn* provides several ways to achieve separate networking from the host machine.

#### Local networking

The first method uses the *–private-network* flag, which only creates a loopback device by default. This is ideal for environments where you don’t need networking, such as build systems and other continuous integration systems.

#### Multiple networking interfaces

If you have multiple network devices, you can give one to the container with the *–network-interface* flag. To give *eno1* to my container, I would add the flag *–network-interface=eno1*. While an interface is assigned to a container, the host can’t use it at the same time. When the container is completely shut down, it will be available to the host again.

#### Sharing network interfaces

For those of us who don’t have spare network devices, there are other options for providing access to the container. One of those is the *–port* flag. This forwards a port on the container to the host. The format is *protocol:host:container*, where protocol is either *tcp* or *udp*, *host* is a valid port number on the host, and *container* is a valid port on the container. You can omit the protocol and specify only *host:container*. I often use something similar to *–port=2222:22*.

You can enable complete, host-only networking with the *–network-veth* flag, which creates a virtual Ethernet interface between the host and the container. You can also bridge two connections with *–network-bridge*.

## Using systemd components

If the system in your container has D-Bus, you can use systemd’s provided utilities to control and monitor your container. Debian doesn’t include *dbus* in the base install. If you want to use it with Debian Jessie, you’ll want to run *apt install dbus*.

#### machinectl

To easily manage containers, systemd provides the *machinectl* utility. Using *machinectl*, you can log in to a container with *machinectl login name*, check the status with

*machinectl status*, reboot with

`name`*machinectl reboot*, or power it off with

`name`*machinectl poweroff*.

`name`## Other systemd commands

Most systemd commands, such as *journalctl*, *systemd-analyze*, and *systemctl*, support containers with the *–machine* option. For example, if you want to see the journals of a container named “foobar”, you can use *journalctl –machine=foobar*. You can also see the status of a service running in this container with *systemctl –machine=foobar status service*.

## Working with SELinux

If you’re running with SELinux enforcing (the default in Fedora), you’ll need to set the SELinux context for your container. To do that, you need to run the following two commands on the host system.

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

Make sure you replace “/path/to/container” with the path to your container. For my container, “DebianJessie”, I would run the following:

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

## biji

can I run xwindow app from inside container?

## John M. Harris, Jr.

If you’re sharing host networking, I can confirm that you can. If you aren’t, you may run into issues I don’t know about. Just make sure to set the DISPLAY variable.

## Anass Ahmed

Can you elaborate more?

I started debian with that command:

. What should I do to make it run specifc X app in my current X session?

## Anass Ahmed

After some muddling through searches and topics, I was able to do it 😀

This Guide was great: http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/

I can now see the differences between the spotify version I’ve here in Fedora and the one that natively work under Debian 😀

## Oleg Pykhalov

I did it in docker and lxc, so pretty sure you can, check info about X11 socket and xhost

## baoboa

look there https://wiki.archlinux.org/index.php/Systemd-nspawn#X_environment for nspawn specific

“–bind=/tmp/.X11-unix:/tmp/.X11-unix” option is needed in addition of setting up the DISPLAY variable inside the container

## Pierre

Interesting. I wonder if there are advantages of using this instead of docker.

Regards, Pierre

## Robert Smol

I think the main advantage is running multiple processes inside the container (e.g. postgresql+uwsgi+nginx) + I guess it also hes better separation then docker. Now I am also guessing, but it looks like you do have direct access to the container filesystem.

## Robert Smol

The commands for SELinux should be run under root user (from $ I was guessing normal user and got :SELinux policy is not managed or store cannot be accessed.)

## Steven Snow

Would you also be able to use this for ARM based OS builds (on X86-64 hardware)? Or does the native architecture dictate the usage?

## Oleg Pykhalov

As i know you can use only x86 on x86 with containers. For others architectures you need a hypervisor like qemu.

## lahcen

can i run gui apps with container?

## Paul Stevensen

Is it possible for a running process (or thread) to enter the container? And is it possible for this process to exit the container to continue in the outside context?

## Wadiyo

Thank for sharing.

I can’t run container in window 7 not yet?

Thank

## baoboa

your are using the same kernel as the host so only linux OS are possible as container.

## biji

I’m trying to nylas sync engine using systemd-nspawn, but failed when installing mysql. would you please shed some light 😀

https://github.com/nylas/sync-engine/wiki/Running-under-systemd-nspawn