CrashLoopBackOff状态根因定位
Kubernetes集群运维中,Pod陷入CrashLoopBackOff是最常见的故障之一。这个状态意味着容器启动后反复崩溃退出,kubelet不断尝试重启。排查的第一步是获取容器退出码和日志,而不是盲目修改配置。
查看Pod状态和事件:
kubectl get pod <pod-name> -n <namespace> -o wide
kubectl describe pod <pod-name> -n <namespace>
describe输出中的Last State字段会显示上一次退出的原因和退出码。退出码137表示OOMKilled(内存溢出),1表示应用错误,2表示命令不存在。不同退出码指向不同的排查方向。
获取容器日志:
# 当前容器日志
kubectl logs <pod-name> -n <namespace>
# 上一次崩溃容器的日志(关键!)
kubectl logs <pod-name> -n <namespace> --previous
--previous参数是排查CrashLoopBackOff最重要的开关,它获取的是上一次崩溃容器的日志,包含真正的错误信息。当前容器可能还在启动过程中,日志尚未输出就又崩了,这时当前日志反而是空的。
OOMKilled与资源限制调优
退出码137(OOMKilled)在Java/JVM类应用中最为常见。JVM默认堆内存上限根据容器cgroup限制自动计算,但容器内存limit设置不当会导致JVM申请的堆内存超过limit被杀。排查步骤:
# 查看Pod的resources配置
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[0].resources}'
# 查看节点实际内存使用
kubectl top node
kubectl top pod -n <namespace>
修复方案是在Deployment中合理设置resources,确保limit大于JVM最大堆加上非堆内存的开销:
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "2000m"
对于JVM应用,还需要显式设置JVM参数,不让它自行推断堆大小:
env:
- name: JAVA_OPTS
value: "-Xms512m -Xmx1536m -XX:+UseG1GC"
-Xmx设置为limit的70-75%,留出空间给Metaspace、线程栈和直接内存。这个比例在不同JDK版本间有差异,建议通过压测确认。
NetworkPolicy导致的服务不可达
集群启用NetworkPolicy后,服务间调用失败是高频故障。现象是DNS解析正常,但TCP连接超时或被拒绝。排查思路是逐层验证:Pod网络到Service网络再到NetworkPolicy。
# 在客户端Pod中测试连通性
kubectl exec -it <client-pod> -n <namespace> -- sh
curl -v http://<service-name>.<namespace>.svc.cluster.local:8080
# 检查NetworkPolicy
kubectl get networkpolicy -n <namespace>
kubectl describe networkpolicy <policy-name> -n <namespace>
NetworkPolicy的常见问题有两种:一是ingress规则漏掉了调用方,二是namespace匹配条件写错。示例:允许同一namespace的Pod访问,但跨namespace调用被拒绝。修复方式是添加正确的ingress规则:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend
namespace: backend
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend
podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
注意namespaceSelector匹配的是namespace的label,不是namespace名称。需要在目标namespace上打label:kubectl label namespace frontend name=frontend。这个细节经常被忽略。
镜像拉取失败与ImagePullBackOff
私有镜像仓库环境下ImagePullBackOff也很常见。根因主要有三类:认证失败、镜像标签不存在、网络不通。快速定位:
kubectl describe pod <pod-name> -n <namespace> | grep -A5 Events
事件信息中会明确提示Failed to pull image和具体原因。认证问题需要检查imagePullSecrets是否正确配置:
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password=pass \
--docker-email=user@example.com \
-n <namespace>
在Deployment的spec.template.spec中引用:
imagePullSecrets:
- name: regcred
如果Secret的namespace与Pod不在同一namespace,Pod无法引用,这也是一个常见错误。
集群故障排查的标准化流程
将以上各类故障的排查步骤标准化,可以大幅缩短MTTR(平均恢复时间)。推荐的排查顺序是:先看Pod状态(Pending/Running/CrashLoop)再查Events(describe输出底部)再查日志(logs –previous)再查配置(resources/networkpolicy/imagePullSecrets)再查节点资源(top node/describe node)。每一步都有明确的命令和判断标准,不需要猜测。
日常运维中建议配置 kubelet 的 –event-ttl 参数延长事件保留时间(默认1小时太短),并在集群中部署event-exporter将事件持久化到ES或Loki,方便事后回溯。这些投入在故障发生时会体现出价值——有完整的事件时间线,远比靠记忆还原故障过程要高效。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/kubernetes-ji-qun-gu-zhang-pai-cha-shi-zhan/