为全球中文用户,精选值得用的数字资源独立编辑 · 透明推荐
RANGKA JOURNAL · 2026.10.07

Docker Compose 部署到 VPS:上线前检查这五件事

让卡优选编辑 · 依据公开资料整理

Docker Compose 部署到 VPS:上线前检查这五件事(AI 概念图)

docker compose up -d 回车,容器状态 Running,浏览器一开页面也出来了——很多人到此就宣布“部署完成”。但开发机上能跑和公网上能稳定跑,中间差着五件事:入口暴露、数据持久化、凭据管理、日志与重启、升级回滚。漏掉任何一件,出问题时你都会在半夜重新学一遍。下面这份清单,就是上线前要逐项打勾的五件事。

第一件:只公开真正需要的入口

生产环境的标准姿势是:反向代理(Nginx / Caddy / Traefik)在前面接收公网请求,应用和数据库待在内部网络里。Compose 里做到这点很简单——需要公开的服务才写 ports,不需要公开的不要写,同一网络内的服务本来就能用服务名互相访问:

services:
  web:
    image: myapp:1.4.2
    ports:
      - "127.0.0.1:8080:80"   # 只绑本机,再由反向代理转发
  db:
    image: postgres:16
    # 没有 ports:外部连不进来,但 web 仍可通过 db:5432 访问

发布端口前,先确认宿主机端口没被占用:ss -tlnp | grep 8080。宿主机端口和容器内部端口不必相同,改宿主机那一侧就能避开冲突。

还有一个容易被忽视的点:Docker 发布出去的端口,默认不受系统防火墙(ufw)那套规则约束——这是 Docker 网络模型的行为,不是 bug。所以“数据库不写 ports”才是真正的安全边界。核验的唯一标准是 ss -tlnp 看到的实际监听情况,而不是防火墙界面长什么样。

第二件:数据要持久化,凭据不能进仓库

数据库文件、上传目录必须挂载数据卷,否则容器一重建数据就没了。镜像、容器和持久化数据是三样东西,别混为一谈:

services:
  db:
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:

密码、密钥不要写进 compose 文件,更不要提交到公开仓库。用 env_file 或环境变量引用:

services:
  db:
    env_file:
      - .env
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
chmod 600 .env   # 仅自己可读,且不加入版本库

镜像一律写明确的 tag(postgres:16 而不是 postgres:latest),并记下每次变更:改了哪个服务的版本、为什么改。latest 的意思是“每次 pull 都可能变”,出兼容性问题时你连对照的基线都说不清。

第三件:重启策略和日志上限,别等磁盘满了才想起来

services:
  web:
    restart: unless-stopped
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

重启策略按业务选:unless-stopped 适合长期运行的服务;on-failure 适合跑完就退出的任务型容器。日志不设上限的话,json-file 会一直吃磁盘,半夜被告警叫醒时你就懂了。平时定期看两眼:docker compose logs --tail=100 web 看应用日志,docker system df 看磁盘占用。

第四件:生产差异用覆盖文件,别改同一份 compose

开发和生产共用一份文件,早晚会有人把调试端口带上生产。推荐做法:基础 compose.yml 放公共部分,生产差异单独放 compose.prod.yml,启动时合并:

docker compose -f compose.yml -f compose.prod.yml up -d

改完先跑 docker compose -f compose.yml -f compose.prod.yml config 看合并后的实际配置,确认无误再 up。这条命令是免费的“上线前彩排”,能发现九成手误。

第五件:升级前备份,升级后做一次真实验收

把升级流程固定下来,每次都走同一套动作:

# 1. 先备份(数据卷打包,或用专业备份工具)
# 2. 拉新镜像并启动该服务
docker compose pull web
docker compose up -d web
# 3. 看状态和日志
docker compose ps
docker compose logs --tail=50 web

注意:容器状态 Running 不等于业务正常。数据库迁移可能失败了,应用可能在报 500。验收至少做一次真实请求:打开网站走一遍核心流程,或者请求健康检查端点:

curl -s -o /dev/null -w "%{http_code}\n" https://你的域名/health

升级失败要有回退方案:因为镜像版本是写死的,只要把 compose 指回旧 tag 再 up -d 就能回退——前提是第二件里的“版本写死”你做到了。

写一张上线验收卡

每次上线前回答这五个问题,答不上来就别 up:① 公网只能访问到反向代理吗?② 删掉容器重建,数据还在吗?③ 凭据文件权限是 600 且没进仓库吗?④ 日志有上限、重启策略设了吗?⑤ 升级失败时,我知道怎么回退吗?把答案和变更记下来,这就是你的上线记录,比收藏一条启动命令有用得多。

这张卡还有一个好处:当你以后要把运维交接给别人,或者半夜被叫醒处理故障时,它能让你在五分钟内回答“这个服务是怎么部署的”。很多小团队的“祖传服务没人敢动”,根因就是当初上线时只记住了 up 命令,没留下任何验收记录。从第一次上线就养成这个习惯,成本几乎为零。

常见坑

把数据库端口 publish 出来“方便调试”。方便了你,也方便了全网的扫描器。调试用 docker compose exec db sh 进容器里做。

用 latest 标签上线。某天 pull 到大版本升级,迁移脚本直接报错,而你甚至不知道上次跑的是哪个版本。

容器 Running 就等于没事。健康检查和一次真实业务请求才是验收标准,状态灯只是参考。

备份了卷目录就以为万事大吉。运行中的数据库要按官方方法导出后再备份,直接拷贝数据文件可能得到一份恢复时打不开的备份。

常见问题

compose.yml 和 docker-compose.yml 用哪个?新版 Compose 优先识别 compose.yml,老名字也兼容。新项目建议用 compose.yml。

改了 compose 文件,是 restart 还是 up?多数场景 docker compose up -d 就够了,它会按新配置重建有变化的容器;只有改了构建上下文才需要加 --build。

怎么确认多文件合并后的最终配置?docker compose config,用 -f 指定多个文件时它会显示合并结果,up 之前看一眼。

down 和 stop 有什么区别?stop 只停容器,网络和卷都在;down 还会删掉容器和网络(数据卷默认保留)。生产环境别手滑 down 掉还没备份的栈。

参考资料

资料核查:2026年10月8日。本文根据公开官方资料独立整理撰写;封面为 AI 生成的概念插画,不是产品实拍。

内容仅供信息参考,具体条件以官方最新说明为准。编辑与商业说明 →