Docker、containerd、CRI、shim 之间的关系

Docker、docker-ce、containerd、CRI、CRI-O、shim 是啥关系?顺便把"以前那条链路"也讲透

聊容器运行时,最常见的困惑就是:

"我以前装个 Docker 就能跑容器,怎么现在 Kubernetes 又说 containerd,又说 CRI,还冒出个 shim?Docker 不是运行时吗?那 docker-ce 又是什么?CRI-O 又是哪路神仙?"

说白了,这不是谁取代谁,而是 K8s 把容器这摊事拆得更清楚了:上层只管提需求,中间用标准接口对接,底层专心把进程跑起来,再用 shim 把运行过程稳住。

你把"现在的链路"和"以前的链路"放一起看,就不会乱。

先把几条链路摆出来:一眼就懂它们在换什么

以前(K8s 早期常见,强绑定 Docker):
kubelet → dockershim → Docker Engine(dockerd) → containerd → runc → 容器进程

现在(K8s 主流之一:containerd 直接对接):
kubelet → CRI → containerd → shim → runc → 容器进程

现在(另一条主流:CRI-O 对接):
kubelet → CRI → CRI-O →(shim/OCI runtime)→ runc → 容器进程

看出来了吗?底层终点几乎都一样,都是 runc + 容器进程。变化主要在上层两件事:

  • 以前 kubelet 需要靠 dockershim 去"翻译"Docker 的接口。

  • 现在 kubelet 只认 CRI,至于底层是 containerd 还是 CRI-O,随你选(只要实现 CRI)。

Docker 和 docker-ce:一个是"概念/产品体系",一个是"你安装的发行版"

很多人把 Docker 当成一个单一组件,其实它更像一个产品集合:CLI、镜像构建、镜像分发、运行容器、网络、卷、日志、API......早期是一条龙,确实省心。

那 docker-ce 是什么?简单讲就是:

Docker 的社区版发行方式/安装包。

你在 Linux 上 yum install docker-ce / apt install docker-ce 装的那套,通常就包含:

  • docker CLI(你敲命令用的)

  • dockerd(Docker Engine)

  • 以及它依赖的一些底层组件(例如 containerd、runc 等)

所以 docker-ce 不是另一种运行时,而是 Docker 这个体系在社区版里怎么被打包交付。

Docker:以前像"一条龙",现在更像"上层工具箱"

Docker 最早为什么火?因为它把一堆事做成了一条龙:

  • build 镜像、pull/push 镜像

  • run 容器

  • 网络、卷、日志、API 都一起包好

体验当然好,但问题也很现实:太大、太全、太像一个产品。

Kubernetes 需要的是一个更"专注跑容器"的底层能力,而不是一个把所有功能都打包的巨无霸。

所以今天很多场景里 Docker 的定位更像:

开发和运维常用的容器工具箱。

在集群里真正负责跑容器的核心,往往不是"Docker 的大引擎",而是它下面的运行时组件(containerd/runc)。

containerd:专职"管理容器生命周期"的运行时核心

containerd 可以理解成:专心把容器跑起来,别的尽量少管。它负责的都是硬活:

  • 拉镜像、解压、管理 snapshot

  • 创建/启动/停止/删除容器

  • 调用更底层 runtime(比如 runc)把容器进程真正拉起来

  • 管理容器 I/O、状态等

所以你现在看到 Kubernetes 默认倾向 containerd,并不奇怪:它更轻、更专注、更符合"运行时组件"该有的样子。

CRI:Kubernetes 的"标准插槽",不是运行时

CRI(Container Runtime Interface)最容易被误解成某个程序,其实它是接口标准。

kubelet 为什么要 CRI?一句话:不想跟某一个运行时绑死。

如果 kubelet 直接适配 Docker、适配 containerd、适配 CRI-O......那 kubelet 的代码得多乱?维护成本得多高?

所以 Kubernetes 的做法是:

我 kubelet 只会说 CRI 这门语言,你们运行时自己来实现。

于是现在链路变得很干净:
kubelet → CRI →(containerd / CRI-O / 其他 runtime)

CRI-O:为 Kubernetes 而生的运行时实现(更"纯粹")

CRI-O 你可以理解成:

专门为 Kubernetes 设计的 CRI 运行时。

它不像 Docker 那样做镜像构建体验,也不像 Docker 那样带一堆平台功能。CRI-O 的目标非常明确:

  • 实现 CRI,让 kubelet 能用标准接口管理容器

  • 遵循 OCI,调用 runc 等 runtime 拉起容器进程

  • 尽量保持轻量、专注、贴合 K8s

