现在我们有版本化镜像、生产 Compose 配置、数据卷、健康检查和备份方案,可以把订单项目部署到一台 Linux 服务器。
这一讲以单机 Compose 为边界,重点是可重复、可验证、能回退。它不是多机高可用方案。
上线前必须准备什么
服务器
- 已按第 6 讲安装 Docker Engine、Buildx 和 Compose 插件
发布物
compose.yamlcompose.production.yaml.env.production
外部条件
如果容器 Nginx 只绑定 127.0.0.1:8080,还需要宿主机反向代理或外部负载均衡器把 HTTPS 流量转发进来。
先检查服务器状态
uname -adocker versiondocker compose versiondf -hfree -htimedatectl status
重点确认:
- Docker Client 和 Server 都正常
数据库和 RabbitMQ 对磁盘空间非常敏感。磁盘已经接近满载时,不应该继续发布新镜像和创建日志。
使用独立部署用户和目录
示例目录:
sudo install -d \ -o deploy \ -g deploy \ -m 750 \ /opt/order-app
进入目录:
将两个 Compose 文件通过受控发布流程放到这里,并确认所有者和权限。
能够访问 Docker Socket 的用户通常拥有接近宿主机管理员的能力。deploy 用户是否加入 Docker 组必须经过权限评估,不能因为方便就给所有开发者开放。
生产 SSH、sudo 和 Docker 权限应使用个人账号、最小授权和审计记录。
安全准备生产变量
install -m 600 /dev/null .env.production
使用受控方式写入真实配置:
APP_IMAGE=registry.example.com/phper/order-api:1.4.0NGINX_IMAGE=registry.example.com/phper/order-nginx:1.4.0APP_ENV=productionAPP_DEBUG=falseDB_DATABASE=order_appDB_USERNAME=order_appDB_PASSWORD=生产数据库密码MYSQL_ROOT_PASSWORD=生产root密码REDIS_PASSWORD=生产Redis密码RABBITMQ_USER=order_appRABBITMQ_PASSWORD=生产RabbitMQ密码RABBITMQ_VHOST=order_app
输入过程中避免终端录屏、Shell 历史和工单日志泄露。
更成熟的环境应由秘密管理系统在部署时提供,而不是长期依赖人工编辑文件。
登录镜像仓库
生产服务器使用只读拉取令牌:
printf '%s' ”$REGISTRY_PULL_TOKEN” \ | docker login \ --username ”$REGISTRY_PULL_USER” \ --password-stdin \ registry.example.com
令牌变量应由安全会话或秘密系统提供,不要把真实值写入发布脚本。
生产服务器没有必要拥有推送、删除或覆盖镜像的权限。
先验证最终Compose配置
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ config --quiet
查看服务和镜像:
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ config --servicesdocker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ config --images
确认:
完整 config 输出可能包含秘密,不能直接上传到日志平台。
拉取全部镜像
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ pull
拉取后核对:
docker image inspect \ registry.example.com/phper/order-api:1.4.0
应与发布清单中的 digest 一致。
拉取成功只证明仓库、权限和镜像存在,不代表应用已经部署。
第一次部署先启动数据服务
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ up -d mysql redis rabbitmq
查看健康状态:
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ ps
查看首次初始化日志:
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ logs --tail 200 mysql redis rabbitmq
等待服务 healthy,再执行数据库迁移。
如果使用云数据库、云 Redis 或独立 RabbitMQ,Compose 不应再启动对应本地服务,应用配置改为受控内部地址。
执行数据库迁移
发布前先完成备份。第一次空库也应确认目标地址,避免迁移连到错误环境。
Laravel 示例:
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ run --rm php \ php artisan migrate --force
迁移是一次性受控任务,不放进 PHP-FPM 入口脚本。
检查迁移输出和退出码。失败时不要继续启动 Web 服务,先确认数据库连接、权限、SQL 和版本兼容性。
涉及大表 DDL 时,还要提前评估锁表、复制延迟、磁盘空间和执行时间,不能因为命令在容器里运行就忽略数据库风险。
启动完整应用
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ up -d --remove-orphans
--remove-orphans 会删除当前项目中不再由配置定义的服务容器。使用前必须确认项目名和最终配置,避免误删仍在使用但遗漏在文件中的容器。
查看:
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ ps
分层验证
容器与健康状态
所有预期服务存在,关键服务为 healthy,没有反复重启。
最近日志
docker compose \ --env-file .env.production \ -f compose.yaml \ -f compose.production.yaml \ logs --tail 200
检查数据库认证、Redis 连接、RabbitMQ vhost、文件权限和 PHP-FPM 错误。
服务器本机HTTP
curl -fsS http://127.0.0.1:8080/health
健康端点应轻量,不返回密码、内部堆栈和敏感版本信息。
外部HTTPS
curl -fsS https://api.example.com/health
再验证证书、域名、反向代理和外部网络路径。
业务冒烟测试
冒烟测试必须使用可识别、可回收的数据,不能污染真实用户和财务数据。
重启服务器后服务会恢复吗
确认 Docker 服务开机启动:
sudo systemctl is-enabled docker
Compose 服务配置了合适的 restart: unless-stopped 后,Docker Daemon 恢复时会尝试启动已有容器。
但仍要验证:
不要第一次在生产重启时才检验恢复流程。应在预发布或维护窗口演练。
上线后立即记录什么
发布时间执行人Git提交镜像标签和digestCompose文件版本数据库迁移备份位置和校验结果健康检查结果冒烟测试结果上一稳定版本
同时观察一段时间的:
小结
单机 Compose 上线不是一句 up -d,而是一套受控流程:检查服务器、准备生产变量、拉取并核对镜像、启动数据服务、备份、执行迁移、启动应用、分层验证并记录发布结果。
本机健康和外部 HTTPS 都要验证,最终还要完成真实业务冒烟测试。
下一讲,我们处理更常见的日常操作:发布新版本、控制更新范围,以及新镜像或数据库变更失败后怎样回滚。
本篇是《Docker 40讲:从项目容器化到线上部署》第34讲。
下一讲:线上版本应该怎样更新和回滚
更多内容将持续更新。