Administrator
Administrator
发布于 2026-10-28 / 0 阅读
0
0

Kubernetes 故障排查(16):Deployment 发布卡住:从 ProgressDeadlineExceeded 到可验证回滚

面向初级运维,使用 Linux 节点和稳定 Kubernetes API。命令按 Bash 编写。本文为教学故障场景,日志及结果为示意,不冒充生产实测;执行前确认 context、命名空间和权限。

一、遭遇情况:发布命令超时,但线上旧版本还在服务

执行新版本发布后,kubectl rollout status 长时间等待,最后超时。集群里同时有新旧 ReplicaSet,新 Pod 无法运行,旧 Pod 却仍然 Ready。

本篇案例是新镜像标签不存在。滚动发布策略要求保留旧可用副本,因此没有立即停掉旧版本。需要分清“新版本未完成”和“旧业务已全部中断”,不能只看一个失败命令判断影响。

二、原因分析:Deployment 管的是期望与进度

Deployment 更新 Pod 模板后创建新 ReplicaSet,并依据 maxSurge、maxUnavailable 等规则替换副本。新副本如果拉镜像、调度、探针或应用启动失败,进度就可能停住。

发布失败到回滚验收的检查路径

客户端 --timeout 是本次等待多久,progressDeadlineSeconds 是控制器判断发布进度的条件之一,两者不是同一个计时器。ProgressDeadlineExceeded 通常提供失败状态,不意味着核心 Deployment 控制器一定自动回滚。

三、排查思路:从控制器追到新 Pod

kubectl get deployment 目标部署 -n 目标命名空间 -o wide
kubectl describe deployment 目标部署 -n 目标命名空间
kubectl get replicaset -n 目标命名空间
kubectl get pods -n 目标命名空间 -o wide
kubectl rollout history deployment/目标部署 -n 目标命名空间

核对 generation 与 observedGeneration、期望副本、updated/ready/available 数量及 conditions。再按 ownerReferences、标签和模板定位新 ReplicaSet 的 Pod,继续读其具体事件。

新 Pod 若 Pending 看第 3 篇,镜像失败看第 4 篇,崩溃看第 6 篇,未就绪看第 8 篇。Deployment 进度是上层结果,根因经常仍在某一个 Pod 的具体阶段。

四、实践:先部署一个可用版本

保存 kt16-rollout.yaml,在测试集群应用:

apiVersion: v1
kind: Namespace
metadata:
  name: kt16
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: kt16
spec:
  replicas: 2
  minReadySeconds: 5
  progressDeadlineSeconds: 60
  revisionHistoryLimit: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: nginx:stable-alpine
          readinessProbe:
            httpGet:
              path: /
              port: 80
---
apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: kt16
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80
kubectl apply -f kt16-rollout.yaml
kubectl rollout status deployment/web -n kt16 --timeout=180s
kubectl rollout history deployment/web -n kt16

确认初始两个副本可用,再注入一个不存在的镜像标签:

kubectl set image deployment/web web=nginx:kt16-missing-release -n kt16
kubectl rollout status deployment/web -n kt16 --timeout=90s
kubectl get deployment,replicaset,pod -n kt16
kubectl describe deployment web -n kt16

预期新副本拉取失败,旧副本继续满足可用要求。具体进度状态出现时间受控制器观察和环境影响,命令超时本身不能代替 conditions 核对。

五、修复实践:决定继续修新版本,还是回到已知模板

如果只是可明确修复的镜像引用,可以发布正确版本继续前进。若需要快速恢复到已知 Pod 模板,先查看历史,再对这个实验执行:

kubectl rollout history deployment/web -n kt16
kubectl rollout undo deployment/web -n kt16
kubectl rollout status deployment/web -n kt16 --timeout=180s
kubectl get deployment,replicaset,pod -n kt16

本实验只有初始可用版本和错误版本,undo 回到上一个模板。真实环境有多次修改时,应先核对目标 revision,必要时明确 --to-revision,不要默认“上一版”一定可用。

回滚 Deployment 主要恢复历史 Pod 模板,不会自动回滚数据库结构、外部系统、Service 或被原地修改的 ConfigMap 内容。镜像标签可变时,历史同名标签也不保证内容未变,所以生产应记录可追踪的版本或 digest。

六、验证:控制器成功只是第一层

核对实际镜像、可用副本、EndpointSlice 和真实业务请求。可以从测试客户端访问 kt16 的 web Service,确认旧可用路径或恢复后的路径正常;只看到 rollout completed,还没有完整验证业务。

maxUnavailable: 0 有助于表达发布时的可用性目标,但仍需要额外容量、健康旧副本和合理探针。它不是面对节点故障也绝不会中断的保证。

PDB 主要参与相应的自愿中断保护,Deployment 自身滚动更新不是简单由 PDB 代替 maxUnavailable 管理。不要为了让发布“动起来”随意删除 PDB、降低探针或把所有旧副本强删。

七、总结:恢复动作也需要证据闭环

先确认影响 → 找出新旧副本 → 读取新副本根因 → 选择继续修复或回滚 → 验证版本与真实请求 → 同步发布源。GitOps 场景还要修正期望配置,避免刚恢复的版本再次被同步成错误状态。

到这里,整套系列形成了一条可复用路径:客户端访问与授权 → 对象和事件 → 容器运行 → 服务网络 → 存储与节点 → 发布恢复。先定位失败阶段,再做最小变更,比反复删除和重启更容易得到可信结论。

官方参考


上一篇 · 系列目录


评论