核心是构建通用镜像,所有环境共用同一镜像,差异仅通过运行时注入的环境变量体现;基础镜像不写死环境参数,统一构建、按需注入变量,应用运行时直接读取环境变量,敏感信息严格隔离。
核心思路是:构建一个通用镜像,所有环境都用它;差异只通过运行时注入的环境变量体现,不改镜像、不重打包。
统一构建基础镜像
在 Dockerfile 中不写死任何环境相关参数(如数据库地址、日志级别、调试开关),只安装运行必需的软件和依赖。PHP 应用就装好 PHP 版本、扩展、Composer 依赖;Node.js 应用就装好 Node、npm 包、构建产物。镜像里不设 ENV NODE_ENV=development 这类固定值。
- 构建命令统一为:
docker build -t myapp:latest . - 开发、测试、生产全部拉取并运行同一个
myapp:latest镜像 - 确保镜像不含敏感信息(如密码、密钥),也不挂载本地源码(那是开发阶段的覆盖行为)
运行时按需注入变量
不同环境启动容器时,用环境变量动态控制行为。Docker Compose 提供三种主流方式,推荐组合使用:
-
env_file:把一组变量放在文件里,比如
.env.dev、.env.prod,内容如DB_HOST=db-dev或LOG_LEVEL=warn;在 compose 文件中用env_file: [.env.dev]引入 -
environment:在
docker-compose.prod.yml中直接写- APP_ENV=production,这类变量优先级高于 env_file,适合强制覆盖 -
命令行传参:CI/CD 流水线中执行
ENV_NAME=staging docker compose up,变量可被 compose 文件中的${ENV_NAME}插值使用
应用内正确读取变量
镜像里的程序必须从运行时环境读取配置,而不是从代码或配置文件硬编码。例如:
- Node.js:
process.env.DB_HOST或dotenv加载(但注意不要加载本地 .env 文件,应由容器注入) - PHP:
getenv('DB_HOST')或 Symfony/DI 容器自动绑定环境变量 - Java Spring Boot:
@Value("${db.host}"),配合--spring.profiles.active=prod触发对应 profile
避免在应用启动前用 shell 脚本根据变量生成配置文件——这会增加启动复杂度;更推荐直接读取环境变量做逻辑分支。
安全与隔离要点
敏感变量(如数据库密码、API 密钥)绝不能写进 docker-compose.yml 或 Git 仓库:
- 用独立的
.env.secrets文件,加入.gitignore,仅本地或 CI 环境提供 - 生产环境建议对接外部密钥管理服务(如 HashiCorp Vault、AWS Secrets Manager),通过 init 容器或 sidecar 注入
- 不同环境的 env_file 文件名明确区分(
.env.productionvs.env.development),启动命令中显式指定,防止误用











