Skip to content

containerd 与 CRI

containerd 是容器运行时,Docker 和 Kubernetes 都会和它发生关系。早期接触容器时常用 docker 命令,到了 Kubernetes 里,kubelet 不再直接调用 Docker CLI,而是通过 CRI(Container Runtime Interface)和运行时通信。containerd 是当前最常见的 CRI 实现之一。

这几个名字容易混在一起:Docker 是面向使用者的完整工具链,containerd 负责镜像和容器生命周期,runc 按 OCI 规范真正创建容器进程,CRI 是 kubelet 和运行时之间的接口。

一、运行时关系

Docker 场景里,用户通过 Docker CLI 调 dockerd,dockerd 再调 containerd。Kubernetes 场景里,kubelet 通过 CRI 直接调 containerd,不需要 dockerd 夹在中间。

Docker 仍然可以在单机开发、Compose、镜像构建场景里使用;Kubernetes 节点上更关心 containerd、kubelet 和 CNI。

二、CRI 是什么

CRI 是 kubelet 调用容器运行时的标准接口。它把“拉镜像、创建 Pod sandbox、启动容器、停止容器、查日志”这些动作抽象成统一 API。

动作kubelet 通过 CRI 请求运行时
拉镜像PullImage
创建 Pod 沙箱RunPodSandbox
创建容器CreateContainer
启动容器StartContainer
获取状态ContainerStatus
删除资源RemoveContainerStopPodSandbox

Pod sandbox 是 Pod 的基础运行环境,通常对应 pause 容器和网络命名空间。业务容器会加入这个 sandbox,共享 Pod IP 和网络空间。

三、containerd 配置

containerd 常见配置文件:

bash
# 生成默认配置,已有配置时要先备份再操作
containerd config default | sudo tee /etc/containerd/config.toml

Kubernetes 节点上常见配置点:

toml
[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true
配置说明
sandbox_imagePod sandbox 使用的 pause 镜像
SystemdCgroup和 kubelet 的 cgroup driver 保持一致
registry mirrors镜像源和私有仓库配置

修改后重启:

bash
sudo systemctl restart containerd
sudo systemctl status containerd --no-pager

Kubernetes 节点上重启 containerd 会影响正在运行的容器管理面,操作前要确认节点是否需要先 drain。

四、crictl

crictl 是面向 CRI 的排查工具。它不依赖 Docker daemon,适合 Kubernetes 节点排查。

配置 /etc/crictl.yaml

yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false

常用命令:

bash
# 查看 Pod sandbox
crictl pods

# 查看容器
crictl ps -a

# 查看镜像
crictl images

# 查看某个容器日志
crictl logs <container-id>

# 查看运行时信息
crictl info

kubectl 从 API Server 看对象状态,crictl 从节点运行时看真实容器状态。API Server 正常但某个节点 Pod 状态异常时,登录节点用 crictl 能看到更底层的信息。

五、nerdctl

nerdctl 是 containerd 的 Docker 风格客户端。命令体验接近 Docker:

bash
nerdctl images
nerdctl pull nginx:1.26
nerdctl run -d --name web -p 8080:80 nginx:1.26
nerdctl ps

containerd 有 namespace 概念。Kubernetes 默认使用 k8s.io namespace:

bash
nerdctl --namespace k8s.io images
nerdctl --namespace k8s.io ps

看不到 Kubernetes 镜像时,经常是因为 namespace 查错了。default namespace 里没有,不代表节点没有镜像。

六、镜像源和私有仓库

containerd 的镜像源配置和 Docker 的 daemon.json 不一样。K3s 内置 containerd 常用 /etc/rancher/k3s/registries.yaml,标准 containerd 常用 certs.dconfig.toml

K3s 示例:

yaml
mirrors:
  docker.io:
    endpoint:
      - "https://docker.1ms.run"
configs:
  registry.example.com:
    tls:
      insecure_skip_verify: false

标准 containerd 的 hosts.toml 示例:

toml
server = "https://docker.io"

[host."https://docker.1ms.run"]
  capabilities = ["pull", "resolve"]

Docker 能拉镜像,不代表 Kubernetes 节点也能拉。Kubelet 通过 containerd 拉镜像,排查 ImagePullBackOff 时要看 containerd 的 registry 配置、证书和凭据。

七、排查入口

现象查看方式
Pod 一直 ContainerCreatingcrictl podscrictl ps -a、kubelet 日志
ImagePullBackOffcontainerd 镜像源、证书、Secret、仓库权限
容器日志 kubectl 看不到节点上 crictl logs
节点 NotReadykubelet、containerd、CNI、磁盘和 cgroup
镜像占用过多crictl images、containerd 内容存储清理

常用节点侧命令:

bash
systemctl status containerd --no-pager
journalctl -u containerd -n 100 --no-pager
journalctl -u kubelet -n 100 --no-pager
crictl info
crictl ps -a

containerd 是 Kubernetes 节点排查里绕不开的一层。Pod 在 API 里只是对象,真正的镜像拉取、容器创建、日志文件和退出码,都落在节点运行时上。

Kubernetes 节点维护时,containerd 会和 kubelet、镜像清理、磁盘压力、Pod 驱逐一起出现,相关操作见 节点运维