【kubernetes - 1.28版本】-4 containerd与docker-ce 的区别

文章目录

  • [containerd 与 docker-ce 的区别](#containerd 与 docker-ce 的区别)
    • 核心结论
    • 本文路线
    • 一、先建立正确的整体认知
      • [1. 两种接入链路](#1. 两种接入链路)
      • [2. 各组件职责](#2. 各组件职责)
      • [3. 三个容易搞错的地方](#3. 三个容易搞错的地方)
    • [二、Kubernetes 1.24 之前:两条路线并行](#二、Kubernetes 1.24 之前:两条路线并行)
      • [1. 路线 A:Docker Engine + 内置 dockershim](#1. 路线 A:Docker Engine + 内置 dockershim)
      • [2. 路线 B:独立 containerd + CRI](#2. 路线 B:独立 containerd + CRI)
      • [3. 两条路线对比](#3. 两条路线对比)
    • [三、Kubernetes 1.24 --- 1.28:核心变化是 dockershim 被移除](#三、Kubernetes 1.24 — 1.28:核心变化是 dockershim 被移除)
      • [1. 路线 A:containerd + kubeadm(推荐学习)](#1. 路线 A:containerd + kubeadm(推荐学习))
        • [第一步:安装并检查 containerd](#第一步:安装并检查 containerd)
        • [第二步:配置 containerd](#第二步:配置 containerd)
        • [第三步:安装 Kubernetes 组件并初始化](#第三步:安装 Kubernetes 组件并初始化)
      • [2. 路线 B:Docker Engine + cri-dockerd](#2. 路线 B:Docker Engine + cri-dockerd)
      • [3. 1.24 到 1.28 之间还要注意什么](#3. 1.24 到 1.28 之间还要注意什么)
    • [四、Kubernetes 1.28 之后:判断标准回到 CRI 兼容性](#四、Kubernetes 1.28 之后:判断标准回到 CRI 兼容性)
      • [1. cgroup 驱动自动检测](#1. cgroup 驱动自动检测)
      • [2. containerd 1.x 与 2.x 的配置差异](#2. containerd 1.x 与 2.x 的配置差异)
      • [3. 别忽略 CRI 插件状态](#3. 别忽略 CRI 插件状态)
    • 五、三个阶段放在一起比较
    • [六、从安装到运行 Pod:两条路线的动作差异](#六、从安装到运行 Pod:两条路线的动作差异)
      • [方案 A:独立 containerd](#方案 A:独立 containerd)
      • [方案 B:Docker Engine + cri-dockerd](#方案 B:Docker Engine + cri-dockerd)
    • 参考资料

containerd 与 docker-ce 的区别

本文回答 Kubernetes 运维面试里的经典问题:为什么早期 Kubernetes 可以直接把 Docker 当作容器运行时,而 1.24 之后很多教程却要求安装 containerd?

核心结论

  • 不是二选一。 Docker Engine 内部本来就使用 containerd 管理容器生命周期,两者处于不同抽象层级。
  • 1.24 是分界线。 早期 kubelet 通过内置的 dockershim 兼容 Docker Engine;1.24 起 dockershim 被移除,kubelet 不能再把 Docker Engine 直接当作运行时。
  • 想继续用 Docker 也可以。 需要额外安装适配器 cri-dockerd;更直接的方式是让 kubelet 通过 CRI 接口连接 containerd。
  • 1.28 不是分界线。 官方在 1.20 宣布弃用 dockershim,1.24 正式移除;1.28 前后的变化更多属于运行时兼容机制、版本支持与部署细节的演进。

本文路线

阶段 关注点
Kubernetes 1.24 之前 Docker Engine 与 containerd 都可以接入,区别在控制链路
Kubernetes 1.24 --- 1.28 dockershim 移除后,两条主流路线分别怎么部署
Kubernetes 1.28 之后 cgroup 驱动自动检测、CRI 版本兼容、containerd 1.x/2.x 配置差异

最后附三阶段对照表、部署动作对照与面试问题清单。


一、先建立正确的整体认知

1. 两种接入链路

Docker Engine 方案

text 复制代码
kubelet
   │
   │ CRI
   ▼
cri-dockerd(适配器)
   │
   ▼
Docker Engine / dockerd
   │
   ▼
containerd → runc → Linux 容器

containerd 方案

text 复制代码
kubelet
   │
   │ CRI
   ▼
containerd(CRI 插件)
   │
   ▼
runc → Linux 容器

2. 各组件职责

组件 职责
Docker Engine 面向用户的容器管理系统,提供 docker 命令、Docker API、镜像构建、网络、卷等功能
containerd 容器运行时组件,负责镜像传输与管理、容器生命周期
runc 更底层的 OCI 运行时,按 OCI 规范创建和运行容器进程
CRI Kubernetes 的容器运行时接口,规定 kubelet 如何与容器运行时通信
dockershim / cri-dockerd 适配层,让不直接实现 CRI 的 Docker Engine 能够接入 kubelet

关键点:Docker Engine 内部本来就使用 containerd。所以从 Docker 方案迁移到 containerd 方案,不是把 Docker 容器换成另一种容器格式,而是改变 Kubernetes 管理容器时所走的控制链路。

!\[03_云原生/云原生技术栈/Kubernetes/image/dff28e2de498ef6a0822deea958e115e_MD5.png]

3. 三个容易搞错的地方

① 装了 Docker,不等于 Kubernetes 通过 Docker Engine 管理 Pod。

例如在 Ubuntu 上执行:

bash 复制代码
docker build -t myapp:v1 .
docker push myregistry.example.com/myapp:v1

这只是用 Docker 构建、推送镜像。即使 Kubernetes 节点只装了 containerd,也完全能运行这个镜像------因为它们使用通用的 OCI 镜像格式。

② 装了 containerd,不等于可以直接用 docker ps。

containerd 常用 ctr、crictl 等工具,而不是 Docker CLI。

③ 表里的 socket 路径与 kubelet 参数都是历史实现。

不要把旧版本的参数原样复制到新版本集群。


二、Kubernetes 1.24 之前:两条路线并行

这个阶段要区分两条路线,而不是认为当时只有 Docker。

1. 路线 A:Docker Engine + 内置 dockershim

早期 Kubernetes 直接集成了一个名为 dockershim 的适配组件,kubelet 借助它调用 Docker Engine,Docker Engine 再通过自身内部的 containerd 等组件运行容器。

典型调用链

text 复制代码
kubelet
   │
   ▼
内置 dockershim
   │
   ▼
Docker Engine(dockerd)
   │
   ▼
containerd → runc

典型部署过程

  1. 在所有节点安装 Docker Engine。
  2. 在所有节点安装 kubelet、kubeadm、kubectl。
  3. 配置 Docker 与 kubelet 的 cgroup 驱动一致。
  4. 通过 kubeadm 初始化控制平面。
  5. 工作节点加入集群。
  6. 安装 CNI 网络插件。
  7. 验证 Pod 能否正常运行。

以上为历史版本示例,具体命令取决于系统和版本:

bash 复制代码
docker --version
systemctl status docker

# 仅适用于相应版本、相应配置的历史部署流程
kubeadm init --pod-network-cidr=<你的Pod网段>

重要区别:不需要因为 Docker 内部已经包含 containerd,就再给 Kubernetes 配置一个独立的 containerd 服务。在这条旧路线里,kubelet 走的是 dockershim → Docker Engine,而不是直接连接独立 containerd 的 CRI 接口。

!\[03_云原生/云原生技术栈/Kubernetes/image/dff28e2de498ef6a0822deea958e115e_MD5.png]

2. 路线 B:独立 containerd + CRI

即使在 1.24 之前,也可以直接使用 containerd。

text 复制代码
kubelet
   │
   │ CRI
   ▼
containerd 的 CRI 插件
   │
   ▼
runc
   │
   ▼
Linux 容器

部署步骤与 Docker 路线类似,但运行时安装和配置不同:

  1. 安装 containerd。
  2. 确认 CRI 插件可用。
  3. 配置 containerd 的 cgroup 驱动。
  4. 安装 kubeadm、kubelet、kubectl。
  5. 指定 containerd 的 CRI socket 初始化集群。
  6. 安装 CNI 插件并验证 Pod。

containerd 1.x 常见的 CRI socket:

text 复制代码
/run/containerd/containerd.sock

使用 kubeadm 时明确指定:

bash 复制代码
kubeadm init \
  --cri-socket unix:///run/containerd/containerd.sock \
  --pod-network-cidr=<你的Pod网段>

在旧版本 kubeadm 中,运行时检测行为与配置要求可能有差异,显式指定 socket 有助于避免检测到多个运行时后产生歧义。

3. 两条路线对比

对比项 Docker Engine + dockershim 独立 containerd
Kubernetes 接入方式 通过内置 dockershim 通过 CRI 插件
kubelet 连接对象 Docker 适配链路 containerd CRI socket
是否需要安装 Docker Engine 需要 不需要
是否需要独立安装 containerd 通常不需要另外安装 需要
常用容器管理工具 docker crictl、ctr
典型 socket 旧版 dockershim socket /run/containerd/containerd.sock
能否运行 OCI 镜像 能 能

三、Kubernetes 1.24 --- 1.28:核心变化是 dockershim 被移除

从 1.24 开始,变化不在于 Docker 不能运行容器 ,而在于 Kubernetes 不再自带连接 Docker Engine 的 dockershim。此后有两条主流路线。

!\[03_云原生/云原生技术栈/Kubernetes/image/dff28e2de498ef6a0822deea958e115e_MD5.png]

1. 路线 A:containerd + kubeadm(推荐学习)

节点上只需要两个关键组件:kubelet 与 containerd,kubelet 通过 CRI 连接 containerd 的 CRI 插件。以下以 Ubuntu 22.04 为例。

第一步:安装并检查 containerd
bash 复制代码
sudo apt update
sudo apt install -y containerd

# 启动并查看服务状态
sudo systemctl enable --now containerd
sudo systemctl status containerd

检查 CRI 是否正常(crictl 需另外安装):

bash 复制代码
sudo crictl \
  --runtime-endpoint unix:///run/containerd/containerd.sock \
  info

crictl info 能成功返回运行时信息,比只看到 containerd 服务处于 active 更能证明 CRI 接口可用。

第二步:配置 containerd

先备份配置,再生成默认配置:

bash 复制代码
sudo mkdir -p /etc/containerd

sudo cp /etc/containerd/config.toml \
  /etc/containerd/config.toml.bak 2>/dev/null || true

sudo containerd config default |
  sudo tee /etc/containerd/config.toml >/dev/null

对于 containerd 1.x,确认以下配置为 true:

toml 复制代码
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true

改完重启服务:

bash 复制代码
sudo systemctl restart containerd

两个坑

  1. containerd config default 会覆盖原有配置文件内容,生产环境不能无条件直接执行。
  2. containerd 2.x 的配置段名称不同,不能照抄 1.x 的配置路径(见第四章第 2 节)。

!\[03_云原生/云原生技术栈/Kubernetes/image/dff28e2de498ef6a0822deea958e115e_MD5.png]

第三步:安装 Kubernetes 组件并初始化

在所有节点安装匹配版本的 kubeadm、kubelet、kubectl,然后在控制平面节点执行:

bash 复制代码
sudo kubeadm init \
  --cri-socket unix:///run/containerd/containerd.sock \
  --pod-network-cidr=<你的Pod网段>

上面是命令模板,Pod 网段必须与所选 CNI 插件的配置一致。工作节点使用初始化输出中的 kubeadm join 命令加入集群。

2. 路线 B:Docker Engine + cri-dockerd

如果希望继续用 Docker Engine 管理 Kubernetes Pod,也可以做到,但要额外安装适配器 cri-dockerd。

调用链变为:

text 复制代码
kubelet
   │
   │ CRI
   ▼
cri-dockerd
   │
   ▼
Docker Engine
   │
   ▼
Docker 内部的 containerd → runc

额外部署步骤

  1. 安装 Docker Engine。
  2. 安装并启动 cri-dockerd。
  3. 确认 cri-dockerd 的 socket。
  4. 安装 kubeadm、kubelet、kubectl。
  5. 初始化集群时显式指定 cri-dockerd socket。
  6. 检查 Docker、cri-dockerd、kubelet 的状态和日志。

常见的 Linux socket:

text 复制代码
unix:///run/cri-dockerd.sock

初始化时指定:

bash 复制代码
sudo kubeadm init \
  --cri-socket unix:///run/cri-dockerd.sock \
  --pod-network-cidr=<你的Pod网段>

具体 socket 路径取决于 cri-dockerd 的安装方式和服务配置,部署前应检查实际值。

为什么不直接用 Docker? 因为 Docker Engine 并不原生实现 Kubernetes 所需的 CRI 接口,cri-dockerd 负责把 kubelet 的 CRI 请求转换为 Docker Engine 能处理的操作。

!\[03_云原生/云原生技术栈/Kubernetes/image/dff28e2de498ef6a0822deea958e115e_MD5.png]

因此,Kubernetes 1.24 以后:

操作 是否仍然可行
docker build 构建镜像 ✅ 可以
docker push 推送镜像 ✅ 可以
Docker Engine 运行普通容器 ✅ 可以
kubelet 依靠内置 dockershim 直接连接 Docker Engine ❌ 不可以
由 Docker Engine 管理 Kubernetes Pod ⚠️ 需要额外安装 cri-dockerd

3. 1.24 到 1.28 之间还要注意什么

Kubernetes 版本 关键变化或注意事项
1.24 移除内置 dockershim;Docker Engine 路线需要 cri-dockerd,或改用其他 CRI 运行时
1.25 延续上述规则;仍要注意旧运行时的 CRI API 兼容性
1.26 kubelet 要求运行时支持 CRI v1 API;不支持该 API 的运行时无法正常完成注册
1.27 Docker 与 containerd 的接入路线没有因该版本发生根本变化
1.28 引入 cgroup 驱动自动检测的 Alpha 特性,但不代表默认自动检测,也不代表 Docker 从此不能使用

1.26 是额外的兼容性节点 :官方文档明确指出,1.26 及之后的 kubelet 要求容器运行时支持 CRI v1 API。

对 containerd 而言,不能只看大版本号。例如 1.5、1.6、1.7 的 CRI 支持情况存在差异。搭建 1.26---1.28 集群时,应选择明确支持 CRI v1 的兼容版本,而不是随意安装旧教程里的包。


四、Kubernetes 1.28 之后:判断标准回到 CRI 兼容性

先纠正一个常见误解:1.28 之后并没有把 containerd 变成唯一可用运行时,也没有彻底禁止 Docker Engine。

真正的判断标准仍然是:运行时能否通过 Kubernetes 要求的 CRI 接口工作,以及它与当前 Kubernetes 版本是否兼容。

1. cgroup 驱动自动检测

早期部署教程通常要求手动把 kubelet 和 containerd 的 cgroup 驱动设为一致的值(例如 systemd),原因是 Linux 用 cgroup 管理容器的 CPU、内存等资源,而常见的两种驱动语义不同:

驱动 含义
systemd 由 systemd 管理 cgroup 层级
cgroupfs 运行时直接通过 cgroup 文件系统管理层级

如果 kubelet 用 systemd 而运行时用 cgroupfs,就可能产生资源管理方面的问题,因此在 kubeadm 集群中通常建议两边都使用 systemd。

1.28 引入的自动检测属于 Alpha 阶段能力,需要相应的特性门控配置。不能因为版本号到了 1.28,就认为已经自动完成检测。

对学习用集群,最稳妥的做法仍是显式配置:

toml 复制代码
# containerd 1.x
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true

并确保 kubelet 也使用 systemd 驱动。

!\[03_云原生/云原生技术栈/Kubernetes/image/dff28e2de498ef6a0822deea958e115e_MD5.png]

2. containerd 1.x 与 2.x 的配置差异

如果看到两份教程,一份配置正常、另一份却提示找不到配置项,很可能是因为它们用了不同的大版本。

配置项 containerd 1.x containerd 2.x
CRI 插件配置段 io.containerd.grpc.v1.cri 运行时与镜像配置拆分为新的插件命名空间
常见运行时配置段 plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options
cgroup 配置 SystemdCgroup = true 同样需要 SystemdCgroup = true
能否照搬旧配置 仅适用于对应的 1.x 版本 不建议照搬 1.x 的完整配置

2.x 的写法:

toml 复制代码
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
  SystemdCgroup = true

这并不是说 1.28 强制要求 containerd 2.x,而是提醒:Kubernetes 版本与 containerd 版本是两个独立的版本维度,配置必须匹配实际安装的 containerd。

!\[03_云原生/云原生技术栈/Kubernetes/image/dff28e2de498ef6a0822deea958e115e_MD5.png]

3. 别忽略 CRI 插件状态

有时 containerd 服务正常,但 kubeadm init 仍然失败,这时需要检查 CRI 插件是否启用:

bash 复制代码
sudo ctr plugins ls | grep -i cri

如果插件状态异常,继续查看配置:

bash 复制代码
grep -n -A5 -B2 'disabled_plugins' /etc/containerd/config.toml

若 cri 被写进 disabled_plugins 列表,containerd 就无法提供 Kubernetes 所需的 CRI 服务。修正后重启并复查:

bash 复制代码
sudo systemctl restart containerd

sudo crictl \
  --runtime-endpoint unix:///run/containerd/containerd.sock \
  info

ctr plugins ls 看插件状态,crictl info 检查 CRI 接口,两者作用不同------不能只看 containerd 进程是否启动。


五、三个阶段放在一起比较

面试被问到"用 Docker 部署和用 containerd 部署有什么区别",可以从这几个维度展开。

比较维度 K8s 1.24 之前 K8s 1.24 --- 1.28 K8s 1.28 之后
Docker Engine 接入 内置 dockershim 需要 cri-dockerd 仍可使用 cri-dockerd
containerd 接入 通过 CRI 插件 通过 CRI 插件 通过 CRI 插件
是否必须安装 Docker 否 否 否
是否必须安装 containerd 取决于路线,Docker 内部本来就使用它 取决于路线,独立 containerd 是常见选择 取决于路线
Docker CLI 是否必须 Docker 路线需要 仅 Docker 路线需要 仅 Docker 路线需要
kubelet 如何连接运行时 旧版 Docker 路线经过 dockershim Docker 路线经过 cri-dockerd;containerd 路线直连 CRI 基本同上
CRI v1 兼容性 视 Kubernetes 与运行时版本而定 1.26 起是关键要求 必须满足当前 Kubernetes 的要求
cgroup 驱动 需要关注一致性 需要关注一致性 仍需关注,新版本有进一步的自动检测能力
配置文件 取决于 Docker / containerd 版本 取决于 cri-dockerd 或 containerd 版本 还需区分 containerd 1.x / 2.x
新建学习集群的建议 适合研究历史架构 建议直接使用 containerd 建议使用兼容的 containerd 版本

官方文档明确说明:Docker Engine 不实现 Kubernetes 所需的 CRI,因此需要额外的 cri-dockerd;而 containerd 可以通过其 CRI 插件直接提供接口。


六、从安装到运行 Pod:两条路线的动作差异

方案 A:独立 containerd

  1. 安装 containerd 与 crictl。
  2. 配置 CRI 插件、SystemdCgroup 和镜像仓库。
  3. 确认 containerd.service 正常、crictl info 成功。
  4. 安装匹配版本的 kubeadm、kubelet、kubectl。
  5. 通过 --cri-socket unix:///run/containerd/containerd.sock 初始化集群。
  6. 安装 CNI,加入工作节点,验证 Pod。

方案 B:Docker Engine + cri-dockerd

  1. 安装 Docker Engine。
  2. 安装并配置 cri-dockerd 服务。
  3. 确认 Docker 与 cri-dockerd 都正常运行。
  4. 安装匹配版本的 kubeadm、kubelet、kubectl。
  5. 通过 --cri-socket unix:///run/cri-dockerd.sock 初始化集群。
  6. 安装 CNI,加入工作节点,验证 Pod。

三点提醒

  1. 两种方案都要求每个节点安装并配置对应的运行时,而不是只装在 Master 上;Master 上的控制平面组件同样运行在容器里。
  2. 容器运行时解决容器创建与生命周期管理,CNI 负责 Pod 网络,kubeadm 负责集群初始化与节点加入------三者不是同一个东西。
  3. 排查顺序建议:systemctl status containerd → ctr plugins ls → crictl info → journalctl -u kubelet。

参考资料

相关推荐
切糕师学AI1 小时前
K8s 滚动更新与 Spring Boot 优雅停机实战:如何做到真正的平滑发布?
spring boot·云原生·容器·kubernetes·k8s
正经教主1 小时前
【FDE系列】阶段2:Day 45(up详细版):综合实战 — Docker + Nginx + Git 完整部署与本周收官
人工智能·git·nginx·docker·fde
CodeGL2 小时前
一文了解:K8s
云原生·容器·kubernetes
java_logo2 小时前
Docker 部署 Portainer CE 中文版:轻松搭建容器管理平台
运维·docker·容器·portainer·容器管理·轩辕镜像·portainer ce
csdn_aspnet18 小时前
Docker Prune:完整指南与上手示例
运维·docker·容器·prune
谢白羽21 小时前
从传统运维到 AI Infra: K8s 上调度 100 张 GPU踩坑笔记
运维·人工智能·缓存·kubernetes·vllm·sglang·vllm-omni
死磕音视频21 小时前
Dify 入门:用 Docker 自部署并搭建知识库问答助手
docker·知识库·dify·大模型应用
xianyuCcCcCCCcc21 小时前
Kubernetes 资源调度与弹性伸缩:Schedule、Metric、HPA 与 Quota
云原生·kubernetes
我不会起名字3221 天前
滚动更新时请求 502:Pod 终止与 endpoint 摘除的时间差
kubernetes·滚动更新·排查·优雅停机