容器生态概念全景:从 nerdctl 到 Dragonfly,一篇理清所有关系
1. 为什么需要理清这些概念
容器生态在过去十年中经历了爆炸式增长。从最初的 Docker 一家独大,到如今围绕 OCI(Open Container Initiative)标准形成的多元化工具链——仅仅"运行一个容器"这件事,背后就涉及低级运行时、高级运行时、沙箱运行时、构建工具、分发系统等多个层次的不同项目。
如果你之前读过本博客的另一篇文章《Docker 引擎架构:理解 Docker、Moby、containerd 和 runc 之间的关系》,应该已经对 dockerd → containerd → runc 这条核心调用链有了清晰认识。本文作为姊妹篇,将视野从 Docker 内部扩展到整个云原生容器生态,逐一厘清 nerdctl、cri-o、crun、kata、gVisor、KubeVirt、buildkit/buildx、Dragonfly、unregistry 以及 distribution/distribution 这些概念的定位与关系。
阅读建议:如果你对
containerd、runc、dockerd的基础概念还不熟悉,建议先阅读上文中链接的 Docker 引擎架构文章,再回到本文继续。
2. 容器运行时分层模型
在讨论具体项目之前,必须先理解容器运行时的分层架构。OCI 标准将"运行容器"这件事拆成了两个层级:
高级运行时负责镜像管理(拉取、解压、存储)、容器生命周期管理(创建、启动、停止)、网络与存储接口。它暴露 gRPC API,典型代表是 containerd 和 cri-o。
低级运行时负责实际操作 Linux 内核特性(命名空间、cgroups、安全策略)来创建和运行容器进程。它遵循 OCI 运行时规范,典型代表是 runc 和 crun。
二者的关系用一句话概括:高级运行时管理"要做什么",低级运行时执行"怎么做"。
2.1 低级运行时:runc 与 crun
runc 是 OCI 运行时规范的参考实现,用 Go 语言编写。它诞生于 2015 年,由 Docker 公司将内部的 libcontainer 库改造为独立工具并捐赠给 OCI。runc 的职责非常纯粹——接收 OCI bundle(包含 rootfs 和 config.json),创建 Linux 命名空间、设置 cgroups、挂载文件系统,然后启动容器进程。正如前文 Docker 引擎架构文章所述,你在执行 docker run 时,调用链末端的实际执行者就是 runc。
crun 是 Red Hat 主导开发的 OCI 运行时,用 C 语言编写。它的设计目标与 runc 完全一致(遵循同一 OCI 规范),但提供了更好的内存效率和更快的启动速度。crun 支持 cgroup v2,并且对 user_namespaces 有更完善的支持。在 Red Hat 的生态中(如 Podman、CRI-O),crun 常作为默认的 OCI 运行时。
| 特性 | runc | crun |
|---|---|---|
| 语言 | Go | C |
| 维护方 | OCI / CNCF 社区 | Red Hat |
| OCI 规范兼容 | 参考实现 | 完全兼容 |
| 内存占用 | 较高 | 较低 |
| 默认使用场景 | containerd / Docker | CRI-O / Podman |
对绝大多数用户来说,runc 和 crun 在使用上几乎无感知差异——它们做的事情完全相同,都是 OCI 运行时的"可替换零件"。
2.2 高级运行时:containerd 与 CRI-O
containerd 在前文 Docker 引擎架构文章中有详尽介绍。它的核心能力包括镜像传输与存储、容器执行与监控、快照管理。containerd 暴露 gRPC API,被 Docker(通过 moby 命名空间)和 Kubernetes(通过 k8s.io 命名空间)同时使用,也提供了 CRI 插件以对接 kubelet。containerd 是 CNCF 的毕业项目。
CRI-O(Container Runtime Interface - OCI)是专为 Kubernetes 设计的轻量级高级运行时。与 containerd 不同,CRI-O 的创建目标非常明确:只做 Kubernetes 需要的事情,不支持 Docker API,不提供镜像构建功能,不附带多余的抽象层。
CRI-O 的核心理念是"用系统工具做系统管理"——它将镜像存储委托给 containers/storage,将网络委托给 CNI 插件,将低级运行委托给 runc 或 crun。这种"单一职责"的设计使得 CRI-O 代码量更小、攻击面更窄。
containerd 和 CRI-O 的关键区别:
| 维度 | containerd | CRI-O |
|---|---|---|
| 设计目标 | 通用容器运行时 | 专为 Kubernetes 设计 |
| Docker API 兼容 | 间接(通过命名空间隔离) | 不支持 |
| 镜像仓库管理 | 内置 | 委托给 containers/image |
| 使用场景 | Docker / Kubernetes | 几乎仅用于 Kubernetes |
| 额外 CLI 生态 | ctr / nerdctl | crictl(CRI 标准工具) |
| 代码复杂度 | 较高 | 较低 |
选择建议:如果你运行纯 Kubernetes 集群且希望最小化攻击面,CRI-O 是合理选择;如果你需要一个既能对接 Kubernetes 也能用于本地开发的通用运行时,containerd 更合适。
2.3 containerd 的 CLI 生态:ctr、crictl 与 nerdctl
containerd 作为守护进程运行后,用户需要通过 CLI 工具与之交互。这里存在三个不同定位的工具,初学者很容易混淆。
ctr 是 containerd 项目自带的调试用 CLI。它功能简陋、不支持命名字段,主要用于 containerd 开发者的日常调试:
# 拉取镜像
ctr images pull docker.io/library/nginx:latest
# 运行容器(参数必须按顺序提供,非常不友好)
ctr run --rm -t docker.io/library/nginx:latest nginx-testcrictl 是 Kubernetes 社区维护的 CRI 兼容调试工具。它通过 CRI API 与任何兼容的高级运行时(containerd 或 CRI-O)交互,是 Kubernetes 节点上排查容器问题的标准工具:
# 列出 Pod(crictl 用的是 Kubernetes 的 Pod 概念)
crictl pods
# 列出容器
crictl ps -a
# 查看容器日志
crictl logs <container-id>nerdctl 是 containerd 的"类 Docker CLI"工具,由 containerd 社区维护。它的设计目标是:让习惯 docker 命令的用户无缝切换到 containerd。nerdctl 兼容 Docker Compose(nerdctl compose up),支持 rootless 模式,支持镜像签名与验证,支持多种网络驱动。2025 年,nerdctl 已成为 containerd 生态中推荐的首选 CLI:
# 运行容器——几乎和 docker 命令一模一样
nerdctl run -d --name web -p 8080:80 nginx:latest
# 构建镜像(背后调用 BuildKit)
nerdctl build -t myapp:latest .
# Compose 多容器编排
nerdctl compose up -d
# Rootless 模式
nerdctl run --rm -it alpine记忆口诀:
ctr是 containerd 的"调试螺丝刀",crictl是 Kubernetes 的"诊断工具",nerdctl是 containerd 的"通用用户界面"。
3. 沙箱化与虚拟化运行时
前面介绍的 runc 和 crun 都是"进程级隔离"的低级运行时——容器进程与宿主机共享同一个 Linux 内核。这种方式性能极佳,但隔离性较弱:一旦内核出现漏洞,容器就可能逃逸到宿主机。
沙箱化运行时(Sandboxed Runtime)通过在容器外层增加额外的隔离层来解决这个问题。它们同样遵循 OCI 运行时规范,可以被 containerd 或 CRI-O 作为 drop-in 替代品使用。
3.1 Kata Containers
Kata Containers 是 Intel 和 Hyper 公司于 2017 年联合发起的项目,现已捐给 OpenInfra 基金会。它的核心思想是:每个容器运行在独立的轻量级虚拟机中,拥有自己的精简内核。这提供了硬件级别的隔离强度,同时保持了容器的操作体验。
Kata 的架构原理如下:
Kata 支持多种虚拟机监控器(VMM):QEMU(默认)、Cloud Hypervisor、Firecracker。Kata 3.0 之后,社区已将运行时核心重写为 Rust,称为 kata-runtime-rs,大幅降低了内存开销。Kata 是"安全容器"领域最高级的实现,广泛应用于多租户公有云和金融场景。
3.2 gVisor(runsc)
gVisor 是 Google 开发的用户态内核方案,用于 Google Cloud Run、GKE Sandbox 等产品。与 Kata 不同,gVisor 并不启动真正的虚拟机,而是在用户态实现了一个由 Go 语言编写的"应用内核"——sentry。
runsc 是 gVisor 提供的 OCI 兼容运行时。当你用 runsc 运行容器时:
- 容器的系统调用被拦截,不直接发给宿主内核;
- 系统调用由 Sentry(用户态内核)处理;
- Sentry 仅将少量可控的系统调用转发给宿主内核。
gVisor 的优势在于启动速度比虚拟机快(无需启动 Guest 内核),兼容性比传统容器好(自带网络栈实现)。缺点是某些系统调用(如部分 io_uring 操作)不被支持,兼容性不如 Kata 的完整内核。
3.3 KubeVirt
KubeVirt 的定位与前两者有本质不同。Kata 和 gVisor 的核心目标都是"让容器更安全",而 KubeVirt 的核心目标是"在 Kubernetes 上运行传统虚拟机"。
KubeVirt 不是 OCI 运行时——你不能用 --runtime=kubevirt 来运行容器。它是一个 Kubernetes 扩展(通过 CRD 和自定义控制器),为集群添加了管理虚拟机的能力:
# KubeVirt 定义的 VirtualMachine 资源
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: my-vm
spec:
running: true
template:
spec:
domain:
devices:
disks:
- name: containerdisk
disk: {}
resources:
requests:
memory: 2Gi
volumes:
- name: containerdisk
containerDisk:
image: quay.io/containerdisks/centos:9KubeVirt 使用 KVM 和 QEMU 虚拟化技术,每个 VM 的磁盘、网络、配置全部通过 Kubernetes 原生 API 管理。它最适合以下场景:
- 需要在同一集群中同时管理容器和传统 VM 工作负载
- 需要迁移遗留应用而暂时无法容器化
- 需要比容器更强的隔离性,但不想脱离 Kubernetes 运维体系
区分要点:Kata 让容器像 VM 一样安全,KubeVirt 让 VM 像容器一样管理。二者解决的是不同问题。
3.4 沙箱运行时对比总结
| 方案 | 隔离方式 | 启动速度 | 兼容性 | 适用场景 |
|---|---|---|---|---|
| runc / crun | 进程级(共享内核) | 极快 | 最好 | 普通容器 |
| gVisor (runsc) | 用户态内核 | 快 | 较高 | 无服务器 / 轻量安全 |
| Kata Containers | 轻量 VM | 较慢 | 完整 | 多租户 / 金融级安全 |
| KubeVirt | 完整 KVM VM | 慢 | 完整(VM) | 传统 VM 迁移到 K8s |
这四种方案可以共存于同一个 Kubernetes 集群中,通过 RuntimeClass 资源按需选择:
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: kata
handler: kata
---
apiVersion: v1
kind: Pod
spec:
runtimeClassName: kata # 指定使用 Kata 运行时
containers:
- name: secure-app
image: myapp:latest4. 镜像构建现代化:BuildKit 与 buildx
4.1 BuildKit
BuildKit 是 Moby 项目下的下一代镜像构建引擎,由 Docker 社区和 Tõnis Tiigi 于 2017 年发起。相较于旧版 docker build,BuildKit 带来了质的飞跃:
- 并行构建:无依赖关系的构建阶段可以同时执行;
- 增量构建与高效缓存:支持多种缓存后端(本地、registry、S3、GitHub Actions cache);
- 构建秘钥管理:
--secret参数允许在构建时安全传递敏感信息而不写入镜像层; - 多架构构建:原生支持 manifest list 和跨平台构建;
- 非 Dockerfile 前端:BuildKit 支持自定义构建语法,如 Mockerfile、Earthly 等。
BuildKit 作为一个独立守护进程运行(buildkitd),可以通过 gRPC 接收构建请求。containerd 也可以直接对接 BuildKit 实现 nerdctl build。
4.2 buildx
buildx 是 Docker CLI 的一个插件,本质上是 BuildKit 的"用户界面"。它把 BuildKit 的强大能力以 docker build 兼容的语法暴露给用户。
buildx 最具价值的功能是跨平台镜像构建。传统的 docker build 只能构建与宿主机相同架构的镜像,而 docker buildx build --platform linux/amd64,linux/arm64 可以使用 QEMU 模拟或通过远程原生节点,一次性构建多个架构的镜像并合并成一个 manifest list:
# 创建多架构构建器
docker buildx create --name mybuilder --use
# 构建并推送 linux/amd64 和 linux/arm64 镜像
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag myregistry/myapp:latest \
--push .一句话关系:
buildx是 Docker CLI 插件,负责把用户的docker buildx build命令翻译成 BuildKit 的 gRPC 请求;buildkitd是实际干活的那个。
5. 容器镜像分发生态
镜像构建完成后,需要通过分发系统在网络中传输。这是容器生态中容易忽视但至关重要的环节。
5.1 CNCF Distribution(distribution/distribution)
https://github.com/distribution/distribution 是 CNCF 的孵化项目,前身为 Docker Registry v2。它是大多数容器镜像仓库的核心实现——Docker Hub、Harbor、阿里云 ACR、腾讯云 TCR 等公开和私有镜像仓库的底层都是它或其 fork。
Distribution 提供标准的 OCI 分发 API(符合 OCI Distribution Spec),支持:
- 镜像推送(push)和拉取(pull);
- 层去重和垃圾回收;
- 多种存储后端(本地文件系统、S3、GCS、Azure Blob 等);
- 访问控制和认证(通过委托给代理或中间件)。
在生产环境中,Distribution 通常不单独部署,而是嵌入到更完整的镜像仓库产品中(如 Harbor 在 Distribution 外层添加了漏洞扫描、签名验证、RBAC 等)。但如果你只需要一个轻量级的私有镜像仓库,运行一个 Distribution 实例就是最简单的选择:
docker run -d -p 5000:5000 --name registry registry:25.2 Dragonfly:P2P 镜像分发加速
Dragonfly(原名 Dragonfly)是阿里云开源的 P2P 文件与镜像分发系统,CNCF 孵化项目。在拥有数万台节点的大型 Kubernetes 集群中,成百上千个节点同时从中心仓库拉取镜像会造成严重的网络拥塞(即"网络打桩"问题)。Dragonfly 通过 P2P 协议解决这个问题:
Dragonfly 的核心组件包括:
- Manager(v2):管理 P2P 集群,调度下载任务;
- Scheduler:决策哪些 peer 之间互相传输数据;
- Seed Peer:作为集群内的"种子节点",直接从源仓库拉取镜像;
- Peer:部署在每个需要拉取镜像的节点上的客户端(
dfdaemon),拦截 containerd 或 Docker 的镜像拉取请求并转为 P2P 下载。
Dragonfly 的优势在大规模集群中尤为显著:当 1000 个节点同时需要拉取 10GB 的 AI 推理镜像时,传统方式下 registry 的出带宽会被打满,而 P2P 方式下每个节点从周围的 peer 获取数据,registry 只需提供一份完整拷贝给种子节点。
值得一提的是,Dragonfly 2.0 从 Go 语言重写,架构大幅简化,已去除对 Redis 和 MySQL 的外部依赖,部署门槛显著降低。
5.3 unregistry:内存级 OCI 分发
https://github.com/psviderski/unregistry 是一个极简的 OCI 分发规范实现,它的核心特性是完全运行在内存中——没有持久化存储,不依赖外部数据库,重启即清空。
unregistry 的设计定位是"分发系统的最后一块拼图"——它实现了 CNCF Distribution 的核心 API(push、pull、discover),但将所有代码压缩到单文件,使其成为 OCI 分发生态中的参考实现和研究工具。
它的使用场景非常独特:
- 集成测试:在 CI 中快速启动一个 OCI registry 作为测试桩(无需持久化,免清理);
- 教学演示:用最少的代码展示 OCI 分发规范的实现原理;
- 本地临时中转:在开发和调试过程中临时存放镜像,用完即弃。
# 用 Python 快速启动 unregistry(在内存中运行)
uvx unregistry --port 5000
# 推送镜像(和标准 registry 操作完全一致)
docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latestunregistry 约 400 行 Python 代码,可作为学习 OCI 分发规范 API 实现的最佳起点。
三者关系:
distribution/distribution是生产级实现,Dragonfly是 P2P 加速层,unregistry是教学与测试用的最小实现。它们分别代表了容器镜像分发生态的核心、网络优化与理解学习三个维度。
6. 全景关系图与总结
6.1 全景架构
将上述所有概念放在一张图中,可以看到完整的容器生态分层关系:
6.2 速记参考表
| 概念 | 一句话定位 | 关键关联 |
|---|---|---|
| dockerd | Docker 守护进程,容器平台入口 | 内部调用 containerd |
| containerd | CNCF 毕业高级运行时 | Kubernetes 和 Docker 的共同基础 |
| runc | OCI 低级运行时参考实现 | containerd 的默认执行器 |
| crun | C 语言 OCI 低级运行时 | Red Hat 生态默认,内存更省 |
| cri-o | 专为 K8s 设计的高级运行时 | 只做 K8s 需要的,更轻更小 |
| nerdctl | containerd 的"类 Docker"CLI | 支持 Compose、rootless、镜像签名 |
| buildkit | 下一代镜像构建引擎 | 并行构建、多架构、缓存 |
| buildx | Docker CLI 的构建插件 | 是 BuildKit 的用户界面 |
| kata | VM 级安全容器运行时 | 每个容器独享精简内核 |
| gVisor / runsc | 用户态内核安全运行时 | Google Cloud Run 的底层 |
| KubeVirt | K8s 上运行传统 VM | 不是 OCI 运行时,是 K8s 扩展 |
| distribution | 标准容器镜像仓库实现 | 原 Docker Registry v2,CNCF 项目 |
| Dragonfly | P2P 镜像分发加速 | 大规模集群避免网络拥塞 |
| unregistry | 内存级 OCI Registry 最小实现 | 教学 / 测试 / 临时中转 |
6.3 总结
容器生态的多样性源于 OCI 标准的开放设计。当你理解了镜像规范定义了镜像格式,运行时规范定义了容器执行接口,分发规范定义了镜像传输协议——你就能明白为什么有这么多不同的项目,因为它们各司其职、可互换组合。
选择容器技术栈时,可以从以下维度做决策:
- 隔离性 vs 性能:普通业务用 runc/crun,多租户敏感业务用 Kata,Serverless 场景考虑 gVisor;
- 通用性 vs 专注性:通用使用 Docker/containerd,纯 K8s 环境用 CRI-O 更轻便;
- 规模考量:小集群直接用 registry,大集群(500+ 节点)引入 Dragonfly P2P 加速;
- 构建效率:多架构构建用 buildx,复杂构建流水线考虑直接对接 BuildKit API;
- 学习路径:理解规范层面可看 unregistry 的源码,生产环境用 distribution/distribution。
希望这篇文章能帮助你在面对纷繁的容器生态论文、选型和部署文档时,快速定位每个组件的坐标,做出合理的技术决策。
7. 参考文献
- OCI Distribution Specification — https://specs.opencontainers.org/distribution-spec/
- OCI Runtime Specification — https://specs.opencontainers.org/runtime-spec/
- OCI Image Specification — https://specs.opencontainers.org/image-spec/
- containerd — https://github.com/containerd/containerd
- nerdctl — https://github.com/containerd/nerdctl
- CRI-O — https://github.com/cri-o/cri-o
- crun — https://github.com/containers/crun
- Kata Containers — https://github.com/kata-containers/kata-containers
- gVisor — https://github.com/google/gvisor
- KubeVirt — https://github.com/kubevirt/kubevirt
- BuildKit — https://github.com/moby/buildkit
- buildx — https://github.com/docker/buildx
- Dragonfly — https://github.com/dragonflyoss/Dragonfly2
- CNCF Distribution — https://github.com/distribution/distribution
- unregistry — https://github.com/psviderski/unregistry
- Docker 引擎架构:理解 Docker、Moby、containerd 和 runc 之间的关系 — 本博客 2025-10 月文章