Deployment 滚动更新机制详解(企业级面试与运维实战) 📅 发布时间:2026/9/13 15:59:15 👁 浏览次数: 文章目录Deployment 滚动更新机制详解企业级面试与运维实战一、Deployment 如何管理 Pod三层级联关系二、滚动更新完整流程以 3 副本为例第一阶段创建新 RS第二阶段逐步滚动以默认策略 maxSurge25%, maxUnavailable25% 为例第三阶段完成三、滚动更新核心参数面试必考1. maxUnavailable最大不可用数2. maxSurge最大峰值数3. 两个参数如何配合四、滚动更新的状态与控制运维核心技能1. 查看更新进度2. 查看历史版本每个版本对应一个 RS3. 暂停与恢复金丝雀发布的核心手法4. 手动控制更新比例精细灰度5. 回滚五、滚动更新卡住的排查生产环境最高频问题现象排查思路四步定位六、滚动更新故障与应对运维实战场景 1新版本有严重 Bug需要立即止损场景 2读不到新版本日志想先全部切过去再排查场景 3更新过程中想终止并保持现状场景 4Deployment 更新超时自动标记失败七、面试高频追问加分要点1. 滚动更新期间服务真的不中断吗2. 为什么回滚能一键完成3. 如何控制回滚历史的保留数量4. 滚动更新与 Recreate 策略的区别5. 滚动更新对 etcd 和 apiserver 的压力八、一个完整的生产级滚动更新示例Deployment 滚动更新机制详解企业级面试与运维实战Deployment 的滚动更新是 Kubernetes 生产环境中最核心的发布机制。它解决的问题是更新应用时如何做到服务不中断、流量不丢失、故障可回滚。下面我从原理到实操、从面试到排障完整拆解。一、Deployment 如何管理 Pod三层级联关系在深入滚动更新之前先理解 Deployment 的层级结构——这是整个滚动更新的地基Deployment用户操作入口 │ 管理 ▼ ReplicaSet版本快照每个版本对应一个 RS │ 管理 ▼ Pod实际运行容器核心结论Deployment不直接管理 Pod它只管理 ReplicaSet每次修改 Deployment 的 Pod 模板镜像、环境变量等都会创建一个新的 ReplicaSet旧版本对应旧 RS新版本对应新 RS滚动更新就是在新旧两个 RS 之间搬副本数关键标志kubectl get deploy输出的DESIRED是 Pod 总数而每个 RS 的DESIRED是各自的副本数两者之和恒等于 Deployment 的期望副本数更新过程中。二、滚动更新完整流程以 3 副本为例假设当前 Deployment 有 3 个副本镜像版本为nginx:1.19现在要更新到nginx:1.21初始状态 Deployment (replicas3) ├── RS-v1 (nginx:1.19, replicas3) ← 当前版本 └── RS-v2 (nginx:1.21, replicas0) ← 尚未创建 执行 kubectl set image deploy/nginx nginxnginx:1.21第一阶段创建新 RSDeployment (replicas3) ├── RS-v1 (nginx:1.19, replicas0 → 3, maxUnavailable1) └── RS-v2 (nginx:1.21, replicas0 → 1) ← 新 RS 创建先扩容 1 个创建 RS-v2replicas0初始根据maxUnavailable和maxSurge计算可扩缩容的幅度见下文参数详解RS-v2 先扩容到 1因为maxSurge1允许超出期望 1 个第二阶段逐步滚动以默认策略 maxSurge25%, maxUnavailable25% 为例第 1 轮RS-v2: 1, RS-v1: 2总 3 个均在服务中 第 2 轮RS-v2: 2, RS-v1: 1 第 3 轮RS-v2: 3, RS-v1: 0每轮动作新 RS 扩容1创建新版本 Pod等待其就绪Readiness Probe 通过旧 RS 缩容-1等新 Pod 就绪后才删除一个旧版本 Pod循环往复直到所有副本都切到新版本第三阶段完成Deployment (replicas3) ├── RS-v1 (nginx:1.19, replicas0) ← 保留但缩容为 0用于回滚 └── RS-v2 (nginx:1.21, replicas3) ← 当前版本关键点旧 RS不会删除只是缩容到 0。这是为了支持一键回滚新 Pod 必须通过Readiness Probe才会被视为就绪如果新 Pod 一直不就绪滚动更新会卡住不会继续缩容旧 RS三、滚动更新核心参数面试必考滚动更新的节奏由strategy.rollingUpdate下的两个参数控制spec:strategy:type:RollingUpdaterollingUpdate:maxUnavailable:25%# 更新过程中允许最多 25% 的副本不可用maxSurge:25%# 更新过程中允许超出期望副本数最多 25%1. maxUnavailable最大不可用数含义滚动更新过程中允许同时不可用正在被替换的 Pod 最大数量作用保证服务有足够的可用副本避免全部 Pod 同时被替换导致服务中断默认 25%向上取整3 副本 → 允许 1 个不可用3 × 25% 0.75 → 向上取整 12. maxSurge最大峰值数含义滚动更新过程中允许超出期望副本数的最大 Pod 数量作用决定新版本 Pod 可以提前创建多少个加快更新速度默认 25%向上取整3 副本 → 允许超出 1 个3 × 25% 0.75 → 向上取整 13. 两个参数如何配合滚动更新的节奏可以理解为每轮可缩容旧 Pod 数 maxUnavailable 每轮可扩容新 Pod 数 maxSurge极端场景举例配置效果maxUnavailable: 1, maxSurge: 1一次只更新 1 个 Pod更新速度慢但最安全maxUnavailable: 100%, maxSurge: 0%先缩容所有旧 Pod全部不可用再创建新 Pod →等价于 Recreate 策略先删后建maxUnavailable: 0%, maxSurge: 100%先创建全部新 Pod峰值翻倍消耗双倍资源全部就绪后再删旧 Pod → 零停机但资源占用高蓝绿发布思想四、滚动更新的状态与控制运维核心技能1. 查看更新进度# 查看更新状态会阻塞直到完成或超时kubectl rollout status deploy/nginx# 输出示例# Waiting for deployment nginx rollout to finish: 1 out of 3 new replicas have been updated...# deployment nginx successfully rolled out2. 查看历史版本每个版本对应一个 RSkubectl rollouthistorydeploy/nginx# 输出示例# REVISION CHANGE-CAUSE# 1 none # 可通过 --record 记录变更原因# 2 kubectl set image deploy/nginx nginxnginx:1.21注意CHANGE-CAUSE来自 Deployment 的metadata.annotations.kubernetes.io/change-cause。K8s v1.26 已移除--record参数需手动添加 annotationkubectl annotate deploy/nginx kubernetes.io/change-cause升级nginx到1.213. 暂停与恢复金丝雀发布的核心手法暂停更新过程中暂停让新旧版本并存一段时间验证新版本稳定性后再继续# 触发更新后立即暂停kubectlsetimage deploy/nginxnginxnginx:1.21 kubectl rollout pause deploy/nginx# 此时RS-v2 创建了 1 个新 Pod 并停止其余 2 个还在旧版本# 相当于手动控制的金丝雀发布恢复kubectl rollout resume deploy/nginx# 继续完成剩余的滚动更新使用场景先更新 1 个 Pod 验证日志/监控无异常再恢复继续全量更新。4. 手动控制更新比例精细灰度通过直接修改maxSurge和maxUnavailable可以控制每次更新的 Pod 数量# 每次只更新 1 个 Podkubectl patch deploy/nginx-p{spec:{strategy:{rollingUpdate:{maxSurge:1,maxUnavailable:0}}}}# 或kubectl edit deploy/nginx# 修改后保存会自动触发一次滚动更新5. 回滚# 回滚到上一个版本kubectl rollout undo deploy/nginx# 回滚到指定版本kubectl rollout undo deploy/nginx --to-revision1# 查看回滚进度kubectl rollout status deploy/nginx回滚原理让旧 RS 重新扩容、新 RS 缩容和正向更新的过程完全对称。五、滚动更新卡住的排查生产环境最高频问题现象kubectl rollout status长时间停留在Waiting for deployment nginx rollout to finish: 1 out of 3 new replicas have been updated...排查思路四步定位Step 1查看 Deployment 状态与事件kubectl describe deploy/nginx重点看Conditions字段中的Progressing和AvailableConditions:Type Status Reason----------------Available True MinimumReplicasAvailable Progressing False ProgressDeadlineExceeded# ← 更新超时失败Step 2查看新旧 RS 的副本分布与状态kubectl get rs-lappnginx# NAME DESIRED CURRENT READY AGE# nginx-abc 3 3 3 1h # 旧 RS# nginx-def 2 2 0 5m # 新 RSREADY0 → 问题在这里Step 3查看新 RS 的 Pod 状态与事件kubectl get pods-lappnginx|grepnginx-def kubectl describe pod/nginx-def-xxxxxStep 4定位根因现象根因Pod 一直ContainerCreating镜像拉取失败私有仓库认证、存储挂载失败PVC 未绑PodRunning但READY 0/1Readiness Probe 失败最常见—— 端口探测不通、健康检查路径返回非 200PodCrashLoopBackOff新版本启动即崩溃环境变量缺失、配置错误、依赖服务未就绪新 Pod 一直 Pending资源不足、节点亲和性不满足最典型场景新版本镜像有 bug启动后 Readiness Probe 一直失败 → 新 Pod 永远不就绪 → 滚动更新永远不会继续缩容旧 RS → 服务保持旧版本可用这是滚动更新的设计优点宁可卡住也不中断。六、滚动更新故障与应对运维实战场景 1新版本有严重 Bug需要立即止损# 紧急回滚最快速kubectl rollout undo deploy/nginx# 或直接改回旧镜像kubectlsetimage deploy/nginxnginxnginx:1.19场景 2读不到新版本日志想先全部切过去再排查# 将 maxUnavailable 设为 100%等价于先删后建kubectl patch deploy/nginx--typejson\-p[{op: replace, path: /spec/strategy/rollingUpdate/maxUnavailable, value: 100%}]# 此时会立即缩容所有旧 Pod全部切换到新版本# 注意这会短暂中断服务等价于 Recreate 策略场景 3更新过程中想终止并保持现状# 暂停滚动更新kubectl rollout pause deploy/nginx# 此时新旧版本并存保持当前状态不再变化# 适合先停下来观察一下新版本表现的场景场景 4Deployment 更新超时自动标记失败默认progressDeadlineSeconds60010分钟超过后 Deployment 被标记为ProgressingFalse但不会自动回滚只是停止更新。需要手动介入# 查看失败原因kubectl describe deploy/nginx|grep-A5Conditions# 手动回滚kubectl rollout undo deploy/nginx七、面试高频追问加分要点1. 滚动更新期间服务真的不中断吗不完全是。关键取决于Readiness Probe 是否配置正确——新 Pod 就绪后才加入 Service 的 Endpoints流量才会切过去Pod 终止时是否优雅——旧 Pod 收到 SIGTERM 后是否能在宽限期内完成排空处理完当前请求再退出面试表述“滚动更新不中断服务的前提是配置了正确的 Readiness Probe 和 preStop Hook。如果没有 Readiness Probe新 Pod 刚启动就会被加入 Endpoints此时容器可能还没真正就绪会短暂返回 5xx。”2. 为什么回滚能一键完成因为每次更新都会留下一个对应的 RS保留完整的历史 Pod 模板。回滚只是把目标 RS 重新扩容、当前 RS 缩容——本质也是一次滚动更新只是方向相反。3. 如何控制回滚历史的保留数量通过spec.revisionHistoryLimit默认 10。超过数量的旧 RS 会被 GC 清理但注意缩容为 0 的 RS 不会被删除保留用于回滚只有超过revisionHistoryLimit的 RS 才会被彻底删除。4. 滚动更新与 Recreate 策略的区别RollingUpdate默认Recreate服务中断通常无前提是配置正确有先删后建资源消耗可能瞬时超出期望副本数maxSurge无额外消耗适用场景无状态服务、微服务有状态服务数据库等无法并存的场景更新速度较慢受 maxSurge/maxUnavailable 控制快5. 滚动更新对 etcd 和 apiserver 的压力每次滚动更新会触发大量 Pod 创建/删除事件这些事件会写入 etcd 并广播给所有控制器。大规模集群数百节点、数千 Pod同时滚动更新时需要控制更新速率否则可能压垮 apiserver。优化手段分批更新先更新部分节点或部分 Deployment使用maxSurge: 1, maxUnavailable: 0保守配置结合PDBPodDisruptionBudget保护关键服务的副本可用性八、一个完整的生产级滚动更新示例apiVersion:apps/v1kind:Deploymentmetadata:name:nginxannotations:kubernetes.io/change-cause:升级nginx到1.21修复安全漏洞spec:replicas:5revisionHistoryLimit:5# 保留最近 5 个历史版本strategy:type:RollingUpdaterollingUpdate:maxUnavailable:1# 最多 1 个副本不可用保守maxSurge:2# 最多超出 2 个副本加快速度selector:matchLabels:app:nginxtemplate:metadata:labels:app:nginxspec:terminationGracePeriodSeconds:30# 优雅终止等待时间containers:-name:nginximage:nginx:1.21ports:-containerPort:80readinessProbe:# 就绪探针关键httpGet:path:/healthzport:80initialDelaySeconds:5periodSeconds:5lifecycle:preStop:# 优雅下线先摘流量再停止exec:command:[/bin/sh,-c,sleep 5]执行更新# 1. 触发更新kubectl apply-fdeployment.yaml# 2. 监控进度kubectl rollout status deploy/nginx# 3. 确认完成后查看版本kubectl rollouthistorydeploy/nginx# 4. 如果出问题回滚kubectl rollout undo deploy/nginxpreStop Hook 的作用当 Pod 被终止时先执行sleep 5给 kube-proxy 时间从 Endpoints 中移除该 Pod 的 IP确保不再有新流量进来然后才收到 SIGTERM 退出。这是避免正在处理的请求被中断的关键。