1. 容器运行时概述
容器运行时(Container Runtime)是容器化技术栈中最底层的执行引擎,负责管理容器的完整生命周期:从镜像拉取、容器创建、进程启动,到资源隔离与终止回收。理解容器运行时的定义、标准化接口以及不同层级的分工,是掌握基于 containerd 的控制面架构设计的前提。
1.1 容器运行时定义
容器运行时是一段直接与操作系统内核交互的软件组件,它利用 Linux 内核特性(如 cgroups、namespace、UnionFS)为容器进程提供隔离的执行环境。从功能边界来看,容器运行时承担以下核心职责:
- 镜像管理:拉取、存储、解包容器镜像,将分层文件系统挂载为容器的 rootfs。
- 容器生命周期:创建、启动、停止、删除容器进程,处理信号与退出码。
- 资源隔离:通过 cgroups 限制 CPU、内存、IO,通过 namespace 隔离进程、网络、挂载点等视图。
- 存储与网络:挂载数据卷、配置网络接口(通常委托给 CNI 插件)。
1.2 OCI 规范简介
Open Container Initiative(OCI)是 Linux 基金会旗下的开放标准组织,旨在制定容器格式和运行时的通用规范。OCI 目前维护三个核心规范:
| 规范名称 | 版本 | 核心内容 |
|---|---|---|
| OCI Image Spec | v1.1 | 定义镜像的索引、清单、层、配置的 JSON 结构与哈希验证方式 |
| OCI Runtime Spec | v1.1 | 定义容器运行时必须遵循的 config.json 格式、生命周期钩子、文件系统挂载标准 |
| OCI Distribution Spec | v1.1 | 定义镜像仓库的推送、拉取、标签、删除等 HTTP API 协议 |
OCI 规范的出现终结了早期容器生态的碎片化。任何符合 OCI Runtime Spec 的运行时(如 runc、crun、youki)都可以运行由任何符合 OCI Image Spec 的工具(如 BuildKit、Kaniko)构建的镜像。这种“一次构建,到处运行”的标准化能力是容器生态繁荣的基石。
1.3 runc 与 containerd 的关系
runc 和 containerd 是容器运行时生态中两个不同层次的组件,它们的分工常被混淆。下面这张架构图清晰展示了二者的定位:
runc 是 OCI Runtime Spec 的参考实现,由 Docker 公司捐赠给 OCI 社区。它是一个轻量级的 CLI 工具,功能单一:读取 config.json 和 rootfs,通过 clone 系统调用创建容器进程,然后退出。runc 本身不管理镜像、不处理网络、不维护持久化状态。
containerd 则是一个工业级的守护进程,最初从 Docker Engine 中拆分出来,现已成为 CNCF 毕业项目。containerd 在 runc 之上提供了完整的控制面能力:
- CRI 实现:实现了 Kubernetes CRI gRPC 接口,可以直接被 kubelet 调用。
- 镜像管理:支持 OCI 镜像的拉取、存储、挂载,内置内容寻址存储(CAS)。
- 快照器:管理容器文件系统的 overlayfs 快照链。
- 任务管理:通过 shim 进程(containerd-shim-runc-v2)隔离容器进程与 containerd 守护进程的生命周期。
1.4 容器运行时分类:低级与高级
根据功能边界和抽象层级,容器运行时通常分为两大类:
| 类别 | 代表实现 | 核心职责 | 是否直接操作内核 | 是否管理镜像 |
|---|---|---|---|---|
| 低级运行时 | runc, crun, youki, gVisor (部分) | 创建容器进程、配置 cgroups/namespace、执行 mount | 是 | 否 |
| 高级运行时 | containerd, CRI-O, Docker Engine | 镜像管理、CRI 接口、存储编排、shim 生命周期 | 否(委托给低级运行时) | 是 |
低级运行时直接与内核交互,负责“跑起一个进程并隔离它”。高级运行时则提供更上层的编排能力,它们通常调用低级运行时来完成实际的容器创建。这种分层设计使得 Kubernetes 可以灵活切换底层运行时——例如从 runc 切换到 gVisor 或 Kata Containers 来增强安全隔离,而无需修改上层编排逻辑。
下面这张图展示了高级运行时与低级运行时在 Kubernetes 节点上的协作关系:
从架构图中可以清晰看到:高级运行时(containerd)负责与编排系统对接、管理镜像和元数据;低级运行时(runc)专注于执行容器进程;中间的 shim 进程则起到解耦作用——即使 containerd 守护进程重启,已运行的容器也不会受到影响。