本节摘要:本节把 Compose 部署的经验收敛成十二个维度的可勾选清单:文件组织、配置管理、镜像选择、资源限制、健康检查、持久化、网络、日志、安全、监控、备份、CI/CD。每个维度先给检查项,再讲为什么。清单不是理论陈列,而是部署前的自检工具——上线前过一遍,能挡掉大多数低级事故。
检查项:Compose 文件纳入版本控制(Git 等);服务、网络、卷的命名一致且有含义;关键配置行有注释;大型应用拆成多个 Compose 文件;服务按功能单一职责划分。
为什么:文件是部署的蓝图,别人接手、半年后自己回看,都靠它理解系统。命名一致的意思是同类资源一个套路,比如数据库一律叫 db 加用途后缀,卷一律叫 数据名_data。注释只写"为什么这么配",不写"这个键是干嘛的"——后者看文档即可,前者才是经验。大型应用拆文件时,用 include 或 extends 组合,别把三百行的文件堆在一个文件里。
检查项:密码、密钥不硬编码进 Compose 文件;用 ${变量} 引用配置;敏感信息用 secrets 或专门的密钥管理;环境差异用不同的 .env 文件表达。
# .env 示例 DB_USER=myuser DB_PASSWORD=mypassword
Compose 文件里写 {DB_USER}、{DB_PASSWORD},.env 里放真实值,文件进 Git、.env 进 .gitignore,这是最便宜的安全措施。更敏感的信息走 secrets 挂载,连环境变量都不放。环境差异(开发、测试、生产)用多份 .env 切换,文件名约定成 .env.dev、.env.prod,启动时用 --env-file 指定,比改文件内容安全。
检查项:优先官方镜像;镜像标签锁定具体版本;latest 只允许出现在本地实验环境;自定义镜像基于官方镜像构建;镜像定期更新并重新部署。
用 postgres:13 而不是 postgres:latest,这是本书反复强调的一条。latest 的问题在于不可复现:今天部署成功,三个月后重建可能拉到行为不同的新版本,排错时你根本不知道跑的到底是哪个版本。生产环境的镜像标签应当精确到小版本,甚至记录摘要值。自定义镜像务必基于官方基础镜像,别从空白系统搭起。
检查项:每个服务设置内存上限;CPU 使用设限或至少设份额;有状态服务预留足够内存;限制值有依据而非随手填。
services: web: image: nginx:latest deploy: resources: limits: cpus: '0.5' memory: 512M reservations: cpus: '0.25' memory: 256M
limits 是硬上限,超过即触发内核回收或 OOM;reservations 是预留,保证基础资源。老写法里的 cpu_shares 和 mem_limit 仍兼容,但新写法统一用 deploy 下的 resources。不设限制的后果是:一个服务的内存泄漏能把整台机器拖垮,殃及同机其他项目。限制值怎么定:先不设跑几天,看监控数据再收紧,别拍脑袋。
检查项:数据库等有状态服务配 healthcheck;依赖方用 condition: service_healthy;检查命令用应用自身的能力;间隔、超时、重试次数合理。
services: db: image: postgres:13 healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 30s timeout: 10s retries: 3
PostgreSQL 官方镜像自带 pg_isready,这是最可靠的检查方式,比 curl 探测端口准确。interval 30 秒、timeout 10 秒、retries 3 是一组稳妥的默认值:检查太频繁浪费资源,检查太稀疏又让启动等待变长。配了健康检查,depends_on 才能用 condition: service_healthy,从"等启动"升级为"等就绪",数据库那种"端口开了但还没准备好接受连接"的经典坑就此绕开。
检查项:数据库数据用命名卷;需要与宿主机交互的用绑定挂载;卷命名有含义;重要卷纳入备份计划;容器设计为可随时删除重建。
判断规则在 1.1 节讲过:命名卷交给 Docker 管理,适合数据库;绑定挂载直连目录,适合开发。一个额外的检查点:卷是否命名了。匿名卷在 down 之后会变成孤儿卷,时间长了磁盘被占满还找不到出处,命名卷至少能通过 docker volume ls 看清家底。
检查项:服务只加入它需要的网络;数据库等后端服务不映射宿主机端口;前端与后端网络分离;外部网络用 external 显式声明。
典型拓扑:web 同时挂 frontend 和 backend,数据库只挂 backend,宿主机端口只映射 web。这样攻击面被压缩到最小:数据库 5432 不出宿主机,公网根本摸不到。两个项目之间需要共享数据服务时,用 external 网络把已有网络接进来,而不是把端口裸奔出去。
检查项:配置日志驱动与轮转;日志量大的服务调整 max-size 与 max-file;生产环境考虑集中收集;排查时知道日志在哪。
services: web: image: nginx:latest logging: driver: json-file options: max-size: "10m" max-file: "3"
默认 json-file 驱动会把日志无限写到宿主机,一个高频服务几天就能吃满磁盘。max-size 10m 加 max-file 3 表示单文件 10 兆、保留 3 份,总共 30 兆封顶。需要跨机检索时,用 fluentd 驱动或采集器把日志送进 ELK Stack、Graylog 这类集中式系统,排查多服务问题会轻松很多。
检查项:容器不以 root 运行;文件系统必要时只读;敏感信息走 secrets;镜像定期扫描漏洞;依赖与基础镜像及时更新。
FROM ubuntu:latest RUN useradd -m myuser USER myuser
Dockerfile 里创建非 root 用户并切换,一行 USER 就把容器权限降到最小。配合 Compose 里的 user 字段可以直接指定运行用户,read_only: true 则把整个根文件系统设为只读,只给需要写的路径挂卷,恶意写入和误写都被挡住。镜像扫描可以用 Docker 官方或其他扫描工具接入 CI,漏洞清单出来后按严重程度排期修。
检查项:容器级监控 CPU、内存、磁盘、网络;应用级监控响应时间、错误率、吞吐量;监控数据有留存;异常能触达负责人。
容器级监控用 Prometheus 采集加 Grafana 展示是事实标准:Prometheus 负责拉取指标,Grafana 负责画图与告警,两者都常用官方镜像,用 Compose 部署它们本身就是本书模板的练手项目。应用级指标需要应用暴露指标端点,再让 Prometheus 抓取。监控的落地顺序建议:先容器级,再应用级,告警规则从最关键的"容器反复重启"开始配。
检查项:卷数据定期备份;Compose 文件与 .env 配置随版本控制备份;备份有恢复演练;灾难恢复计划落到书面。
卷备份最朴素的方法是用一个临时容器打包:
docker run --rm -v db_data:/data -v $(pwd):/backup ubuntu tar cvf /backup/db_data.tar /data
把 db_data 卷挂进临时容器,打包到当前目录,--rm 用完即删。配置备份同样重要:docker-compose.yml 和 .env 在 Git 里,等于系统配置有了历史版本。检验备份是否有效的唯一标准是恢复演练——三个月做一次"从备份把库恢复到新机器"的演练,比备份脚本本身更能暴露问题。另外,卷级备份之外还有逻辑备份:对数据库这种有格式的应用,定期用容器内的导出工具做逻辑备份,比如对 PostgreSQL 执行导出命令生成可读的 SQL 文件,逻辑备份恢复粒度更细,单表误删时能只捞一张表,是卷备份的补充而非替代。
检查项:代码变更自动构建镜像;构建后自动跑测试;测试通过自动部署;部署失败能快速回滚;环境差异由流水线参数控制。
CI 工具选型看团队现状:GitHub 仓库用 GitHub Actions 最顺,GitLab 自带 CI,自建机房 Jenkins 是老兵。流水线的最小闭环是:推送代码触发构建,构建出镜像推送仓库,服务器拉新镜像用 up -d 重启。回滚手段与部署手段同样重要:上一版镜像标签留档,回滚就是再 up 一次旧标签。服务数量多到记不清谁依赖谁时,再引入服务发现工具(Consul、etcd、ZooKeeper 是三个常见选择),让服务注册与发现自动化,这一步等业务规模真到了再说,前期用 Compose 内置的服务名解析足够。

