“容器”一词已被过度使用。此外,根据上下文,它对不同的人可能有不同的含义。
传统的 Linux 容器实际上只是 Linux 系统上的普通进程。这些进程组与其他进程组隔离,使用了资源约束(控制组 [cgroups])、Linux 安全约束(Unix 权限、capabilities、SELinux、AppArmor、seccomp 等)和命名空间(PID、网络、挂载等)。
如果您启动一个现代 Linux 系统,并使用 cat /proc/PID/cgroup
查看任何进程,您会看到该进程位于一个 cgroup 中。如果您查看 /proc/PID/status
,您会看到 capabilities。如果您查看 /proc/self/attr/current
,您会看到 SELinux 标签。如果您查看 /proc/PID/ns
,您会看到进程所在的命名空间列表。因此,如果您将容器定义为具有资源约束、Linux 安全约束和命名空间的进程,那么根据定义,Linux 系统上的每个进程都在一个容器中。这就是为什么我们经常说 Linux 就是容器,容器就是 Linux。 容器运行时是修改这些资源约束、安全性和命名空间并启动容器的工具。
Docker 引入了 容器镜像 的概念,它是一个标准的 TAR 文件,组合了
- Rootfs(容器根文件系统): 系统上的一个目录,看起来像操作系统的标准根目录 (
/
)。例如,一个包含/usr
、/var
、/home
等的目录。 - JSON 文件(容器配置): 指定如何运行 rootfs;例如,当容器启动时,在 rootfs 中运行什么 命令 或 入口点;为容器设置的 环境变量;容器的 工作目录;以及其他一些设置。
Docker “tar
打包” rootfs 和 JSON 文件以创建 基础镜像。这使您能够在 rootfs 上安装其他内容,创建新的 JSON 文件,并 tar
打包原始镜像和包含更新 JSON 文件的新镜像之间的差异。这将创建一个 分层镜像。
容器镜像的定义最终由 开放容器倡议 (OCI) 标准组织标准化为 OCI 镜像规范。
用于创建容器镜像的工具称为 容器镜像构建器。有时容器引擎执行此任务,但也有几种独立的工具可用于构建容器镜像。
Docker 获取这些容器镜像(tarball),并将它们移动到 Web 服务,可以从中拉取它们,开发了一种拉取它们的协议,并将该 Web 服务称为 容器注册表。
容器引擎 是可以从容器注册表拉取容器镜像并将它们重新组装到 容器存储 上的程序。容器引擎还启动 容器运行时(见下文)。

Linux 容器内部结构。插图作者:Scott McCarty。 CC BY-SA 4.0
容器存储通常是 写时复制 (COW) 分层文件系统。当您从容器注册表拉取容器镜像时,您首先需要解压 rootfs 并将其放置在磁盘上。如果您的镜像由多个层组成,则每个层都会被下载并存储在 COW 文件系统上的不同层上。COW 文件系统允许单独存储每个层,从而最大限度地提高分层镜像的共享性。容器引擎通常支持多种类型的容器存储,包括 overlay
、devicemapper
、btrfs
、aufs
和 zfs
。
在容器引擎将容器镜像下载到容器存储后,它需要创建一个 容器运行时配置。 运行时配置结合了来自调用者/用户的输入以及容器镜像规范的内容。例如,调用者可能希望指定对正在运行的容器的安全性的修改,添加额外的环境变量,或将卷挂载到容器。
容器运行时配置和展开的 rootfs 的布局也已由 OCI 标准组织标准化为 OCI 运行时规范。
最后,容器引擎启动一个 容器运行时,它读取容器运行时规范;修改 Linux cgroup、Linux 安全约束和命名空间;并启动容器命令以创建容器的 PID 1。此时,容器引擎可以将 stdin
/stdout
中继回调用者并控制容器(例如,停止、启动、附加)。
请注意,正在引入许多新的容器运行时,以使用 Linux 的不同部分来隔离容器。人们现在可以使用 KVM 隔离(类似于迷你虚拟机)运行容器,或者他们可以使用其他虚拟机管理程序策略(例如,拦截容器中进程的所有系统调用)。由于我们有一个标准的运行时规范,这些工具都可以由相同的容器引擎启动。甚至 Windows 也可以使用 OCI 运行时规范来启动 Windows 容器。
在更高的层面上是 容器编排器。 容器编排器是用于协调多个不同节点上容器执行的工具。容器编排器与容器引擎对话以管理容器。编排器告诉容器引擎启动容器并将它们的网络连接在一起。编排器可以监视容器并在负载增加时启动其他容器。
2 条评论