Skip to content
VDS · Docker 与容器

无停机更新容器

如何更新镜像以保持服务在线并可回滚:固定版本、健康检查、操作顺序以及自动化。

更新于 2026年8月23日

更新容器并不是“拉取新镜像”,而是“用新版本替换正在运行的版本,并且能够回滚”。这个区别只会在一个时刻显现:新版本启动失败时。

一套可行的流程

cd /opt/myapp
docker compose pull
docker compose up -d
docker compose ps
docker compose logs -f --tail 100

Compose 只会重建镜像发生变化的服务,其余服务保持不变。停机时间仅为重启容器所需的几秒钟。

但在执行之前,请先满足两个条件。

第一:版本已固定。 文件中必须写明 postgres:17.2,而不是 postgres:latest。否则某天 pull 会带来一个重写数据格式的大版本,回滚将变得不可能。

第二:备份是新的。 一次破坏数据库的更新会造成不可逆的损坏。在大版本变更之前,请先做一次转储——参见需要备份哪些内容。

无中断替换

对于反向代理后面的 Web 服务,如果容器配置了健康检查,停机时间几乎可以降为零:代理只会向已就绪的实例发送请求。

services:
  app:
    image: ghcr.io/example/app:1.5.0
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
      interval: 5s
      timeout: 3s
      retries: 6
      start_period: 20s
docker inspect -f '{{.State.Health.Status}}' <container>

如果没有健康检查,Compose 会在进程启动后立即认为容器已就绪——而此时应用程序仍在读取配置并执行迁移。

在新版本至少运行一小时之前,不要删除旧镜像。回滚意味着恢复 image: ...:1.4.2 并执行 docker compose up -d,但前提是旧镜像仍在磁盘上。更新后立刻执行 docker image prune -a 会让您失去这个选项。

回滚

sed -i 's|app:1.5.0|app:1.4.2|' compose.yaml
docker compose up -d app
docker compose logs -f --tail 50 app

如果新版本已经更改了数据库结构,仅回滚镜像是不够的——您需要从备份恢复。因此大版本更新应在空闲时段进行,并确保备份已经过验证:参见恢复演练。

自动化:请谨慎

Watchtower 可以自行更新容器。对于家庭服务来说这很方便;对于生产环境来说则是风险:更新在夜间到来,破坏数据库,却无人察觉。一个合理的折中方案是只发送通知:

services:
  watchtower:
    image: containrrr/watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --monitor-only --schedule "0 0 6 * * *"

您会得知有新版本发布,然后在合适的时间手动更新。

重启机器

系统软件包的更新与容器相互独立。内核更新后需要重启,带有 restart: unless-stopped 的容器会自动恢复运行。请提前测试这一点——在空闲时段执行 sudo reboot,而不是在故障期间。只要系统上安装了 qemu-guest-agent,从控制面板执行软重启即可正常工作。

常见错误

  • 只执行 pull 而不执行 up -d。 新镜像已下载,但旧容器仍在运行。
  • 磁盘被旧镜像塞满。 每月执行一次 docker image prune——但不要在更新后立刻执行。参见磁盘空间。
  • 您一次性更新了所有内容。 某个服务出问题——而您无法判断是哪一个。请一次只更新一个服务。
  • 您没有阅读发行说明。 配置文件不兼容是大版本变更后最常见的故障原因;参见常见 Docker 问题中的分析。