| 维度 | 核心检查项 | 高频动作 | 常见误区 |
|---|---|---|---|
| 文件组织 | 版本控制、命名规范、注释 | 关键配置行写为什么 | 注释解释键的作用 |
| 配置管理 | 不硬编码、变量引用 | .env 进 .gitignore | 密码写进 Compose 文件 |
| 镜像选择 | 官方镜像、锁定版本 | latest 改具体版本 | 用 latest 图省事 |
| 资源限制 | 内存与 CPU 设限 | deploy 下写 limits | 不设限等 OOM 拖垮机器 |
| 健康检查 | 有状态服务必配 | pg_isready、curl | 只看端口不看就绪 |
| 持久化 | 数据入命名卷 | 卷纳入备份清单 | 数据写进容器层 |
| 网络 | 最小暴露面 | 后端不映射端口 | 全部端口裸奔公网 |
| 日志 | 轮转与集中收集 | max-size 10m | 日志写满磁盘 |
| 安全 | 非 root、只读、扫描 | Dockerfile 加 USER | 一路 root 跑到底 |
| 监控 | 容器级加应用级 | Prometheus 加 Grafana | 出了问题才想起监控 |
| 备份 | 卷加配置双备份 | 定期恢复演练 | 只备份不演练 |
| CI/CD | 构建测试部署闭环 | 镜像留档可回滚 | 部署没有回滚手段 |
⚠️ 检查单不是装饰品:十二条全勾不等于万无一失,但每条不勾都对应一类真实事故——latest 拉到坏版本、日志撑爆磁盘、数据库卷被 down -v 误删、OOM 拖垮整机。把清单贴在部署流程里,比事后复盘划算得多。
💡 从最容易的三项开始:如果你管理的存量部署还没做过实践改造,先做镜像锁定版本、日志轮转、健康检查这三项,改动小、见效快,其余按优先级排期推进。
十二个维度过完,这本书的旅程就到这里了。从第 1 章的语法地基,到第 6 章的检查清单,你已经具备独立评估、部署和维护一套 Compose 应用的能力——接下来,去把第一个模板跑起来,让清单在实践中慢慢长成你自己的版本。