Kubernetes 宣移除 dockershim 之后,containerd 成了容器编排领域事实上的标准运行时。虽然 Docker 创建的容器依然可以正常使用,但如果你在搭建新的 Kubernetes 集群,或者希望精简节点上的组件,直接使用 containerd 是更主流的选择。这篇文章会把 Docker 和 containerd 的关系讲清楚,再一步步演示如何完成迁移。

一、先搞清楚 Docker 和 containerd 是什么关系
很多人以为 containerd 是 Docker 的替代品,是从零开始写的一个新项目,这个理解有偏差。containerd 最早就是 Docker 公司捐给 CNCF 的项目,它原本就是 Docker 架构中的一个核心组件,负责容器生命周期管理、镜像存储和网络命名空间的创建。Docker 引擎本质上是在 containerd 之上加了一层封装,包括 Docker CLI、Docker API、镜像构建、日志管理、卷管理等用户体验层面的功能。
换句话说,你日常使用的 docker run,最终执行容器创建的其实就是底层的 containerd。Docker 引擎内部还有一个叫 containerd-shim 的进程,它负责守护每个容器的运行,即使 Docker 守护进程重启,容器也不会被杀掉,这就是所谓的热升级能力。
迁移到 containerd,相当于把 Docker 这层外壳剥掉,直接操作内核组件。好处是明显的:节点上少了一个常驻的 Docker 守护进程,资源占用更低,容器启动链路更短,与 Kubernetes 的 CRI 接口对接也更直接。代价是失去了一部分便利功能,比如 docker build 构建镜像、docker logs 查看日志,这些需要换成新的工具来替代。
二、迁移前必须确认的兼容性问题
1. 镜像格式差异
Docker 默认存储的镜像是 Docker V2 格式,而 containerd 通过 CRI 插件使用的是 OCI 标准格式。两者在镜像清单层面有细微差别,最直接的表现是镜像列表不互通:切换运行时后,原来 Docker 拉取的镜像不能被 containerd 直接使用,需要重新拉取或转换。
2. 日志驱动配置
Kubernetes 依赖容器运行时输出日志文件到指定目录,然后由 kubelet 所在节点的日志收集器统一处理。Docker 默认的日志驱动是 json-file,而 containerd 的 CRI 插件要求日志输出到 /var/log/pods 和 /var/log/containers 目录。如果你的监控体系依赖特定日志路径,迁移时要同步调整采集配置。
3. 镜像构建工具链
containerd 本身不提供 docker build 能力,官方推荐使用 BuildKit 或者 nerdctl 这类工具。BuildKit 可以独立运行,通过 buildctl 命令构建镜像并直接推送到仓库;nerdctl 则是一个模仿 Docker CLI 的工具,用起来几乎和 Docker 一样,学习成本很低。迁移前建议先在测试环境把这些工具跑通。
4. 监控指标接口
Docker 提供了自己的 metrics 接口,很多监控系统直接采集 Docker 的 API 数据。containerd 的监控指标需要通过 CRI 接口或者 Prometheus 插件获取,原来针对 Docker 写的采集脚本需要改造。这一点在生产环境迁移中经常被忽略,需要提前盘点。
三、安装和配置 containerd 完整步骤
下面以 Ubuntu 系统为例演示完整流程,CentOS 的操作基本一致,只是包管理命令不同。开始之前,建议先在测试节点演练一遍。
第一步,安装 containerd 软件包。推荐从官方仓库安装,这样能获取较新的稳定版本:
# 安装依赖并添加 Docker 官方仓库 sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 安装 containerd sudo apt-get update sudo apt-get install -y containerd.io
第二步,生成默认配置并修改。默认配置文件是不存在的,需要先导出一份:
sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml
然后编辑 /etc/containerd/config.toml,重点关注两处配置。一是把 SystemdCgroup 设置为 true,让容器使用 systemd 管理 cgroup,这是 Kubernetes 官方推荐的做法,可以避免 cgroup 驱动不一致导致的资源统计问题:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
二是配置镜像加速器。如果节点在国内,拉取镜像时配置一个加速地址能明显提升速度:
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://registry.example-cn.ipipp.com"]
第三步,重启服务并设置开机自启:
sudo systemctl restart containerd sudo systemctl enable containerd sudo systemctl status containerd
第四步,安装 crictl 工具。crictl 是 CRI 运行时的命令行客户端,作用相当于之前的 docker 命令。它需要一个配置文件指定运行时 endpoint:
cat <<'EOF' | sudo tee /etc/crictl.yaml runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: false EOF
配置完成后,执行 sudo crictl info 能正常返回运行时信息,就说明安装成功了。
四、常用命令对照与镜像处理
切换到 containerd 后,日常操作习惯需要调整。下面这个对照表能帮你快速上手:
| 操作 | Docker 命令 | containerd 环境命令 |
|---|---|---|
| 查看镜像 | docker images | crictl images |
| 拉取镜像 | docker pull nginx | crictl pull nginx |
| 查看容器 | docker ps | crictl ps |
| 查看所有容器 | docker ps -a | crictl ps -a |
| 进入容器 | docker exec -it 容器 bash | crictl exec -it 容器 bash |
| 查看日志 | docker logs 容器 | crictl logs 容器 |
| 查看详情 | docker inspect 容器 | crictl inspect 容器 |
有一点要特别说明:crictl 操作的是 CRI 命名空间下的镜像和容器,而 containerd 本身支持多命名空间。如果你想直接管理 containerd 的原生资源,需要用 ctr 命令并指定命名空间,例如 ctr -n k8s.io images list。两个命令看到的镜像列表不同,这是初学者最容易困惑的地方。
至于本地已有 Docker 镜像的处理,最简单的方案是导出再导入。Docker 导出的 tar 包可以通过 ctr 命令导入到 k8s.io 命名空间:
# 在原环境导出 docker save -o app.tar myapp:1.0 # 导入到 containerd 的 k8s.io 命名空间 sudo ctr -n k8s.io images import app.tar
如果镜像数量多,或者来源环境不可用,直接配置镜像加速重新拉取往往更省事。
五、迁移后的验证与回退方案
切换运行时后不要急着下线 Docker,先做完整验证。第一步验证容器网络,创建一个测试 Pod 确认 DNS 解析和服务访问正常;第二步验证日志采集,检查 /var/log/pods 目录下是否正常生成日志文件,日志收集器能否正确读取;第三步验证监控指标,确认 cAdvisor 或 Prometheus 采集到的容器指标没有中断。
对于 Kubernetes 集群节点,迁移顺序建议是先驱逐节点上的工作负载,修改 kubelet 配置中的 --container-runtime 参数和对应的 endpoint,再让节点重新加入集群:
# 修改 /var/lib/kubelet/kubeadm-flags.env CONTAINER_RUNTIME="containerd" CONTAINER_RUNTIME_ENDPOINT="unix:///run/containerd/containerd.sock" # 重启 kubelet sudo systemctl restart kubelet
回退方案也要提前准备。只要不卸载 Docker 包,把 kubelet 的运行时参数改回 docker 的 endpoint 并重启,节点就能恢复原状。所以生产环境迁移时,建议保留 Docker 一到两周作为观察期,确认日志、监控、告警链路全部稳定后,再彻底清理 Docker 环境和相关的镜像存储目录,释放磁盘空间。
整体来看,从 Docker 迁移到 containerd 的技术难度并不高,真正的挑战在于周边工具链的适配。把镜像构建、日志采集、监控指标这几个依赖点提前梳理清楚,按照测试节点、工作节点、控制节点的顺序分批操作,整个迁移过程可以做到业务无感知。
containerdDocker迁移容器运行时修改时间:2026-09-05 00:16:47