面向系统管理员的容器手册
容器

> 
> 你所需了解的容器如何工作的知识。
> 
> 
> 


![](/data/attachment/album/201810/28/111518jruxxoukh0txu447.jpg)


现在人们严重过度使用了“容器”这个术语。另外，对不同的人来说，它可能会有不同的含义，这取决于上下文。


传统的 Linux 容器只是系统上普通的进程。一组进程与另外一组进程是相互隔离的，实现方法包括：资源限制（控制组 [cgoups]）、Linux 安全限制（文件权限，基于 Capability 的安全模块、SELinux、AppArmor、seccomp 等）还有名字空间（进程 ID、网络、挂载等）。


如果你启动一台现代 Linux 操作系统，使用 `cat /proc/PID/cgroup` 命令就可以看到该进程是属于一个控制组的。还可以从 `/proc/PID/status` 文件中查看进程的 Capability 信息，从 `/proc/self/attr/current` 文件中查看进程的 SELinux 标签信息，从 `/proc/PID/ns` 目录下的文件查看进程所属的名字空间。因此，如果把容器定义为带有资源限制、Linux 安全限制和名字空间的进程，那么按照这个定义，Linux 操作系统上的每一个进程都在一个容器里。因此我们常说 [Linux 就是容器，容器就是 Linux](https://www.redhat.com/en/blog/containers-are-linux)。而**容器运行时**是这样一种工具，它调整上述资源限制、安全限制和名字空间，并启动容器。


Docker 引入了**容器镜像**的概念，镜像是一个普通的 TAR 包文件，包含了：


* **rootfs（容器的根文件系统）**：一个目录，看起来像是操作系统的普通根目录（`/`），例如，一个包含 `/usr`, `/var`, `/home` 等的目录。
* **JSON 文件（容器的配置）**：定义了如何运行 rootfs；例如，当容器启动的时候要在 rootfs 里运行什么命令（`CMD`）或者入口（`ENTRYPOINT`），给容器定义什么样的环境变量（`ENV`），容器的工作目录（`WORKDIR`）是哪个，以及其他一些设置。


Docker 把 rootfs 和 JSON 配置文件打包成**基础镜像**。你可以在这个基础之上，给 rootfs 安装更多东西，创建新的 JSON 配置文件，然后把相对于原始镜像的不同内容打包到新的镜像。这种方法创建出来的是**分层的镜像**。


<ruby> <a href="https://www.opencontainers.org/">  开放容器计划 </a> <rt>  Open Container Initiative </rt></ruby>（OCI）标准组织最终把容器镜像的格式标准化了，也就是 <ruby> <a href="https://github.com/opencontainers/image-spec/blob/master/spec.md">  镜像规范 </a> <rt>  OCI Image Specification </rt></ruby>（OCI）。


用来创建容器镜像的工具被称为**容器镜像构建器**。有时候容器引擎做这件事情，不过可以用一些独立的工具来构建容器镜像。


Docker 把这些容器镜像（**tar 包**）托管到 web 服务中，并开发了一种协议来支持从 web 拉取镜像，这个 web 服务就叫<ruby> 容器仓库 <rt>  container registry </rt></ruby>。


**容器引擎**是能从镜像仓库拉取镜像并装载到**容器存储**上的程序。容器引擎还能启动**容器运行时**（见下图）。


![](/data/attachment/album/201810/28/111529awgwuyf1wii6zff5.png)


容器存储一般是<ruby> 写入时复制 <rt>  copy-on-write </rt></ruby>（COW）的分层文件系统。从容器仓库拉取一个镜像时，其中的 rootfs 首先被解压到磁盘。如果这个镜像是多层的，那么每一层都会被下载到 COW 文件系统的不同分层。 COW 文件系统保证了镜像的每一层独立存储，这最大化了多个分层镜像之间的文件共享程度。容器引擎通常支持多种容器存储类型，包括 `overlay`、`devicemapper`、`btrfs`、`aufs` 和 `zfs`。


容器引擎将容器镜像下载到容器存储中之后，需要创建一份**容器运行时配置**，这份配置是用户/调用者的输入和镜像配置的合并。例如，容器的调用者可能会调整安全设置，添加额外的环境变量或者挂载一些卷到容器中。


容器运行时配置的格式，和解压出来的 rootfs 也都被开放容器计划 OCI 标准组织做了标准化，称为 [OCI 运行时规范](https://github.com/opencontainers/runtime-spec)。


最终，容器引擎启动了一个**容器运行时**来读取运行时配置，修改 Linux 控制组、安全限制和名字空间，并执行容器命令来创建容器的 **PID 1** 进程。至此，容器引擎已经可以把容器的标准输入/标准输出转给调用方，并控制容器了（例如，`stop`、`start`、`attach`）。


值得一提的是，现在出现了很多新的容器运行时，它们使用 Linux 的不同特性来隔离容器。可以使用 KVM 技术来隔离容器（想想迷你虚拟机），或者使用其他虚拟机监视器策略（例如拦截所有从容器内的进程发起的系统调用）。既然我们有了标准的运行时规范，这些工具都能被相同的容器引擎来启动。即使在 Windows 系统下，也可以使用 OCI 运行时规范来启动 Windows 容器。


容器编排器是一个更高层次的概念。它是在多个不同的节点上协调容器执行的工具。容器编排工具通过和容器引擎的通信来管理容器。编排器控制容器引擎做容器的启动和容器间的网络连接，它能够监控容器，在负载变高的时候进行容器扩容。




---


via: <https://opensource.com/article/18/8/sysadmins-guide-containers>


作者：[Daniel J Walsh](https://opensource.com/users/rhatdan) 选题：[lujun9972](https://github.com/lujun9972) 译者：[belitex](https://github.com/belitex) 校对：[wxy](https://github.com/wxy)


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


OK
The term "containers" is heavily overused. Also, depending on the context, it can mean different things to different people.

Traditional Linux containers are really just ordinary processes on a Linux system. These groups of processes are isolated from other groups of processes using resource constraints (control groups [cgroups]), Linux security constraints (Unix permissions, capabilities, SELinux, AppArmor, seccomp, etc.), and namespaces (PID, network, mount, etc.).

If you boot a modern Linux system and took a look at any process with `cat /proc/PID/cgroup`

, you see that the process is in a cgroup. If you look at `/proc/PID/status`

, you see capabilities. If you look at `/proc/self/attr/current`

, you see SELinux labels. If you look at `/proc/PID/ns`

, you see the list of namespaces the process is in. So, if you define a container as a process with resource constraints, Linux security constraints, and namespaces, by definition every process on a Linux system is in a container. This is why we often say [Linux is containers, containers are Linux](https://www.redhat.com/en/blog/containers-are-linux). **Container runtimes** are tools that modify these resource constraints, security, and namespaces and launch the container.

Docker introduced the concept of a **container image**, which is a standard TAR file that combines:

**Rootfs (container root filesystem):**A directory on the system that looks like the standard root (`/`

) of the operating system. For example, a directory with`/usr`

,`/var`

,`/home`

, etc.**JSON file (container configuration):**Specifies how to run the rootfs; for example, what**command**or**entrypoint**to run in the rootfs when the container starts;**environment variables**to set for the container; the container's**working directory**; and a few other settings.

Docker "`tar`

's up" the rootfs and the JSON file to create the **base image**. This enables you to install additional content on the rootfs, create a new JSON file, and `tar`

the difference between the original image and the new image with the updated JSON file. This creates a **layered image**.

The definition of a container image was eventually standardized by the [Open Container Initiative (OCI)](https://www.opencontainers.org/) standards body as the [OCI Image Specification](https://github.com/opencontainers/image-spec/blob/master/spec.md).

Tools used to create container images are called **container image builders**. Sometimes container engines perform this task, but several standalone tools are available that can build container images.

Docker took these container images (**tarballs**) and moved them to a web service from which they could be pulled, developed a protocol to pull them, and called the web service a **container registry**.

**Container engines** are programs that can pull container images from container registries and reassemble them onto **container storage**. Container engines also launch **container runtimes** (see below).

![Linux container internals Linux container internals](https://opensource.com/sites/default/files/linux_container_internals_2.0_-_hosts.png)

Linux container internals. Illustration by Scott McCarty. [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)

Container storage is usually a **copy-on-write** (COW) layered filesystem. When you pull down a container image from a container registry, you first need to untar the rootfs and place it on disk. If you have multiple layers that make up your image, each layer is downloaded and stored on a different layer on the COW filesystem. The COW filesystem allows each layer to be stored separately, which maximizes sharing for layered images. Container engines often support multiple types of container storage, including `overlay`

, `devicemapper`

, `btrfs`

, `aufs`

, and `zfs`

.


After the container engine downloads the container image to container storage, it needs to create a **container runtime configuration.** The runtime configuration combines input from the caller/user along with the content of the container image specification. For example, the caller might want to specify modifications to a running container's security, add additional environment variables, or mount volumes to the container.

The layout of the container runtime configuration and the exploded rootfs have also been standardized by the OCI standards body as the [OCI Runtime Specification](https://github.com/opencontainers/runtime-spec).

Finally, the container engine launches a **container runtime** that reads the container runtime specification; modifies the Linux cgroups, Linux security constraints, and namespaces; and launches the container command to create the container's **PID 1**. At this point, the container engine can relay `stdin`

/`stdout`

back to the caller and control the container (e.g., stop, start, attach).

Note that many new container runtimes are being introduced to use different parts of Linux to isolate containers. People can now run containers using KVM separation (think mini virtual machines) or they can use other hypervisor strategies (like intercepting all system calls from processes in containers). Since we have a standard runtime specification, these tools can all be launched by the same container engines. Even Windows can use the OCI Runtime Specification for launching Windows containers.

At a much higher level are **container orchestrators.** Container orchestrators are tools used to coordinate the execution of containers on multiple different nodes. Container orchestrators talk to container engines to manage containers. Orchestrators tell the container engines to start containers and wire their networks together. Orchestrators can monitor the containers and launch additional containers as the load increases.

## 2 Comments