一、为什么我的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"

这种情况就像你家路由器不断重启——肯定哪里出问题了。常见重启诱因包括:

  1. 容器进程崩溃(比如Java应用OOM)
  2. 健康检查失败(Liveness探针罢工)
  3. 资源不足(CPU/内存争抢)
  4. 配置错误(挂载点不存在)

二、抽丝剥茧——系统性排查六步法

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
解决方案

  1. 增加Pod内存限制
  2. 使用Redis替代本地缓存
  3. 添加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
解决方案

  1. 调整timeoutSeconds为10
  2. 实现轻量级健康检查端点
  3. 添加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重启问题望闻问切。关键是要建立系统化的排查思维:

  1. 先看现象(Events日志)
  2. 再查配置(探针、资源)
  3. 后分析代码(OOM、死锁)
  4. 最后考虑环境(节点、存储)

记住,没有无缘无故的重启,只有还没发现的真相。当你下次看到Pod在跳舞时,不妨按照这个指南来段排查华尔兹。