docker-compose.yml 结构与关键特性:从开发到生产的工程化实践
docker-compose.yml 是定义多服务应用的声明式配置文件,它让开发者能够以简洁的 YAML 语法描述复杂的服务拓扑、网络、存储和安全策略。掌握其核心结构与高级特性,是构建可维护、安全、环境一致的容器化应用的关键。
一、基本结构:服务(services)、网络(networks)、卷(volumes)、密钥(secrets)
一个典型的 docker-compose.yml 包含以下顶级字段:
yaml
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
depends_on:
- db
networks:
- app-network
db:
image: postgres:15
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secret
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
volumes:
db-data:
networks:
app-network:
driver: bridge二、关键特性详解
1. depends_on:控制服务启动顺序
作用:确保一个服务在另一个服务启动之后才开始启动。
示例:
yaml
depends_on:
- db局限性:
- 仅保证启动顺序,不等待服务“就绪”。
即:web服务会在db容器启动后启动,但此时 PostgreSQL 可能仍在初始化,尚未接受连接,导致web启动失败。
解决方案:必须配合 healthcheck 使用。
2. healthcheck:判断服务是否真正就绪
作用:通过定期执行命令检测服务健康状态,Docker 将服务标记为 healthy 或 unhealthy。
语法:
yaml
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"] # 检查 PostgreSQL
interval: 10s # 每 10 秒检查一次
timeout: 5s # 超时 5 秒
retries: 5 # 失败 5 次后标记为 unhealthy
start_period: 30s # 容器启动后 30 秒内不检查常用健康检查命令:
| 服务 | 健康检查命令 |
|---|---|
| PostgreSQL | pg_isready -U postgres |
| MySQL | mysqladmin ping -h localhost -u root -p$MYSQL_ROOT_PASSWORD |
| Redis | redis-cli ping |
| Node.js API | curl -f http://localhost:3000/health || exit 1 |
与 depends_on 结合使用(Compose v2.1+ 支持 condition: service_healthy):
yaml
depends_on:
db:
condition: service_healthy这样,web 服务将等待 db 进入 healthy 状态后才启动,彻底解决“启动顺序但未就绪”问题。
3. networks:自定义网络,服务间通信
作用:创建隔离的网络环境,服务可通过服务名(service name)直接通信。
示例:
yaml
networks:
app-network:
driver: bridge服务间通信:
web服务可通过http://db:5432访问数据库- 无需暴露端口到主机,提升安全性
- 自动 DNS 解析,无需手动配置 IP
优势:
- 网络隔离,避免端口冲突
- 支持自定义驱动(如 overlay 用于 Swarm)
- 服务发现简单可靠
4. secrets 与 configs:安全注入敏感数据与配置
secrets:安全传递密码、密钥等敏感信息
yaml
services:
web:
image: myapp
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
# 或 external: true(从 Swarm/K8s 获取)在应用中通过 /run/secrets/db_password 读取:
js
const password = fs.readFileSync('/run/secrets/db_password', 'utf8');configs:注入非敏感配置文件(如 Nginx 配置、TLS 证书)
yaml
services:
web:
configs:
- nginx_config
configs:
nginx_config:
file: ./config/nginx.conf优势:
- 避免将密码硬编码在
environment或.env文件中 - 支持 Docker Swarm 和 Kubernetes 集成
- 生产环境更安全
三、开发 vs 生产配置:多文件覆盖模式
docker-compose 支持使用多个 YAML 文件,后加载的文件会覆盖或合并前一个文件的配置,非常适合区分环境。
1. 开发配置:docker-compose.dev.yml
yaml
# docker-compose.dev.yml
version: '3.8'
services:
web:
build: .
volumes:
- .:/app # 挂载源码,热更新
- /app/node_modules # 忽略容器内 node_modules
command: npm run dev # 启动开发服务器
environment:
- NODE_ENV=development
ports:
- "9229:9229" # 开启调试端口2. 生产配置:docker-compose.prod.yml
yaml
# docker-compose.prod.yml
version: '3.8'
services:
web:
image: myapp:latest # 使用预构建镜像
command: npm start
environment:
- NODE_ENV=production
ports: []
# 移除 volumes,禁止 shell 访问
# 可添加 replicas、resources 限制3. 合并启动
bash
# 开发环境
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
# 生产环境
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d执行逻辑:
- 先加载基础配置(
docker-compose.yml) - 再加载环境特定配置,覆盖相关字段
- 最终生成一个合并后的服务定义
四、最佳实践总结
| 特性 | 推荐用法 |
|---|---|
depends_on | 必须配合 healthcheck 使用,避免启动失败 |
healthcheck | 所有依赖服务(DB、Redis)都应配置 |
networks | 所有服务使用自定义网络,通过服务名通信 |
secrets | 生产环境注入数据库密码、JWT 密钥等 |
configs | 注入 Nginx、Logrotate 等配置文件 |
| 多文件配置 | base.yml + dev.yml / prod.yml 分离环境 |
五、结语
docker-compose.yml 不只是一个“启动多个容器”的工具,它是一个完整的应用编排平台。通过合理使用 healthcheck、networks、secrets 和多文件覆盖模式,你可以构建出:
- 开发友好:热更新、调试端口、交互式 shell
- 生产安全:非 root 用户、无敏感信息、资源限制
- 环境一致:开发、预发、生产配置统一管理
这才是现代全栈开发应有的工程化水平。