"containerd 和 CRI-O 有啥区别?"

两者都能当 K8s 运行时,但 CRI-O 更像"为了 K8s 而定制的后端",而 containerd 更像"通用型运行时管理器"。

shim:为什么要有"垫片"?为了稳,不是为了多一层

shim 听起来像"中间商",但它解决的都是生产里非常实在的问题。

以 containerd 为例,一个容器通常会对应一个 shim(例如 containerd-shim-runc-v2)。它的价值主要在三点:

让容器不依赖 containerd 的生命周期

你真的希望 containerd 重启一下,所有容器跟着死吗?当然不希望。

shim 让容器进程可以继续跑,containerd 重启后再重新接管。

处理容器 I/O 和退出状态

stdout/stderr 谁接?容器退出后 exit code 谁收?状态怎么回报?

这些都需要一个"离容器很近、一直在线"的管家,shim 就干这个。

隔离底层 runtime 的细节

containerd 不必直接黏着 runc 的各种细节,通过 shim 隔离开,系统更稳,演进也更容易。

所以 shim 的存在,核心就是两个字:稳定。

以前那条链路:dockershim 到底是干嘛的?为什么后来不用了?

早期 Kubernetes 很依赖 Docker 生态,但 kubelet 需要一种方式驱动 Docker,于是有了 dockershim。

你可以把 dockershim 理解成:

kubelet 和 Docker Engine(dockerd) 之间的翻译官/胶水层。

它把 kubelet 的需求转成 Docker 能理解的调用方式,让 Kubernetes 能"用 Docker 跑 Pod"。

所以以前链路是:
kubelet → dockershim → dockerd → containerd → runc → 容器进程

有趣的是:很多人以为 Docker 直接跑容器,但 Docker Engine 下面早就有 containerd/runc。底层能力一直在那里,只是以前你不需要关心。

那为什么 dockershim 后来逐步退场?也很现实:

  • Kubernetes 不想和 Docker 的实现细节强绑定

  • 运行时生态更丰富了(containerd、CRI-O 等)

  • 需要统一标准(CRI)来降低维护成本、提升一致性

于是大家改走 CRI 标准化路线。

现在的链路:更标准、更可插拔,也更清爽

现在主流链路就是:

  • kubelet → CRI → containerd → shim → runc → 容器进程

  • kubelet → CRI → CRI-O →(shim/OCI runtime)→ runc → 容器进程

它带来的变化很直接:

  • kubelet 只对 CRI 负责,运行时更可插拔

  • containerd/CRI-O 专注运行时职责,边界更清晰

  • shim 把稳定性兜住,容器不怕 runtime 重启

  • 分层更清楚,排障也更容易定位

总而言之:把它们当成"分工明确的一条流水线"

  • Docker:容器工具箱/平台体验(开发运维常用)

  • docker-ce:Docker 的社区版发行包,你装的 Docker 通常就是它

  • CRI:kubelet 和运行时之间的标准接口(kubelet 只认它)

  • containerd:通用型运行时管理器(K8s 常用)

  • CRI-O:为 Kubernetes 定制的 CRI 运行时实现(更专注、更原生)

  • shim:容器的管家/垫片,让容器更稳、更独立

  • 最终都落到 runc + 容器进程:你的应用真正跑在这里

以前是 kubelet 通过 dockershim "绑"着 Docker 跑;现在是 kubelet 通过 CRI "插"上 containerd 或 CRI-O 跑。Docker/docker-ce 负责好用,containerd/CRI-O 负责执行,shim 负责稳定。

相关推荐
ulias2121 天前
Linux系统中的权限问题
linux·运维·服务器
青花瓷1 天前
Ubuntu下OpenClaw的安装(豆包火山API版)
运维·服务器·ubuntu
问简1 天前
docker 镜像相关
运维·docker·容器
Dream of maid1 天前
Linux(下)
linux·运维·服务器
齐鲁大虾1 天前
统信系统UOS常用命令集
linux·运维·服务器
Benszen1 天前
Docker容器化技术实战指南
运维·docker·容器
ZzzZZzzzZZZzzzz…1 天前
Nginx 平滑升级:从 1.26.3 到 1.28.0,用户无感知
linux·运维·nginx·平滑升级·nginx1.26.3·nginx1.28.0
lin_dec+1 天前
Serverless:零成本按需计算的未来
云原生·serverless
Hommy881 天前
【开源剪映小助手】Docker 部署
docker·容器·开源·github·aigc
一叶知秋yyds1 天前
Ubuntu 虚拟机安装 OpenClaw 完整流程
linux·运维·ubuntu·openclaw