K8s集群Containerd排错:Pod起不来怎么查
K8s集群里Pod一直卡在ContainerCreating、节点变成NotReady,或者镜像拉不下来,很多情况下问题出在Containerd这一层。
Containerd是Kubernetes用来真正启动和运行容器的运行时组件,一旦它异常,K8s的调度指令就落不了地。
下面按“先确认现象、再定位组件、然后修配置、最后验证恢复”的顺序,把排查路径走一遍。
先确认问题出在Containerd还是K8s
不要一上来就重启服务。
先看节点和Pod的状态,判断范围。
在能访问集群的机器上执行:
kubectl get nodes
kubectl get pods -A -o wide | grep -v Running
如果某个节点是NotReady,登录该节点继续查。
如果节点正常但Pod卡住,记下Pod所在节点和事件信息:
kubectl describe pod -n <命名空间>
重点看Events里有没有Failed to create pod sandbox、failed to pull image、rpc error这类字样。
出现这些,基本可以把方向锁定在Containerd。
用crictl确认Containerd能否正常响应
crictl是Kubernetes官方提供的容器运行时命令行工具,用来和Containerd这类CRI运行时通信。
先确认Containerd服务本身是活的:
systemctl status containerd
journalctl -u containerd -n 100 --no-pager
如果服务是active (running),再看crictl能不能连上:
crictl version
crictl info
如果报connection refused或context deadline exceeded,说明crictl连不到Containerd的socket。
检查/etc/crictl.yaml里的runtime-endpoint是否指向正确路径,常见配置是:
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
如果socket路径不对,改成Containerd实际监听的地址,再执行crictl info确认返回JSON信息。
排查配置文件和镜像拉取问题
Containerd的配置文件通常在/etc/containerd/config.toml。
常见坑是配置了错误的镜像仓库、sandbox镜像地址写错,或者SystemdCgroup没开。
先看关键配置项:
grep -n "sandbox_image\|SystemdCgroup\|endpoint" /etc/containerd/config.toml
如果SystemdCgroup = false,在kubelet使用systemd cgroup驱动的集群里,可能导致Pod反复重启。
正确做法是设为true:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
改完配置后重载并重启:
systemctl daemon-reload
systemctl restart containerd
如果是镜像拉取失败,先用crictl手动拉一次,看具体报错:
crictl pull nginx:latest
报no such host通常是DNS问题,检查/etc/resolv.conf;
报x509或certificate是证书问题;
报401或403是私有仓库认证没配。
私有仓库认证信息一般放在/etc/containerd/config.toml的registry段,或通过ctr image pull带上认证参数测试。
节点层面容易被忽略的检查项
有些问题不在Containerd本身,而在它依赖的资源上。
磁盘写满会导致Containerd无法创建容器。
检查:
df -h /var/lib/containerd
如果使用率接近100%,清理无用镜像和容器:
crictl rmi --prune
内存和PID耗尽也会让容器起不来,用free -h和dmesg | tail -50看有没有OOM记录。
另外确认kubelet和Containerd的cgroup驱动一致。
如果kubelet配置里是cgroupDriver: systemd,Containerd也必须对应开启SystemdCgroup = true,否则节点可能反复NotReady。
修复后的验证方法
改完配置或清理完资源后,不要只看服务状态。
按以下顺序验证:
systemctl restart containerd
systemctl restart kubelet
crictl info
kubectl get nodes
kubectl get pods -A -o wide | grep -v Running
crictl info能正常返回运行时信息,节点在几十秒内恢复Ready,之前卡住的Pod重新调度或进入Running,说明问题已经解决。
如果Pod还在报错,回到kubectl describe pod看新的事件,确认是否出现新的报错信息。
几个常见疑问
Containerd和Docker是什么关系?
Docker内部也使用Containerd作为运行时,但K8s从1.24版本左右开始默认直接用Containerd作为CRI运行时,不再经过Docker。排错时要用crictl而不是docker命令。
重启Containerd会影响正在运行的业务Pod吗?
重启Containerd本身不会主动杀掉已运行的容器,但期间CRI接口短暂不可用,kubelet可能上报节点异常。生产环境建议在维护窗口操作,并确认有副本冗余。
为什么改了config.toml没生效?
Containerd不会自动监听配置变化,必须执行systemctl restart containerd。另外确认改的是实际加载的配置文件路径,有些安装方式会用--config指定非默认路径。
crictl和ctr有什么区别?
crictl走CRI接口,面向Kubernetes场景;ctr是Containerd自带的底层工具,直接操作Containerd命名空间。排查K8s问题时优先用crictl,ctr适合更底层的镜像和容器操作。
排错的核心思路是分层:先看K8s层面的Pod事件,再确认Containerd服务状态,然后用crictl验证CRI通信,最后检查配置、磁盘、cgroup这些依赖项。
每一步都有对应的命令和预期输出,按顺序走一遍,大部分Containerd导致的Pod异常都能定位到具体原因。