朋友们!咱今天就聊聊容器世界里那个**存在感超低却至关重要的狠角色**——Containerd。说真的,每次提到容器,Docker 那可爱的鲸鱼 logo 立刻蹦进脑子,Kubernetes 的舵轮标志也霸气得不行。但**Containerd?** 它就像后台那位穿着格子衫、默默敲代码的大佬,活儿全干了,名声?不存在的!(直到你的集群出问题,深入排查时才惊呼:啊!原来是您老在管事啊?)
## 一、 容器世界的"地基":运行时到底是啥玩意儿?
先别急着跑,咱得把地基打牢了。想象一下你盖房子(容器):
1. **图纸 (镜像 Image):** 房子的设计蓝图,定义了里面要有啥(比如 Ubuntu + Nginx + 我的代码)。Docker build / Podman build 主要干这个。
2. **施工队 (容器运行时 Container Runtime):** **负责按图纸把房子 (容器) 真正盖起来并运行!** 这才是 Containerd 的核心战场。它干的是**最脏最累最底层的活**:
* 从仓库拖图纸 (`docker pull` / `crictl pull` 背后是它)。
* 按图纸砌砖、通水电 (`container create`)。(理解成创建运行环境:挂载 rootfs、设置 namespaces/cgroups 限制...)
* 启动住户进程 (`container start`)。
* 管理房子的生老病死 (`stop`, `pause`, `rm`...)。
* 处理房子里的垃圾 (`container kill` 清理进程)。
* 看门+监控 (`events`, `stats`)。
**简单粗暴总结:** 没了运行时,你的镜像就是一坨漂亮的、没法运行的二进制数据!Docker 和 K8s 都**依赖**底层运行时来真正操作容器。
## 二、 Containerd 的崛起:从 Docker 的"内脏"到行业基石
故事时间到!(倒杯咖啡呗☕️)
* **远古时代 (2013-2016):** Docker 一家独大。它自己就包含了一个完整的容器运行时(当时是 `docker-containerd` + `docker-runc` 的早期组合)。开发者用 Docker CLI (`docker run...`),一切岁月静好(表面上看)。
* **痛点浮现:**
* **Docker 太重了!** 对于只想跑容器、不需要 Docker Swarm/Build 等全家桶的场景(尤其是 K8s),一个臃肿的 Docker Daemon 显得很多余。
* **依赖耦合深:** K8s 想直接管理容器生命周期?得通过一层层的 Docker API 调用,效率低,路径长,**复杂且不稳定!**
* **标准缺失:** 各家运行时实现五花八门,互操作性是个噩梦。
* **破局之道:OCI 标准与 CRI**
* **OCI (Open Container Initiative):** Linux 基金会搞的,定了容器**镜像格式 (OCI Image Spec)** 和**运行时规范 (OCI Runtime Spec)**。`runc` 成为了最主流的 OCI 运行时参考实现。(`runc` 就是干实际 `fork/exec` 进程 + 设置隔离环境那个小工具)。
* **CRI (Container Runtime Interface):** Kubernetes 发明的插件接口!它定义了一组 gRPC 协议。K8s 的 `kubelet` 只认 CRI,**不管**底下是 Docker、Containerd 还是其他什么运行时,只要实现了 CRI 接口就能接入 K8s!(划重点啊同志们!!!)
* **Containerd 的华丽转身:**
* Docker 公司(后改名 Mirantis)有远见!他们意识到需要把核心的**运行时管理能力**独立出来、标准化、让更多人受益。
* **2016-2017:** Docker 把 `containerd` 项目捐献给了 **CNCF (云原生计算基金会)**。是的,就是管着 K8s、Prometheus 那帮大佬的基金会!
* **使命:** 成为一个**专注于运行容器**的、**工业级**的、**符合标准**的**守护进程 (daemon)**。它定位清晰:
* 管理容器生命周期(从拉镜像到运行到销毁)。
* 管理镜像(拉取、存储、转换)。
* 管理存储卷(Volume)。
* 提供稳定 API 供上层调用(比如 Docker Engine,比如 K8s CRI 插件)。
* **它自己不直接操作 `runc`!** 它通过一个叫 `containerd-shim` 的中间层来管理 `runc` 实例。这个 `shim` 设计超级妙!后面细说。
**结果?Containerd 赢了!而且赢得漂亮!**
* 它成了 **Kubernetes 默认推荐**的容器运行时(尤其是在 1.24 版本弃用内置 Docker shim 之后)!!!
* Docker Engine 自己也把 Containerd 作为默认底层运行时。
* 几乎所有主流云平台和发行版的 K8s 底层都在用它(GKE, EKS, AKS, 你熟知的 Linux 发行版...)。
* **轻量、稳定、专注、符合标准**,让它成了大规模容器集群的**不二之选**。
## 三、 Containerd 架构深潜:简洁有力,插件为王!(适合好奇宝宝)
别被“底层”吓到,Containerd 的设计其实相当优雅(至少在我看来)。来,掀开引擎盖瞧瞧:
±-----------------------+ ±-----------------------------------+
| Your Awesome App | | Docker Engine (dockerd) |
| (e.g., docker run) | <—>| (Build, Network Mgmt, API, UX…) |
±-----------------------+ ±-------------±--------------------+
| (Containerd API)
v
±-------------------------------------------------+
| containerd (daemon) |
| ±---------------+ ±---------------+ |
| | Plugins | | GRPC API | <------->| CRI Clients (e.g., kubelet via cri-plugin)
| | (Storage, | | (Core Control) | |
| | Metadata, | ±---------------+ |
| | Events…) | |
| ±---------------+ |
| | |
| | Manage Tasks |
| v |
| ±-----------------------------------------------+|
| | Task Supervisor ||
| | (Manages shims and their lifecycle) ||
| ±-----------------------------------------------+|
| | |
| | (via containerd-shim) |
| v |
| ±-----------------------------------------------+|
| | containerd-shim (per container!) || <-- 关键先生!
| | - Acts as parent for runc ||
| | - Keeps STDIO open (no TTY stuck!) ||
| | - Reports exit status ||
| | - Zombie process reaping ||
| | - Enables live restore on daemon restart || (神设计!)
| ±-----------------------------------------------+|
| | |
| | (OCI Runtime Spec) |
| v |
| ±-----------------------------------------------+|
| | runc (or other OCI runtime) ||
| | (fork/exec the container process, namespaces,||
| | cgroups, seccomp, capabilities…) ||
| ±-----------------------------------------------+|
±-------------------------------------------------+
**核心亮点解析(个人觉得超酷的点):**
1. **`containerd-shim`:神设计!**
* **为啥要它?** 设想:如果 `containerd` 自己直接 `fork/exec` 出 `runc` 来跑容器,那么 `containerd` 就是容器的父进程。一旦 `containerd` 重启或挂掉(虽然它很稳定,但总有运维操作嘛),它的所有子进程(容器)会收到 `SIGKILL` 信号——容器全挂了!灾难!
* **`shim` 如何救场:** `containerd` 先 `fork/exec` 出一个 `containerd-shim` 进程。然后,`shim` 再去 `fork/exec` 出 `runc`跑容器。这样:
* `containerd` 挂了?没关系!容器的父进程是 `shim`,`shim` 还活着,容器继续跑!
* `containerd` 重启后,它能找到存活的 `shim`,重新连接上,继续管理容器。**无缝衔接!** (生产环境救命稻草!!!)
* **它还干了啥好事?**
* **处理 TTY/STDIO:** 保证即使 `containerd` 断开,你的 `docker attach` / `kubectl logs` 还能用。
* **收集退出状态:** 容器挂了?`shim` 确保退出码被正确报告给 `containerd`。
* **清理僵尸:** 负责任地“收尸”。
* **降低升级影响:** 升级 `containerd` 时,容器通常不受影响!(当然,最好还是滚动重启)
2. **插件化架构:**
* Containerd 的核心职责明确且稳定。其他功能(比如**存储驱动、快照ter、镜像仓库授权、CRI 实现...**) 都设计成了**插件 (Plugins)**!
* **好处爆炸多:**
* 核心更稳定!升级插件不影响核心。
* 按需启用!生产环境不需要的功能?关掉!安全加固。
* 生态扩展!社区或厂商可以开发自己的插件满足特定需求(比如 GPU 支持插件)。
* CRI 支持就是通过 `cri` 插件实现的!(`cri` 插件把 K8s CRI 请求翻译成 containerd 自己的 API 调用)
3. **CRI 插件:连接 K8s 的桥梁**
* 这就是为啥 K8s (kubelet) 能直接驱动 containerd!`cri` 插件实现了 CRI gRPC Server。
* 它处理 PodSandbox (pause 容器)、Pod 网络、镜像拉取(可配置镜像仓库认证)、容器创建启动销毁等所有 CRI 要求的动作。
* 通常配置在 `/etc/containerd/config.toml` 里,超级灵活。
## 四、 Containerd vs Docker:剪不断理还乱?**不!定位清晰得很!**
别再傻傻分不清了!他俩是**上下游关系**,不是竞争对手!(虽然历史渊源深)
* **Docker (Engine / dockerd):**
* **定位:** 完整的**开发者体验 (DX) 工具链和平台**。
* **包含:**
* 容器运行时管理(**底层调用 containerd**)
* **镜像构建 (`docker build`)**
* **镜像仓库交互 (`docker push/pull`)**
* 高级网络管理(Swarm scope, 跨容器网络)
* **用户友好的 CLI (`docker run/ps/exec...`)**
* REST API
* 文档、社区、商业支持等。
* **优点:** 开箱即用,开发者友好,功能全家桶。
* **缺点:** 相对较重,部分功能在纯运行时场景冗余。
* **Containerd:**
* **定位:** 纯粹的、高性能、稳定的**容器生命周期管理守护进程**。专注底层运行时。
* **包含:**
* 容器生命周期 (create/start/stop/rm...)
* 镜像管理 (pull/push/存储)
* 存储卷管理
* 底层 API (GRPC)
* 通过插件扩展(如 CRI)。
* **优点:** 轻量级、高效稳定、符合标准(OCI)、插件化、CNCF 毕业项目、云原生/K8s 首选。
* **缺点:** **没有用户友好的默认 CLI!** 你需要 `ctr` (containerd 自带的测试工具,贼难用) 或者 `nerdctl` (超赞的替代品!) 或者 `crictl` (主要看 CRI 容器) 来操作它。**不处理构建!不提供 Docker 那样的网络抽象!**
**大白话比喻:**
* **Docker 是辆功能齐全的豪华 SUV:** 能拉人载货(容器),有漂亮内饰和导航(CLI/UX),自带工具箱(Build/Swarm)。适合家庭出游(开发者本地)。
* **Containerd 是重型卡车的底盘和引擎:** 极其坚固可靠,动力澎湃,专注于承载核心负荷(运行容器)。但你要自己配驾驶室(CLI)、货箱(网络/构建)才能组成一辆完整的卡车(生产集群)。它是物流车队(云平台/K8s)的绝对主力。
**结论:** 你开发应用、本地调试?Docker 依然很棒!跑大规模生产 K8s 集群?Containerd 是基石!**Docker Engine 离不开 Containerd,现代 K8s 集群拥抱 Containerd。**
## 五、 上手 Containerd:直击要害操作指南(告别 `ctr` 的地狱!)
我知道 `ctr` 的命令行设计得...呃...不太友好(这是客气的说法)。别慌!强推神器 **[nerdctl](https://github.com/containerd/nerdctl)**!它提供了类似 `docker` CLI 的用户体验,直接操作 containerd!**(开发者福音!!!)**
假设你已经装了 containerd(大部分 K8s 发行版默认装好了)。装 `nerdctl`:
```bash
# 去 GitHub release 页面找最新版,比如:
wget https://github.com/containerd/nerdctl/releases/download/v1.7.2/nerdctl-1.7.2-linux-amd64.tar.gz
tar -xvf nerdctl-1.7.2-linux-amd64.tar.gz -C /usr/local/bin/
基础操作 (感觉是不是很 Docker?):
# 1. 拉镜像 (默认使用 Docker Hub)
nerdctl pull nginx:alpine
# 2. 运行容器!(熟悉的配方)
nerdctl run -d --name my-nginx -p 8080:80 nginx:alpine
# 3. 查看运行中的容器
nerdctl ps
# 4. 看日志
nerdctl logs my-nginx
# 5. 进容器 shell
nerdctl exec -it my-nginx sh
# 6. 停止 & 删除
nerdctl stop my-nginx
nerdctl rm my-nginx
高级玩法(nerdctl 也支持很多):
- 构建镜像:
nerdctl build -t my-image .(需要buildkitd) - Compose:
nerdctl compose up -d(兼容docker-compose.yml!本地开发测试更方便了) - 管理镜像:
nerdctl images,nerdctl rmi ... - 管理网络 (
nerdctl network ...) / 卷 (nerdctl volume ...)
查看 Containerd 管理的容器:
# 使用 crictl (如果你是 K8s 环境,crictl 默认就是配好连 Containerd 的)
crictl ps
crictl images
# 或者直接用 nerdctl (不加 `-n k8s.io` 看的是 default 命名空间,K8s 容器通常在 `k8s.io`)
nerdctl -n k8s.io ps
配置 (/etc/containerd/config.toml) : 这才是重点!生产环境必调!常见项:
systemd_cgroup = true(如果系统用 systemd,务必开启!尤其 K8s!不然资源统计不准!)- 镜像仓库 mirror / 认证: 加速拉取,访问私有仓库。
sandbox_image(pause 镜像): 指定 K8s 用的 pause 镜像地址。- 日志驱动/选项: 控制容器日志格式、大小限制 (
json-file或journald常见)。 - 存储驱动 (
io.containerd.runc.v2是主流) / 快照ter (overlayfs主流)。
(超级重要) 改完配置记得重启服务:sudo systemctl restart containerd
六、 我为什么觉得 Containerd 是未来?(个人碎碎念)
- Kubernetes 的“官方选择”: 事实标准的力量是巨大的。社区、生态、工具链都围绕着它优化。稳定性、性能的投入是持续的。
- “Less is More” 的胜利: 它完美诠释了单一职责原则。只做运行时,做到极致。这带来了惊人的稳定性和低资源消耗。在一个动辄成百上千节点的 K8s 集群里,每节点省一点 CPU/Memory,整体收益巨大!
- 插件化带来无限可能: GPU、FPGA、特殊硬件加速?安全沙箱(Kata Containers, gVisor)?新的存储后端?都可以通过插件集成!核心依然保持纯净。这种架构的生命力太强了。
- OCI 标准的坚定执行者: 拥抱开放标准是避免厂商锁定的关键。Containerd 和
runc的组合是 OCI 的标杆实现。 - 社区与基金会背书: CNCF 毕业项目意味着极高的成熟度、完善度以及活跃健康的社区支持。企业用着放心。
- 摆脱 Docker 的历史包袱: Docker 曾经是伟大的开创者,但其架构设计(尤其是早期)为了快速迭代,包含了一些历史包袱和较强的耦合。Containerd 作为后起之秀,设计更清晰、更现代。
当然,也有槽点:
- 用户体验门槛: 没有
nerdctl之前(或者crictl),原生ctr真的让人抓狂。现在好多了,但生态工具链相比 Docker 的成熟度和统一性,仍需努力(尤其在非 K8s 场景)。 - 学习曲线: 想真正理解它的架构(特别是 sh
156

被折叠的 条评论
为什么被折叠?



