Docker 运维入门实战:不停机更新,改了代码不用停掉整个站

举报
yd_274623194 发表于 2026/10/30 11:15:04 2026/10/30
【摘要】 关键词:docker compose up、滚动更新、健康检查、回滚、镜像标签上一篇我们给 my-app 加上了日志和健康检查:出问题先看日志,服务健不健康看 docker compose ps 的状态。今天把这套东西用起来——改了代码之后,怎么更新这几个容器,而不用把整个站停掉再重起。先说一个实话:单机、每个服务只有一个副本时,不存在真正的"零中断"。目标是把中断压到一次只影响一个服务、几...

关键词:docker compose up、滚动更新、健康检查、回滚、镜像标签

上一篇我们给 my-app 加上了日志和健康检查:出问题先看日志,服务健不健康看 docker compose ps 的状态。今天把这套东西用起来——改了代码之后,怎么更新这几个容器,而不用把整个站停掉再重起。

先说一个实话:单机、每个服务只有一个副本时,不存在真正的"零中断"。目标是把中断压到一次只影响一个服务、几秒钟,并且每一步都能验证、能回滚,而不是 docker compose down 一把梭,把网关、网页、接口全停了再慢慢起。

本文接着前面的结构讲:gateway(Nginx 网关)、web(静态网页)、api(8000 端口的 Python 接口服务),并且假设上一篇的健康检查已经配好——没有它,下面的"等健康了再继续"就无从谈起。

一、更新前先分清:改了什么,就动什么

my-app 里三类改动,对应三种更新范围,别一上来就全量重建:

  • 只改了 api 的代码:只重建、只重启 api,web 和 gateway 不动。
  • 只改了 web 的静态文件:只重建、只重启 web。
  • 改了 gateway 的 Nginx 配置:只重启 gateway,而且要先验证配置。

全量 docker compose up -d --build 在服务少的时候也能跑,但它会把所有容器按依赖顺序重建一遍,中断面最大,还容易把一个没改动的服务也卷进一次本可避免的重启。更新的原则是:动得越少,炸得越小。

二、给镜像打个版本号,别只用 latest

回滚的前提是旧镜像还在。先给要更新的服务打个明确的标签,再构建:

# 假设 api 这次改动记为 v1.1,旧版本 v1.0 的镜像仍在本地
docker compose build api
docker tag my-app-api:latest my-app-api:v1.1

更稳妥的做法是在 docker-compose.yml 里把镜像名写死成带版本的:

services:
  api:
    build: ./api
    image: my-app-api:v1.1

这样 docker compose ps 里一眼就能看出每个服务跑的是哪个版本,出问题要回滚时,也不用猜"刚才跑的到底是哪一份代码"。latest 永远指向"最新一次构建",它不是一个版本,而是一个会变的指针——排查和回滚都别依赖它。

三、一次只更新一个服务:构建、重启、等健康

以 api 改了一个接口逻辑为例,完整顺序是:

docker compose build api
docker compose up -d --no-deps api

--no-deps 是关键:它只重建 api,不连带重启 gateway 和 web。Compose 会停掉旧的 api 容器、起一个新的,然后健康检查开始探活。这时不要急着动下一个服务,先等它健康:

docker compose ps api          # STATUS 一列应出现 (healthy)
docker compose logs --tail 50 api   # 看启动日志有没有报错

等 (healthy) 出现,再从网关侧验证一次接口真的通了,而不是只看容器在跑:

curl http://localhost/api/health || curl https://你的域名/api/接口路径

这一步的意义在上一篇已经讲过:进程在跑不等于接口能用。健康检查通过 + 网关侧请求有正常响应,这次更新才算落袋。web 的更新同理:docker compose build web,再 docker compose up -d --no-deps web,等健康、再验证页面。

四、网关配置改了:先验证,再重启

如果这次改的是 gateway 的 Nginx 配置(比如加了一个转发规则),重启之前先在容器里验证配置语法,配错了直接停下,别让一个坏配置把入口换掉:

docker compose exec gateway nginx -t
docker compose up -d --no-deps gateway
docker compose logs --tail 50 gateway

nginx -t 通过再重启,是网关更新里成本最低的一道保险。重启后同样从外侧请求一次,确认网页和接口都还能通过网关访问——网关是所有流量的入口,它一坏,所有服务看起来都坏了。

五、更新顺序:后端先行,网关最后

多个服务都要更新时,按这个顺序走,一次一个:

  1. api:先更新后端,验证健康、验证接口。
  2. web:再更新网页,验证页面。
  3. gateway:只有它的配置变了才动它,而且放在最后。

理由很简单:网关转发到后端,后端先就位,网关再怎么重启,转发目标都是健康的。反过来先重启网关、后端还是旧的甚至正在重启,网关那几秒的请求就全落空了。顺序本身也是一种中断控制。

六、出问题了怎么回滚:别现想,现成的步骤

更新后验证没通过(健康检查变 (unhealthy)、日志里有报错、网关侧请求失败),先别急着再改代码,先回滚到上一个能用的版本,把服务恢复了再慢慢查:

# 把 api 的镜像标签改回 v1.0(或直接用旧镜像名),再重建重启
docker compose up -d --no-deps api
docker compose ps api
docker compose logs --tail 50 api

回滚时同样只动出问题的那个服务,同样等健康、同样从网关侧验证。回滚不是"认输",它是更新流程的一部分:能快速回滚的更新,才敢放心更新。如果旧镜像已经被删了、旧代码也没打标签,回滚就只能靠"重新构建一份旧代码",那一步的成本和风险都高得多——所以第二步的版本号不是形式,是回滚的入场券。

七、三个新手最容易踩的坑

1. 用 docker compose down 做更新
down 会停掉并删除所有容器,包括网关和没改动的服务,整个站先全停,再一个一个起。这是部署,不是更新。日常更新用 up -d --no-deps <服务名>,只动该动的。

2. 不等健康就更新下一个服务
上一个服务还在 (health: starting),下一个已经重启了,出了问题根本分不清是谁的锅。一次一个、等健康、再验证、再继续,这四步别省。

3. 更新完只看容器在跑
docker compose ps 显示 Up 只是容器在跑。更新的验收标准是三条:健康状态 (healthy)、服务日志无报错、从网关侧真实请求一次有正常响应。三条缺一,都不算更新完成。

结语

从单容器、Compose 编排、数据卷、反向代理和 HTTPS、日志与健康检查,到今天的滚动更新,这条线已经是一套能对外服务、出了问题能定位、改了代码能安全更新的部署了。下一篇可以往"别让一个服务拖垮整台机器"走一步:给每个容器加上内存、CPU 限制和重启策略,让单个服务的异常有边界。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。