写于 2019-12,背景:K8s 1.20 宣布弃用 dockershim(K8s 1.24 正式移除),社区全面转向 containerd / CRI-O。Containerd 成为 K8s 容器运行时的事实标准。
一、为什么选 Containerd
Docker 的架构是"客户端 docker + 守护进程 dockerd + 容器运行时 containerd"。K8s 实际只需要 containerd,于是社区开始鼓励直接用 containerd,跳过 dockerd:
| 维度 | Docker | Containerd |
|---|
| 体积 | ~1GB | ~200MB |
| 启动速度 | 较慢 | 更快 |
| 与 K8s 集成 | 需要 dockershim(已废弃) | 原生 CRI 支持 |
| 镜像构建 | 内置 docker build | 需要 buildkit / nerdctl |
| 生态 | 完整 | 偏运行时,缺少 CLI |
结论:跑 K8s,选 containerd;本机玩镜像构建,继续用 docker。
二、Containerd 安装
2.1 推荐:完整包(cri-containerd-cni)
cri-containerd-cni 一个 tar 包就包含 containerd + runc + CNI 插件 + systemd 配置文件:
1
2
3
4
5
6
| # 下载(version 1.7.11)
curl -L -o cri-containerd-cni-1.7.11-linux-amd64.tar.gz \
https://github.com/containerd/containerd/releases/download/v1.7.11/cri-containerd-cni-1.7.11-linux-amd64.tar.gz
# 解压到根目录(包含 etc/systemd、usr/local/bin、opt/cni 等)
tar Cxzvf / cri-containerd-cni-1.7.11-linux-amd64.tar.gz
|
解压后的目录结构:
1
2
3
4
5
6
7
8
9
10
11
12
| /
├── etc
│ ├── cni/net.d/10-containerd-net.conflist
│ ├── crictl.yaml
│ └── systemd/system/containerd.service
├── opt
│ ├── cni/bin/ # CNI 插件(bridge/host-local/loopback 等 16 个)
│ └── containerd/cluster/ # GCE cloud-init 模板
└── usr/local
├── bin/containerd, containerd-shim, containerd-shim-runc-v1/v2,
│ ctr, crictl, critest, ctd-decoder
└── sbin/runc
|
2.2 单独装 runc
如果只用 containerd 不需要 runc 二进制,可以单独装:
1
2
3
4
5
| wget https://github.com/opencontainers/runc/releases/download/v1.1.11/runc.amd64
mv runc.amd64 /usr/sbin/runc
chmod +x /usr/sbin/runc
runc -v
# runc version 1.1.11 ...
|
2.3 单独装 CNI 插件
1
2
3
4
5
6
| # 下载
wget https://github.com/containernetworking/plugins/releases/download/v1.4.0/cni-plugins-linux-amd64-v1.4.0.tgz
# 解压到 /opt/cni/bin
mkdir -p /opt/cni/bin
tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.4.0.tgz
|
CNI 插件(16 个)包括:bandwidth / bridge / dhcp / firewall / host-device / host-local / ipvlan / loopback / macvlan / portmap / ptp / sbr / static / tuning / vlan / vrf。
三、生成配置文件
Containerd 默认不带配置文件,需要手动生成:
1
2
3
4
5
| # 创建配置目录
mkdir /etc/containerd
# 生成默认配置
containerd config default > /etc/containerd/config.toml
|
关键配置项
1. 镜像加速(国内必须):
1
2
| [plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
|
2. sandbox_image(K8s 启动 Pod 用的 pause 镜像):
1
2
| [plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"
|
3. SystemdCgroup(K8s 推荐用 systemd cgroup driver):
1
2
| [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
|
启动服务
1
2
3
| systemctl daemon-reload
systemctl enable --now containerd
systemctl status containerd
|
四、镜像加速配置
Containerd 的镜像加速基于 hosts.toml 机制,类似 nginx 的 upstream。/etc/containerd/certs.d/ 下的每个域名一个目录:
4.1 docker.io 加速
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| mkdir -p /etc/containerd/certs.d/docker.io
cat > /etc/containerd/certs.d/docker.io/hosts.toml << EOF
server = "https://docker.io"
[host."https://dockerproxy.com"]
capabilities = ["pull", "resolve"]
[host."https://docker.m.daocloud.io"]
capabilities = ["pull", "resolve"]
[host."https://reg-mirror.qiniu.com"]
capabilities = ["pull", "resolve"]
[host."https://registry.docker-cn.com"]
capabilities = ["pull", "resolve"]
[host."http://hub-mirror.c.163.com"]
capabilities = ["pull", "resolve"]
EOF
|
4.2 K8s 官方镜像加速
registry.k8s.io 和 k8s.gcr.io 是 K8s 组件(apiserver、controller-manager、coredns、metrics-server)默认镜像源,国内必须加速:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # registry.k8s.io
mkdir -p /etc/containerd/certs.d/registry.k8s.io
cat > /etc/containerd/certs.d/registry.k8s.io/hosts.toml << EOF
server = "https://registry.k8s.io"
[host."https://k8s.m.daocloud.io"]
capabilities = ["pull", "resolve", "push"]
EOF
# k8s.gcr.io(部分旧镜像)
mkdir -p /etc/containerd/certs.d/k8s.gcr.io
cat > /etc/containerd/certs.d/k8s.gcr.io/hosts.toml << EOF
server = "https://k8s.gcr.io"
[host."https://k8s-gcr.m.daocloud.io"]
capabilities = ["pull", "resolve", "push"]
EOF
|
4.3 其他常用仓库加速
按需配置 docker.elastic.co(ES 镜像)、gcr.io(Google 容器)、ghcr.io(GitHub 容器)、quay.io(Red Hat 镜像)、nvcr.io(NVIDIA GPU 镜像)、mcr.microsoft.com(微软镜像)等等。模板都是一样的:
1
2
3
4
5
6
7
| # 通用模板
mkdir -p /etc/containerd/certs.d/<REGISTRY>
cat > /etc/containerd/certs.d/<REGISTRY>/hosts.toml << EOF
server = "https://<REGISTRY>"
[host."https://<REGISTRY>.m.daocloud.io"]
capabilities = ["pull", "resolve", "push"]
EOF
|
重启生效:systemctl restart containerd
五、客户端工具三件套
Containerd 自带 3 个客户端,各有分工:
5.1 ctr(containerd 自带)
Containerd 原生 CLI,功能最全但最不友好:
1
2
3
4
5
6
7
8
| # 拉镜像
ctr -n k8s.io images pull docker.io/library/nginx:1.25
# 跑容器(无 namespace)
ctr run -d docker.io/library/redis:7 redis-server
# 列出镜像
ctr images ls
|
ctr 没有 docker CLI 的 run / ps / exec 那种"一体化"体验,调试不直观。
5.2 crictl(K8s 调试专用)
K8s 官方推荐 的 CRI 客户端,专用于排查 K8s 节点问题:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # 配置 runtime endpoint
crictl config runtime-endpoint unix:///var/run/containerd/containerd.sock
# 生成的配置在 /etc/crictl.yaml
# 列出 Pod/容器/镜像
crictl pods -A
crictl ps -a
crictl images
# 拉镜像
crictl pull nginx:1.25
# 看容器日志
crictl logs <container-id>
# exec 进容器
crictl exec -it <container-id> sh
|
什么时候用 crictl? 当你 SSH 进 K8s worker 节点,Pod 起不来,需要直接查 containerd 里的容器状态。
5.3 nerdctl(Docker 体验,containerd 后端)
nerdctl 是 containerd 官方的"Docker 兼容"客户端,命令几乎和 docker 一致:
1
2
3
4
5
6
7
8
9
| # 安装
wget https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-1.7.6-linux-amd64.tar.gz
tar xf nerdctl-1.7.6-linux-amd64.tar.gz -C /usr/local/bin
# 用法跟 docker 几乎一样
nerdctl run -d -p 80:80 nginx:alpine
nerdctl ps
nerdctl logs <container>
nerdctl exec -it <container> sh
|
nerdctl vs ctr:ctr 是给 containerd 开发者用的,nerdctl 是给应用运维用的,学习曲线 = docker 经验。
六、Containerd 在 K8s 中的角色
K8s 1.24+ 不再内置 dockershim,需要 containerd / CRI-O / Docker Engine (with cri-dockerd) 三选一:
1
2
3
4
5
| kubelet (K8s 节点)
↓ CRI (gRPC)
containerd
↓ OCI
runc → 容器进程
|
kubelet 通过 CRI(Container Runtime Interface)调用 containerd,containerd 内部用 runc 启动容器。用户不需要再写 docker build——镜像可以用 buildah、buildkit、kaniko 在 CI 里构建。
七、常见坑
- 镜像加速不生效:hosts.toml 路径错了(应是
/etc/containerd/certs.d/<registry>/ 不是 /etc/docker/) - crictl 报 connection refused:runtime-endpoint 没配对,crictl 默认走 dockershim,现在要改成
unix:///var/run/containerd/containerd.sock - SystemdCgroup 没开:cgroup driver 不一致,kubelet 起不来,日志里能看到 “cgroup driver “cgroupfs” differs from kubelet”
- pause 镜像拉不到:sandbox_image 默认是
k8s.gcr.io/pause:3.5,国内必须改成阿里云
八、前置知识 / 下一步
前置:Docker 基础、K8s 集群架构(参考 2017-06-15《Kubernetes 入门》)
下一步:
- K8s 二进制部署(2020-03-15)—— Containerd 作为容器运行时的完整部署
- K8s 集群管理(2021-12-15)—— 升级 / 节点隔离 / 排错
参考资料