滚动更新是一种不停机逐步替换旧版本为新版本的部署方式。对 HelloWorld 示例,核心要点包括:准备可回滚镜像、设计健壮的健康检查、分批推送与流量控制、实时监控与快速回退机制,确保用户请求不中断且有可观测性和回滚路径。


直观理解:把更新想成换灯泡
先说个比喻,别急着跳进命令行。我常把滚动更新比作“换走廊的灯泡”——你不会一下把整栋楼的灯都拔掉再换新的,而是一盏一盏地换,换好之后确认亮着再换下一盏。这样即便某个新灯泡有问题,也只影响少数人,能快速换回旧灯泡。
为什么要做滚动更新
- 不影响可用性:用户请求不中断,尤其对在线服务至关重要。
- 快速定位问题:分批替换能把故障范围缩小到少量实例,便于排查。
- 支持自动化回滚:配合健康检查和监控,可以在异常时自动或半自动回退。
- 可观测性强:分批发布让你可以看到每批的指标变化。
基本概念和术语
- 实例(replica):运行同一个应用的一个进程或容器。
- 批次(batch)/步长(maxUnavailable/maxSurge):每次替换的实例数量。
- 健康检查(liveness/readiness):判断新实例是否可接流量的关键。
- 回滚(rollback):当更新出现问题,恢复到上一个已知稳定版本。
常见的发布策略对比
| 策略 | 优点 | 缺点 |
| 滚动更新 | 平滑、简单、无停机 | 需要良好健康检查,无法完全隔离新版本 |
| 蓝绿部署 | 切换瞬间完成,回滚简单 | 资源占用翻倍,切换点可能有短暂风险 |
| 金丝雀发布 | 精准观测、风险最小化 | 复杂度高,需要精细流量控制 |
为 HelloWorld 设计一个滚动更新流程(思路)
下面按费曼法把概念讲清楚,然后给出可操作步骤。目标是:任何人照着做,能把一个简单的 HelloWorld 应用在无感知的情况下更新。
前提条件
- 你有一个容器化的 HelloWorld 镜像(例如 hello:v1、hello:v2)。
- 运行环境支持滚动更新(常见:Kubernetes、Docker Swarm、某些 PaaS)。本文以 Kubernetes 为主,也给出纯容器或反向代理场景的思路。
- 已设置监控(响应时间、错误率)和日志收集。
核心步骤概览
- 准备新镜像并标记:确保镜像有唯一标签并可回滚。
- 设置健全的健康检查:readiness 用来决定什么时候把流量导向新实例。
- 配置滚动策略:决定每次替换多少实例(例如 25%)。
- 自动或人工推进:每一批次替换后观察指标再继续下一批。
- 遇到异常立即回滚:通过 kubectl rollback 或重新部署旧镜像。
Kubernetes 示例(实操步骤)
我先把关键命令列清楚,接着解释每一步为什么要这么做。
1. 准备 Deployment(示例说明)
一个典型的 Deployment 清单里,最重要的是镜像标签、liveness/readiness 和策略配置(rollingUpdate)。
关键字段解释:
- spec.replicas:副本数。
- spec.strategy.rollingUpdate.maxUnavailable:允许同时不可用的最大实例数或比例。
- spec.strategy.rollingUpdate.maxSurge:允许超出期望副本的最大实例数或比例,用于短期并行运行新旧版本。
- readinessProbe:决定何时将 Pod 标记为可接流量。
2. 更新镜像(命令示例)
假设已有 deployment 名为 hello-deploy,当前镜像是 hello:v1,想更新到 hello:v2:
- kubectl set image deployment/hello-deploy hello=yourrepo/hello:v2
- kubectl rollout status deployment/hello-deploy
这两条命令会触发滚动更新并等待完成。重要的是不要把 readiness 写得太“严格”或太“宽松”。
3. 观察与回滚
- 查看事件和 Pod:kubectl describe deployment hello-deploy;kubectl get pods -w
- 查看日志:kubectl logs -f pod/…
- 如需回滚:kubectl rollout undo deployment/hello-deploy
设计健康检查的实践建议
这部分决定更新是否安全,常见坑我也说说。
- readiness 要快且可靠:它用于接流量,检查点可以是轻量的 /health 或 /ready 接口。
- liveness 略宽松:用于容器自愈,避免启动初期被误杀。
- 启动探针(startupProbe):对于慢启动的应用,用来区分“还没启动”和“已经启动但卡住”。
一个典型配置举例(概念说明):readiness 每 5s 检查一次,连续 2 次通过才标记为就绪;liveness 每 30s 检查,失败 3 次重启容器。
在没有 Kubernetes 的环境如何做滚动更新
现实中很多小团队没用 K8s。也可以用更轻量的方法实现类似效果。
Nginx + 多主机(或多容器)
- 在后端多台实例(或容器)上运行 v1。
- 逐台部署 v2:在某台机器上拉取新镜像、启动并做健康检查。
- 当新实例就绪后,从负载均衡池中把该机替换旧机。
- 继续下一台,出现异常随时把流量指回旧版本。
Systemd / 单机场景
单机但需要零停机时可以用短时间的并行实例 + socket 代理策略:
- 启动新进程在备用端口,检查就绪后切换代理(如 socat 或小型反向代理)到新进程。
- 如果失败,切回旧端口。
监控与指标:不能忽略的部分
监控和告警是滚动更新的安全网,没它你就是盲跑。
- 关注错误率(5xx)、延迟 P95/P99、请求量和成功率。
- 设置分批的短时间窗口告警,避免因短暂峰值触发回滚。
- 记录每次发布的版本、镜像 ID、变更点和回滚原因,便于事后分析。
常见问题与排查思路
- 更新卡住不前:检查 readiness probe 是否通过;查看事件(kubectl describe)是否有 ImagePullBackOff 或 CrashLoopBackOff。
- 部分实例错误率上升:回退到上一版本,并抽取异常日志对比接口返回、依赖变化。
- 切换时出现短暂 502/504:检查负载均衡健康检查与代理超时配置,适当增加超时或并行实例数。
一些实用的小技巧(我常用的)
- 在镜像里保留版本信息(git commit、构建时间),方便问题追溯。
- 把每次发布的变更写入发布日志(release notes)并自动关联到 CI/CD。
- 先在预发布环境做一次滚动更新演练,观察脚本和探针是否按预期工作。
- 对数据库迁移要小心,滚动更新对向后兼容的迁移最安全(先做兼容性迁移,再切代码)。
实战示例:一个完整的 HelloWorld 发布场景(思路流程)
- CI 构建 hello:v2,运行集成测试和健康检查镜像内的 /health。
- 将镜像推到镜像仓库并打 tag,同时更新 Deployment 的镜像字段。
- 触发滚动更新(Kubernetes 自动按策略替换)。
- 监控 5~10 分钟内错误率、延迟异常;无异常则完成发布。
- 若发现回归或错误,执行 rollback 并根据日志分析原因。
写在最后(像边想边写的那种语气)
其实讲到这里我还会想,很多团队觉得“滚动更新”听起来高大上,实际操作起来就是把复杂问题拆成小步走。别被工具绑架,核心是:保证每一步都有可观测性和回滚路径。慢一点、稳一点,用户通常不会因为你分几批换了个 HelloWorld 就注意到——除非你把整个网站关了。