服务器K8s集群gVisor排错:Pod启动异常与运行时故障排查
在Kubernetes集群里启用gVisor后,Pod无法启动多半不是集群本身的问题,而是RuntimeClass配置、节点运行时状态或权限限制没有对齐。
下面按排查顺序讲清楚每一步该查什么、怎么修、如何验证。
先确认gVisor运行时是否被节点正确识别
gVisor不是默认Runtime,需要先确认节点上是否安装了runsc,以及containerd是否配置了对应的runtime handler。
登录到目标节点,执行:
which runsc
runsc --version
如果命令不存在,说明gVisor没有安装或不在PATH中。
安装步骤可参考gVisor官方文档,但安装后需要检查containerd配置。
查看/etc/containerd/config.toml,找到[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]部分。
正确配置应类似:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc]
runtime_type = "io.containerd.runsc.v1"
修改后重启containerd:
systemctl restart containerd
systemctl status containerd --no-pager
确认没有报错后,再继续排查。
检查RuntimeClass与Pod的关联是否正确
Kubernetes通过RuntimeClass对象把Pod调度到支持gVisor的节点。
先查看集群里是否存在RuntimeClass:
kubectl get runtimeclass
如果没有输出,需要先创建。
一个最小示例:
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: runsc
保存为gvisor-runtimeclass.yaml后执行:
kubectl apply -f gvisor-runtimeclass.yaml
然后确认Pod的spec.runtimeClassName是否写了gvisor。
如果Pod没有指定RuntimeClass,它会使用默认运行时,gVisor不会生效。
另外,节点需要打上标签,确保调度器知道哪些节点支持gVisor。
例如:
kubectl label node <节点名> gvisor=true
并在Pod模板中加上nodeSelector或affinity。
用kubectl describe和日志定位具体错误
当Pod卡在ContainerCreating或反复重启时,优先看事件:
kubectl describe pod -n <命名空间>
重点关注Events部分。
常见错误有:
Failed to create pod sandbox: rpc error: code = Unknown desc = failed to start sandbox container: ...:通常是runsc启动失败,需要看节点上containerd日志。RuntimeClass "gvisor" not found:RuntimeClass名字写错或没创建。failed to get sandbox runtime: no runtime for "runsc" is configured:节点containerd没有配置runsc handler。
查看containerd日志可以执行:
journalctl -u containerd -n 100 --no-pager
如果日志里提示runsc相关错误,比如permission denied、no such file or directory,说明节点上runsc二进制权限或路径有问题。
检查/usr/local/bin/runsc是否存在且可执行:
ls -l /usr/local/bin/runsc
chmod +x /usr/local/bin/runsc
节点内核与cgroup配置容易忽略的坑
gVisor对内核版本和cgroup驱动有要求。
如果节点使用cgroup v2,containerd需要配置SystemdCgroup = true,否则runsc可能无法正常创建沙箱。
在/etc/containerd/config.toml中确认:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc]
runtime_type = "io.containerd.runsc.v1"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc.options]
TypeUrl = "io.containerd.runsc.v1.options"
SystemdCgroup = true
改完重启containerd,再重建Pod测试。
另外,某些内核模块缺失或AppArmor/SELinux策略过严也会阻止runsc启动。
可以临时把SELinux设为permissive测试:
setenforce 0
如果Pod能启动,说明是策略问题,需要针对性添加规则而不是长期关闭。
验证gVisor是否真正生效
Pod正常运行不代表gVisor已生效。
进入Pod执行:
kubectl exec -it -- dmesg | head
如果看到gVisor字样,通常说明运行在沙箱中。
更可靠的方法是检查/proc/version:
kubectl exec -it -- cat /proc/version
gVisor环境下的输出会包含gVisor标识,与宿主机内核版本不同。
如果显示的是宿主机内核,说明Pod没有使用gVisor,需要回头检查RuntimeClass和节点配置。
常见疑问
Pod一直卡在ContainerCreating,但节点上runsc正常,怎么办?
先看kubectl describe pod事件,再检查节点磁盘空间和inode。gVisor启动沙箱需要临时目录,/var/lib/containerd或/tmp空间不足会直接导致失败。
改了containerd配置后需要重启kubelet吗?
通常重启containerd即可,但部分场景下kubelet缓存了运行时信息,建议同时重启:
systemctl restart containerd kubelet
gVisor排错时最应该先看哪个日志?
优先看kubectl describe pod事件,其次看节点上journalctl -u containerd。这两处能覆盖大部分配置和启动错误。
排错的核心思路是:先确认节点运行时配置,再确认RuntimeClass和Pod关联,最后通过事件和日志定位具体报错。
每一步改完都重建Pod验证,避免多个变更叠加导致判断困难。