概述
大家好,我是老王,在云原生领域摸爬滚打了七八年,今天想和大家聊聊Kubernetes运维中最让人头疼的问题之一——Pod启动失败。相信不少朋友都遇到过这种场景:满怀信心地执行了kubectl apply,结果pod一直卡在Pending或CrashLoopBackOff状态,那种感觉就像精心准备的代码突然报了个莫名其妙的error。别急,今天我就把自己这些年踩过的坑、总结的排查套路,还有社区里大家常遇到的典型问题,都整理出来和大家分享。如果你也正在为某个‘倔强’的pod发愁,不妨跟着我的思路一起排查,文末还有我整理的排查清单和几个经典案例,欢迎大家在评论区补充你的实战经验!
一、先别急着查日志,这些基础检查你做了吗?
很多新手一看到pod起不来就直奔日志,其实有些问题根本不需要那么复杂。上周我们团队的小张就遇到了一个典型情况:他写的deployment yaml里,image用的是自己本地构建的tag,结果在集群里死活拉不下来。后来发现是imagePullPolicy设成了IfNotPresent,而集群里根本没有这个镜像。\n\n所以排查第一步,先做这些基础确认:\n1. kubectl describe pod
二、镜像问题:你以为拉取了,其实并没有
镜像相关的问题能占pod启动失败的30%以上,而且表现形式五花八门。除了刚才说的镜像不存在,还有这些常见坑:\n\n\n如果你的镜像是latest标签,又设了IfNotPresent,那么节点上有旧版本就不会拉取新的。建议生产环境用固定tag,并且设置imagePullPolicy: Always。\n\n\n这个坑我踩过三次!明明在机器上docker login成功了,但k8s就是拉不了。后来发现是secret的namespace不对,或者secret类型选错了(要用docker-registry类型)。\n\n 上个月帮朋友公司排查,他们的pod在A集群正常,迁移到B集群就启动失败。最后发现两个集群的docker config.json格式不一样,一个用了auth字段,一个用了auths字段。\n\n\n特别是基础镜像加上各种依赖,超过2GB很常见。这时候可以:\n- 优化镜像层(合并RUN指令、清理缓存)\n- 使用本地镜像仓库做缓存\n- 调整kubelet的--image-pull-progress-deadline参数\n\n 我整理了一份《镜像优化checklist》,关注公众号‘云原生实战派’,回复‘镜像优化’即可获取。
三、资源不足:你的Pod在‘抢车位’
资源不足不只是CPU和内存不够,还包括一些隐形的限制。先看张图,这是我们生产环境某个节点的资源监控:\n\n
\n\n从图中能看到,虽然CPU和内存还有余量,但PID数量已经快满了。这就是很多人忽略的——进程数限制。\n\n\n1. \n 很多团队只设limits不设requests,导致调度器无法准确评估。建议requests设为limits的70%-80%。\n\n2. \n 你的pod可能要求GPU,但调度到了普通节点。或者要求特定污点容忍,但节点有污点。\n\n3. \n 存储配额满了、StorageClass不存在、AccessModes不匹配,都会导致pod卡在Pending。\n\n 上周在咱们的技术群里,有个朋友问‘为什么pod的requests设小了反而启动更快?’ 大家讨论后发现,是他们集群开启了弹性调度,小requests的pod更容易找到‘碎片’资源。你怎么看这种策略?欢迎来稿分享你的观点。
四、配置错误:YAML里的‘魔鬼细节’
YAML配置问题往往最隐蔽,因为语法检查能过,但运行时才报错。分享几个真实案例:\n\n\nyaml\n# 错误示例\nenv:\n - name: DB_HOST\n value: $(POSTGRES_SERVICE) # 应该是$(POSTGRES_SERVICE_HOST)\n\n这种错误在kubectl apply时不会报错,但pod启动时容器内部获取不到正确的值。\n\n\nyaml\nlivenessProbe:\n initialDelaySeconds: 3 # 应用启动需要10秒,3秒后就开始探针\n periodSeconds: 5\n failureThreshold: 1 # 失败1次就重启,太敏感了\n\n结果就是pod陷入CrashLoopBackOff的死循环。\n\n\n以非root用户运行,但没给目录写权限;或者需要特权模式但没配置。\n\n\n1. 使用kubeval或kube-score做yaml静态检查\n2. 先kubectl apply --dry-run=client验证\n3. 复杂配置先用最小化测试\n\n 你遇到过哪些‘看起来对但就是不行’的yaml配置?在评论区分享,我会挑选3个最有价值的案例,整理成《YAML避坑专题》发布。
五、网络问题:Pod的‘社交障碍’
网络问题在微服务架构中特别常见,而且排查难度大。先看一个典型的网络拓扑:\n\n
\n\n\n1. \n Calico/Flannel等CNI插件崩溃,导致pod没有分配到IP。可以通过kubectl get pod -n kube-system检查CNI组件状态。\n\n2. \n 配置了NetworkPolicy但规则太严格,pod无法访问必要的服务。特别是需要访问kube-dns的情况。\n\n3. \n CoreDNS异常或者pod的dnsPolicy配置错误。可以进入pod内部nslookup测试。\n\n\n- 使用netshoot工具镜像快速诊断:kubectl run netshoot --image nicolaka/netshoot --rm -it -- bash\n- 检查iptables规则:特别是kube-proxy生成的规则链\n- 查看kube-dns日志:注意NXDOMAIN和SERVFAIL错误\n\n 我写了一个网络排查的bash脚本合集,可以快速检查常见网络问题。想要的朋友在评论区留言‘需要网络脚本’,我会私信发你GitHub链接。
六、存储挂载:数据卷的‘连接错误’
有状态服务的pod启动,存储问题能占一半。上周我们有个MySQL pod一直起不来,排查过程很有代表性:\n\n\n- 第一天:pod卡在ContainerCreating,describe显示‘Unable to mount volumes’\n- 第二天:检查StorageClass,发现用的是Retain策略,之前的PVC还处于Released状态\n- 第三天:手动删除PV,重新创建,pod正常启动\n\n\n1. \n 可能是StorageClass不存在、provisioner故障、或者云平台配额满了。\n\n2. \n NFS共享目录权限不对、hostPath的宿主机目录不存在、或者fsGroup配置错误。\n\n3. \n subPath指定的目录在volume中不存在,又没配置createIfNotExist。\n\n 咱们社区的@容器大师 分享过一个案例:他们使用local volume,但节点重启后磁盘UUID变了,导致pod无法挂载。解决方案是在StorageClass里用devicePath而不是UUID。\n\n 如果你有存储方面的踩坑经历,欢迎投稿到‘存储专题’,审核通过后可以获得社区认证专家标识和流量扶持。
七、系统组件故障:K8s自身的‘bug’
有时候问题不在你的配置,而在K8s组件本身。这些情况虽然少,但遇到了特别难排查。\n\n\n症状:节点上的pod全部异常,但kubectl get node显示Ready。\n排查:\n- journalctl -u kubelet 看日志\n- systemctl status kubelet 看服务状态\n- 检查/var/lib/kubelet目录权限\n\n\n特别是deployment控制器异常时,你的pod副本数可能无法维持。\n\n\netcd响应慢会导致所有API操作延迟,pod创建请求超时。\n\n\n部署Prometheus监控这些关键指标:\n- kubelet的PLEG延迟\n- etcd的wal_fsync延迟\n- controller manager的工作队列深度\n\n 去年我们遇到一次etcd磁盘IO打满,导致集群几乎瘫痪。后来发现是某个业务频繁list全量pod。加了resourceVersion参数后解决。\n\n 下周六晚上8点,我会在社区直播《K8s组件深度排错》,现场演示如何定位组件级故障。报名方式见文末二维码。
八、我的六步排查法:从混乱到有序
经过这么多坑,我总结了一套标准化排查流程,分享给大家:\n\n\nkubectl get pod -o wide 先确定pod在哪个节点,什么状态。\n\n\nkubectl describe pod <name> Events部分是黄金信息源。\n\n\nkubectl logs <pod-name> [-c container-name] 如果是多容器,每个都要看。\n\n\nkubectl exec -it <pod-name> -- bash 进去看看环境、网络、文件系统。\n\n\n如果怀疑节点问题,kubectl describe node <node-name>。\n\n\n检查kubelet、docker、CNI等组件日志。\n\n\nmermaid\ngraph TD\n A[Pod启动失败] --> B{查看pod状态}\n B -->|Pending| C[检查调度事件]\n B -->|ContainerCreating| D[检查镜像/存储]\n B -->|CrashLoopBackOff| E[查看容器日志]\n C --> F[资源/亲和性]\n D --> G[镜像拉取/卷挂载]\n E --> H[应用启动错误]\n\n\n\n1. k9s - 终端可视化工具\n2. stern - 多pod日志聚合\n3. popeye - K8s集群健康检查\n\n 你平时用什么排查流程?有没有更好的工具推荐?评论区等你分享,我会把大家的建议整理成社区最佳实践文档。
总结
好了,今天关于Kubernetes Pod启动失败的排查就聊到这里。其实写这篇文章的时候,我又想起了刚接触K8s时,一个简单的pod启动问题能折腾一整天的日子。技术就是这样,踩的坑多了,经验就丰富了。\n\n\n1. 把今天的排查步骤保存下来,下次遇到问题按流程走\n2. 评论区分享你的踩坑经历,帮助其他小伙伴避坑\n3. 如果你有更优的解决方案,欢迎投稿到‘故障排查’专栏\n4. 加入我们的技术交流群(扫码下方二维码),群里每天都有实战讨论\n\n 我整理了本文提到的所有工具链接、配置示例和排查脚本,打包成了一个资源包。想要的朋友在评论区留言‘需要资源包’,前50位我会直接发下载链接。\n\n 技术之路,一个人走很快,一群人走更远。期待在评论区看到你的经验和问题,咱们一起把‘科技交流汇’建成技术人真正的交流家园!