一、为什么我的Pod总在跳舞?——重启现象初探
每次查看Kubernetes集群状态时,发现有些Pod像跳踢踏舞一样不断重启,这到底是怎么回事呢?咱们先来看个典型场景:
# 技术栈:Kubernetes v1.22+
# 一个总在重启的Pod状态示例(通过kubectl describe pod查看)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulled 23s (x5 over 2m) kubelet Container image "nginx:1.14" already present
Warning BackOff 18s (x6 over 2m) kubelet Back-off restarting failed container
Normal Pulling 5s (x6 over 3m) kubelet Pulling image "nginx:1.14"
这种情况就像你家路由器不断重启——肯定哪里出问题了。常见重启诱因包括:
- 容器进程崩溃(比如Java应用OOM)
- 健康检查失败(Liveness探针罢工)
- 资源不足(CPU/内存争抢)
- 配置错误(挂载点不存在)
二、抽丝剥茧——系统性排查六步法
2.1 第一步:查看Pod的"体检报告"
# 获取Pod详细状态(重点关注Events部分)
kubectl describe pod shopcart-7d64f7569b-2zqj5 -n production
# 查看容器日志(--tail限制行数,-c指定容器)
kubectl logs --tail=100 shopcart-7d64f7569b-2zqj5 -c main-app
2.2 第二步:检查健康探针配置
# 有问题的探针配置示例
livenessProbe:
exec:
command: ["curl", "http://localhost:8080/health"]
initialDelaySeconds: 0 # 立即开始检查
periodSeconds: 5 # 检查间隔太短
failureThreshold: 1 # 失败1次就重启
# 建议调整为:
livenessProbe:
httpGet:
path: /health
port: 8080
httpHeaders: ["X-Health-Check: true"]
initialDelaySeconds: 30 # 给应用启动留时间
periodSeconds: 15
failureThreshold: 3 # 连续失败3次才重启
2.3 第三步:资源限制排查
# 查看Pod资源使用情况
kubectl top pod mysql-primary-0 -n database
# 检查是否被OOMKilled
kubectl get pod -o json | jq '.items[] | select(.status.containerStatuses[].lastState.terminated.reason=="OOMKilled")'
2.4 第四步:存储卷问题排查
# 检查挂载点状态
kubectl exec -it file-server-0 -- df -h
# 查看PersistentVolumeClaim状态
kubectl get pvc -n storage
三、经典故障现场还原
3.1 案例一:内存泄漏引发的血案
// 技术栈:Spring Boot 2.5 + Kubernetes
// 有内存泄漏的代码片段
@RestController
public class CacheController {
private static Map<String, Object> cache = new HashMap<>();
@GetMapping("/cache")
public String cacheItem(@RequestParam String key) {
// 没有设置缓存淘汰策略
cache.put(key, new byte[1024 * 1024]); // 每次请求分配1MB
return "Cached!";
}
}
问题现象:Pod每10分钟重启一次,kubelet日志显示OOMKilled
解决方案:
- 增加Pod内存限制
- 使用Redis替代本地缓存
- 添加JVM参数:-XX:+HeapDumpOnOutOfMemoryError
3.2 案例二:健康检查配置不当
# 技术栈:Flask + Kubernetes
# app.py 健康检查接口
@app.route('/health')
def health():
time.sleep(8) # 数据库查询慢导致响应延迟
return "OK", 200
# deployment.yaml片段
livenessProbe:
httpGet:
path: /health
port: 5000
timeoutSeconds: 1 # 超时时间设置过短
问题现象:Pod启动后立即进入CrashLoopBackOff
解决方案:
- 调整timeoutSeconds为10
- 实现轻量级健康检查端点
- 添加readinessProbe区分检查类型
四、防患于未然——最佳实践指南
4.1 资源限制黄金法则
resources:
requests:
cpu: "500m" # 保证基本资源
memory: "512Mi"
limits:
cpu: "2" # 最高不超过2核
memory: "2Gi" # 限制内存上限
4.2 优雅终止配置
# 确保完成现有请求再终止
terminationGracePeriodSeconds: 60
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 30; nginx -s quit"]
4.3 日志收集方案
# 使用sidecar模式收集日志
kubectl logs -f myapp-log-collector -n monitoring
五、高阶排查工具链
5.1 使用kubectl-debug直接诊断
# 安装调试工具
kubectl krew install debug
# 进入故障Pod诊断
kubectl debug -it shopcart-7d64f7569b-2zqj5 --image=nicolaka/netshoot
5.2 Prometheus监控方案
# 查询重启次数统计
count_over_time(kube_pod_container_status_restarts_total[1h])
六、总结与思考
经过上述排查流程,我们可以像老中医一样对Pod重启问题望闻问切。关键是要建立系统化的排查思维:
- 先看现象(Events日志)
- 再查配置(探针、资源)
- 后分析代码(OOM、死锁)
- 最后考虑环境(节点、存储)
记住,没有无缘无故的重启,只有还没发现的真相。当你下次看到Pod在跳舞时,不妨按照这个指南来段排查华尔兹。
评论