面向初级运维,使用 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 场景还要修正期望配置,避免刚恢复的版本再次被同步成错误状态。
到这里,整套系列形成了一条可复用路径:客户端访问与授权 → 对象和事件 → 容器运行 → 服务网络 → 存储与节点 → 发布恢复。先定位失败阶段,再做最小变更,比反复删除和重启更容易得到可信结论。