Pod异常退出的常见信号
Kubernetes集群里Pod莫名其妙重启或消失,这是SRE日常最头疼的问题之一。表现多种多样:CrashLoopBackOff、OOMKilled、Error状态、被驱逐。每种信号对应不同的排查路径,一上来就查日志效率很低,正确的做法是先看事件再查日志,先看状态再看配置。
Step 1:确认Pod当前状态
kubectl get pods -n production -o wide
# 输出示例
NAME READY STATUS RESTARTS AGE IP NODE
api-server-6b8f4d... 0/1 CrashLoopBackOff 7 18m 10.244.1.55 node-02
关键看STATUS和RESTARTS。CrashLoopBackOff说明容器反复启动失败,RESTARTS=7说明已经重启7次,每次间隔会指数退避。
Step 2:查看Pod事件定位触发原因
kubectl describe pod api-server-6b8f4d... -n production
重点关注Events部分,这里记录了Pod生命周期中的关键事件:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning BackOff 2m (x6 over 8m) kubelet Back-off restarting failed container
Normal Pulling 3m kubelet Pulling image "registry/api:v2.3.1"
Normal Started 3m1s kubelet Started container api-server
Warning OOMKilled 2m59s kubelet Container api-server exceeded memory limit
这条OOMKilled事件直接说明了退出原因:内存超限被内核杀掉。接下来就要看资源配额配置和实际内存消耗。
Step 3:容器日志排查
如果当前Pod还在运行(或刚重启过),先看容器标准输出:
# 当前容器的日志
kubectl logs api-server-6b8f4d... -n production --tail=200
# 看上一个崩溃容器的日志(关键!)
kubectl logs api-server-6b8f4d... -n production --previous --tail=200
--previous参数查看的是上一次容器崩溃前的日志,这对于CrashLoopBackOff场景极其重要,因为当前容器可能刚启动日志还很少。
常见日志中的致命信号:
java.lang.OutOfMemoryError→ JVM堆内存不足FATAL: sorry, too many clients already→ 数据库连接池耗尽signal: killed→ OOMKilled或被手动killexec format error→ 镜像架构不匹配(ARM镜像跑到x86节点)
OOMKilled问题深度分析
OOMKilled是最常见的异常退出类型。排查步骤:
# 查看Pod资源配额
kubectl get pod api-server-6b8f4d... -n production -o jsonpath='{.spec.containers[0].resources}'
# 查看实际内存使用
kubectl top pod api-server-6b8f4d... -n production
一个典型的错误配置:
resources:
requests:
memory: "256Mi"
limits:
memory: "256Mi" # 没有余量,稍微一波动就被杀
修正方案:requests和limits要有梯度,limits留出30-50%缓冲:
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
同时检查JVM参数,Java应用在容器中必须设置-XX:MaxRAMPercentage=75.0,让JVM感知容器内存限制,而不是用-Xmx硬编码。
CrashLoopBackOff的排查路径
CrashLoopBackOff是容器启动后立即退出导致的循环。常见原因和对应的检查命令:
1. 启动命令错误:Dockerfile里ENTRYPOINT/CMD写错,或K8s的command覆盖了镜像默认启动命令。
# 检查Pod的command配置
kubectl get pod api-server-6b8f4d... -o jsonpath='{.spec.containers[0].command}'
2. 配置缺失:ConfigMap或Secret没挂载,程序读到空配置崩溃。
# 查看挂载情况
kubectl get pod api-server-6b8f4d... -o jsonpath='{.spec.containers[0].volumeMounts}'
3. 健康检查配置过严:livenessProbe超时或阈值太短,应用还在启动就被判定不健康杀了。
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5 # 应用启动需要30秒,5秒就开始探活
periodSeconds: 3 # 每3秒探一次,太激进
failureThreshold: 1 # 失败1次就杀,容错太低
修正:启动慢的应用,initialDelaySeconds要大于P95启动时间,failureThreshold至少3。
Evicted Pod的处理
节点资源不足(磁盘、内存)时,kubelet会驱逐低优先级Pod。查看原因:
kubectl describe pod <pod-name> -n production | grep -A5 "Events"
# 常见驱逐原因
# DiskPressure: 节点磁盘使用超85%
# MemoryPressure: 节点内存使用超阈值
# pid.available: 节点PID耗尽
处理方案:检查节点资源kubectl describe node node-02,清理不用的镜像和日志,给节点打污点隔离,或者加资源配额保证关键Pod不被驱逐。
搭建Pod异常监控告警
靠人肉巡检太慢,用Prometheus规则自动告警:
# prometheus-rules.yaml
groups:
- name: pod-alerts
rules:
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0
for: 5m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.pod }} 不断重启"
- alert: PodOOMKilled
expr: kube_pod_container_status_terminated_reason{reason="OOMKilled"} == 1
for: 1m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.pod }} 被OOMKilled"
告警触发后,SRE团队按上面的流程定位:先describe看事件,再logs看日志,配合top看资源,三步定位绝大多数Pod异常。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/kubernetespod-yi-chang-tui-chu-pai-cha-quan-liu-cheng-cong/