theme: default themeName: "默认主题" title: "K8s Pod反复重启业务崩溃?掌握这四步排查思路,彻底搞定不断重启"
前言
Pod反复重启是Kubernetes日常运维中最让人头疼的问题之一。它不像服务器宕机那样一眼就看出问题,而是偷偷摸摸地restart、restart、再restart,等你发现时,业务可能已经断断续续不可用了。很多新手面对Pod不断重启,第一反应是重启大法——删掉Pod重建,但往往是治标不治本。本文给你一套系统化的排查思路,下次遇到Pod重启问题,照着流程走一遍,保管药到病除。
Pod重启的四种原因
在动手排查之前,先搞清楚Pod为什么会重启。Kubernetes中Pod的重启由Liveness Probe(存活探针)失败触发,总结下来无非四种原因:
应用自身崩溃:程序抛出未捕获的异常、OOM被杀、收到SIGTERM/SIGKILL信号 健康检查失败:Liveness/Readiness探针连续多次检测失败 依赖服务不可用:数据库/缓存/下游API连接超时/拒绝 资源不足被驱逐:Node资源紧张时K8s会主动驱逐Pod排查第一步:查看Pod状态和事件
最直接的信息来源是kubectl describe,百分之八十的问题在这里就能找到答案:
kubectl describe pod -n
重点关注这几个区域:
Events:事件列表,看最后几行Events:
Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 5m default-scheduler Successfully assigned default/myapp-xyz to node-1 Normal Pulling 5m kubelet Pulling image "myapp:latest" Normal Pulled 4m kubelet Successfully pulled image "myapp:latest" Normal Created 4m kubelet Created container myapp Normal Started 4m kubelet Started container myapp Warning BackOff 2m kubelet Back-off restarting failed container
看到`Back-off restarting failed container`就说明容器启动后失败了,K8s在自动重试。这是第一个信号——容器根本没有正常跑起来。
排查第二步:查看容器日志
容器启动失败了,那就看日志:
# 查看当前容器日志
kubectl logs -n
如果Pod重启过,加上--previous看上次失败的日志
kubectl logs -n --previous
日志会告诉你具体是什么错误。常见几类:
端口绑定失败:listen tcp 0.0.0.0:8080: bind: address already in use
端口被占用了,可能是程序配置问题或者同一Pod内多个容器端口冲突。
配置文件找不到:Error: failed to start container ... Error response ... "container "myapp" in pod "xxx": not found: configmap "app-config" not found"
依赖的ConfigMap或Secret没挂载进来。
数据库连接失败:panic: failed to connect to database: dial tcp 10.244.1.5:5432: connect: connection refused
依赖的服务还没ready或者网络不通。
OOMKilled:如果日志里没内容,直接看容器退出码:
kubectl get pod -n -o jsonpath='{.status.containerStatuses[].lastState.terminated.exitCode}'
退出码137 = 收到SIGKILL信号,通常是OOM。退出码143 = 收到SIGTERM,优雅退出。
排查第三步:检查资源限制和探针配置
如果日志看起来正常,容器也能启动,但运行一段时间后就挂——可能是资源不够被OOM,或者健康检查失败。
查看资源限制:kubectl get pod -n -o jsonpath='{.spec.containers[].resources}'
典型的问题配置:
resources:
requests: memory: "128Mi" cpu: "100m" limits: memory: "128Mi" # 刚好够用,一有波动就OOM cpu: "100m"
内存request设置得太紧,一有点内存波动就触发OOMKilled。解决:适当放宽limits,或者检查应用是否有内存泄漏。
检查探针配置:livenessProbe:
httpGet: path: /healthz port: 8080 initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 3 # 连续3次失败才重启 readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5
问题场景:
- initialDelaySeconds设置太短,容器还没启动完就检测,导致连续失败→重启
- /healthz接口响应慢,超时失败
- 依赖的数据库不可用时,/healthz返回失败,触发重启
排查第四步:检查依赖和调度
如果前三步都没问题,那问题可能在Pod依赖上。
查看Pod依赖是否Ready:kubectl get pods -n -o wide | grep
检查网络连通性:
# 进入Pod内部测试网络
kubectl exec -it -n -- sh
然后
nc -zv 8080 ping
查看Node资源情况:
kubectl describe node
重点看Allocatable和Allocated resources部分,如果内存或CPU已经分配了90%以上,说明Node资源紧张,Pod可能被驱逐。
真实案例:Java应用OOM导致无限重启
一个Spring Boot应用部署到K8s后,Pod一直在重启。describe看到Back-off日志,logs看到OOMKilled。
排查过程:1. `kubectl logs --previous` 没有输出(OOM时应用直接被kill) 2. 查看JVM内存参数:-Xmx512m,而Pod的memory limit也是512m 3. 问题在于:JVM堆内存512m + Metaspace + 线程栈 + 容器开销 > 512m limit,一超过就被OOM Kill
解决方案:- 将memory limit调大到768m
- 或者调整JVM参数:-XX:MaxRAMPercentage=70.0,让JVM自动按容器限制调整堆大小
预防Pod重启的最佳实践
1. 合理设置资源限制:requests不能太小,limits要比requests大50%-100% 2. 正确配置探针:initialDelaySeconds要大于应用启动时间,failureThreshold别太低 3. 添加优雅停止:处理SIGTERM信号,给业务留出收尾时间 4. 开启Pod Disruption Budget:保证滚动更新时最小可用实例数 5. 监控告警:记录Pod重启次数,设置阈值告警
# 优雅停止示例
lifecycle: preStop: exec: command: - /bin/sh - -c - "sleep 10"
结语
Pod反复重启排查的核心就四步:看事件→看日志→查资源→查依赖。80%的问题在第一步describe就能发现线索,别一上来就删Pod重建,那只会掩盖问题而不是解决问题。下次遇到Pod重启,照着这个流程走一遍,保证你不再是那个只会重启的运维。
看完还有什么疑问吗?
如果文章没有覆盖到你的情况,欢迎联系我们咨询——免费解答,说清楚再决定要不要服务。
📞 服务热线:13708730161 💬 微信:eyc1689 📧 邮箱:service@eycit.com 🌐 https://www.eycit.com
易云城IT服务,您身边的IT专家。