containerd config.toml 重复执行 default 命令会导致 CRI 插件注册项残留或冲突,引发 kubelet 启动失败、节点 NotReady 或 CRI 连接拒绝;应首次生成后直接编辑配置,确保 [plugins."io.containerd.grpc.v1.cri"] 段存在且未注释,并统一 cgroup 驱动为 systemd,修改后需重启 containerd 再验证。

containerd config.toml 重复生成导致 CRI 插件失效
用 containerd config default 多次执行会覆盖原有配置,但不会自动清理旧的插件注册项。最典型的现象是 kubelet 启动后报错:failed to load plugin "io.containerd.grpc.v1.cri",或者 kubectl get nodes 显示节点 NotReady,journalctl -u kubelet -n 50 里反复出现 CRI 连接拒绝。
实操建议:
- 首次生成后,不要反复运行
containerd config default;如需修改,直接编辑/etc/containerd/config.toml - 确认
[plugins."io.containerd.grpc.v1.cri"]段落存在且未被注释 - 检查
containerd是否启用了 systemd cgroup 驱动:必须与 kubelet 一致(通常为systemd),否则 Pod 启动卡在Pending状态 - 改完配置后,务必执行
sudo systemctl restart containerd,再验证sudo ctr version和sudo crictl ps是否正常
containerd 与 kubelet 的 cgroup driver 不匹配
这是生产环境最隐蔽也最致命的配置冲突之一。kubelet 默认使用 cgroupfs,而现代 Linux 发行版(Ubuntu 22.04+/CentOS 8+)默认启用 systemd cgroup v2,若 containerd 配置为 cgroupfs,会导致容器进程无法被正确归属到 cgroup,继而触发 OOMKilled、资源限制失效或节点失联。
实操建议:
- 查 kubelet 当前驱动:
ps aux | grep kubelet | grep -o 'cgroup-driver=[^[:space:]]*' - 查 containerd 实际配置:
grep -A 5 '\[plugins\."io\.containerd\.grpc\.v1\.cri"\]' /etc/containerd/config.toml | grep systemd,确认systemd_cgroup = true - 若不一致,统一设为
systemd_cgroup = true,并在/var/lib/kubelet/kubeadm-flags.env中显式添加--cgroup-driver=systemd - 重启顺序必须是:先
sudo systemctl restart containerd,再sudo systemctl restart kubelet
cri-containerd-cni 包解压覆盖导致 CNI 插件路径错乱
手动下载 cri-containerd-cni-*.tar.gz 并解压时,若目标目录(如 /opt/cni/bin)已存在旧版插件,且新包中插件名相同但 ABI 不兼容(例如 bridge 插件从 v1.1 升级到 v1.2),Calico 或 Flannel 初始化会失败,表现为 Pod 一直处于 ContainerCreating,kubectl describe pod 显示 Failed create pod sandbox,日志里有 "no such file or directory" "plugin not found"。
实操建议:
- 解压前清空原 CNI 目录:
sudo rm -rf /opt/cni/bin/*,避免混杂版本 - 确认
/etc/containerd/config.toml中plugin_dir指向正确路径(默认是/opt/cni/bin) - 检查关键插件是否存在且可执行:
ls -l /opt/cni/bin/{bridge,host-local,loopback} - 临时测试可用性:
sudo crictl pull k8s.gcr.io/pause:3.9→sudo crictl run --rm -t --net-plugin=bridge ...
kubeadm init 时忽略 containerd socket 路径变更
kubeadm 默认连接 /run/containerd/containerd.sock,但某些离线安装脚本或二进制部署会把 socket 放在 /var/run/containerd/containerd.sock 或自定义路径(如 /run/crio/crio.sock)。若未显式指定,kubeadm 会静默 fallback 到 docker.sock(即使 docker 已卸载),最终初始化失败,错误信息常为:failed to run Kubelet: failed to create kubelet: unable to load client CA file 或更底层的 socket connect refused。
实操建议:
- 确认 socket 路径真实存在:
sudo ls -l /run/containerd/containerd.sock,若不存在,查containerd的 systemd Unit 文件中ExecStart的--address参数 - kubeadm init 时强制指定:
kubeadm init --cri-socket /run/containerd/containerd.sock - 或提前写入默认配置:
echo "criSocket: /run/containerd/containerd.sock" | sudo tee -a /etc/kubeadm.conf,再用--config /etc/kubeadm.conf - 注意:该 socket 路径必须对
kubelet用户(通常是root)可读,SELinux 环境下还需检查上下文是否被重置
systemd_cgroup 值,而后者又影响 CNI 插件能否正确挂载网络命名空间;socket 路径错了,kubeadm 就连握手都做不到——这些环节一旦断掉,错误日志往往只报最表层现象,得一层层反推。


















