在 Docker Compose 中区分开发和生产环境,最稳妥的做法是用多份 Compose 配置文件配合不同的 env_file,而不是依赖单一 .env 文件。
先说结论:多环境配置需要同时处理 Compose 解析层和容器运行层两套变量体系,用 -f 参数组合配置文件 + env_file 加载环境专属变量是最清晰的方案。
- 适合:需要在开发、测试、生产之间切换配置的项目
- 先准备:基础 compose.yaml + 环境专属 compose.dev.yaml/compose.prod.yaml + 对应 .env.dev/.env.prod 文件
- 验收:用 docker compose config 确认变量注入正确,进容器用 env 命令验证运行时环境变量
命令速用版
开发环境启动:
docker compose -f compose.yaml -f compose.dev.yaml up -d
生产环境启动:
docker compose -f compose.yaml -f compose.prod.yaml up -d
指定环境文件启动:
ENVIRONMENT=prod docker compose `--env-file` .env.prod up -d
检查最终配置(不启动容器):
docker compose -f compose.yaml -f compose.prod.yaml config
为什么会这样
Docker Compose 有两套环境变量体系,很多人混淆导致配置不生效:
第一套是 Compose 解析层:项目根目录的 .env 文件用于替换 docker-compose.yml 中的 ${VAR} 占位符,比如镜像版本、端口号。这个变量在 Compose 解析文件时就确定了,不会进入容器内部。
第二套是容器运行层:服务定义中的 environment 或 env_file 提供的变量,最终会出现在容器内的 env 命令输出中,应用代码能读到这些值。
多环境配置的关键是让不同环境使用不同的 env_file,并配合外部变量控制 Compose 文件行为。单一 .env 文件无法同时满足这两层需求,所以需要文件分离策略。
分步处理
步骤 1:创建基础配置文件
在项目根目录创建 compose.yaml,定义所有环境共享的服务框架:
version: '3.8'
services:
webapp:
image: myapp:${APP_VERSION:-latest}
ports:
- "8080:8080"
environment:
- APP_ENV=${ENVIRONMENT}
env_file:
- .env.${ENVIRONMENT:-dev}
depends_on:
- db
db:
image: postgres:${POSTGRES_VERSION:-14}
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:步骤 2:准备环境专属变量文件
创建 .env.dev 和 .env.prod:
# .env.dev DB_URL=postgresql://dev-db:5432/myapp DEBUG=true LOG_LEVEL=debug # .env.prod DB_URL=postgresql://prod-db:5432/myapp DEBUG=false LOG_LEVEL=info
注意:这些文件不要提交到 Git,.env.example 作为模板提交。
步骤 3:创建环境专属 Compose 配置
开发环境 compose.dev.yaml:
version: '3.8'
services:
webapp:
build: .
volumes:
- ./src:/app/src
environment:
- DEBUG=true
db:
ports:
- "5432:5432"
environment:
- POSTGRES_USER=devuser
- POSTGRES_PASSWORD=devpass生产环境 compose.prod.yaml:
version: '3.8'
services:
webapp:
image: myapp:1.2.0
deploy:
replicas: 3
db:
volumes:
- /data/postgres:/var/lib/postgresql/data步骤 4:启动时指定环境
开发环境:
ENVIRONMENT=dev docker compose -f compose.yaml -f compose.dev.yaml up -d
生产环境:
ENVIRONMENT=prod docker compose -f compose.yaml -f compose.prod.yaml up -d
回滚提醒:如果配置有误,用 docker compose down 停止后修改,不要用 docker compose up `--force-recreate` 直接覆盖,先确认 config 输出正确。
怎么验证是否生效
检查 1:确认 Compose 解析的变量
docker compose -f compose.yaml -f compose.prod.yaml config
查看输出中 ${VAR} 是否已被替换为实际值。
检查 2:确认容器内环境变量
docker compose exec webapp env | grep APP_ENV docker compose exec webapp env | grep DB_URL
应该能看到你在 env_file 或 environment 中定义的变量。
检查 3:确认服务行为
查看应用日志确认加载了正确的配置:
docker compose logs webapp | grep -i "environment\|config"
开发环境应该看到 DEBUG=true 相关日志,生产环境应该看不到调试信息。
常见坑
坑 1:.env 文件位置不对
Compose 默认只读取项目根目录的 .env 文件,子目录的 .env 不会自动加载。如果要用其他位置的文件,需要用 `--env-file` 参数显式指定。
坑 2:变量优先级混淆
环境变量优先级从高到低为:命令行参数 (-e) > compose 文件中 environment 字段 > env_file 指定的文件 > 系统环境变量 > .env 文件中的默认值。如果同一个变量在多处定义,高优先级的会覆盖低优先级的。
坑 3:数组配置合并规则
使用多个 Compose 文件时,数组类型配置(如 ports、volumes)会合并而非替换。如果生产环境想移除开发环境的端口暴露,需要在 prod 文件中显式定义,而不是期望它自动覆盖。
坑 4:敏感信息泄露
.env 文件包含密码等敏感信息,不要提交到 Git。建议创建 .env.example 作为模板提交,团队成员各自配置本地 .env 文件。CI/CD 流水线中通过注入环境变量而非文件来传递敏感信息。
坑 5:变量插值被禁用
某些场景下变量 ${VAR} 没有被替换,可能是使用了 `--no-interpolate` 选项,或者变量名拼写错误。用 docker compose config 命令可以查看最终解析后的配置,确认变量是否正确替换。
参考来源
- Docker Compose 多环境配置管理——一套配置轻松适配开发、测试、生产环境
- Docker Compose 环境变量配置详解 - 直角漫步 - 博客园
- Docker Compose 多环境变量管理 (从入门到生产级落地)
- Docker Compose 多环境变量管理:如何实现开发、测试、生产无缝切换
- 附 004.Docker Compose 环境变量说明
- 揭秘 docker-compose.yml 环境变量文件:如何优雅管理多环境配置