
docker compose 仅在启动时读取项目根目录下的 `.env` 文件,且环境变量需显式声明在 `docker-compose.yml` 中才会注入容器;修改 `.env` 后必须重新运行 `docker-compose up`(而非仅重建镜像),否则旧值仍会被缓存使用。
在 FastAPI 项目中使用 Docker 容器化部署时,许多开发者会依赖 .env 文件管理配置(如数据库 URL、密钥等),并期望通过 docker-compose up 自动加载更新。但实际中常遇到「修改 .env 后容器内 echo $VAR 仍显示旧值甚至为空」的问题——这并非 FastAPI 或 Docker 的 Bug,而是由 Docker Compose 的环境变量加载机制导致的。
? 核心机制说明
- .env 文件仅被 docker-compose 进程读取(用于替换 docker-compose.yml 中的 ${VAR} 占位符),不会自动挂载或注入到容器内部;
- 容器内能否访问某个环境变量,取决于 docker-compose.yml 中是否通过 environment 或 env_file 显式声明;
- docker-compose build --no-cache 只重建镜像,不重启容器,也不重新解析 .env;真正触发 .env 重读的操作是 docker-compose up(含 up --build)。
✅ 正确操作步骤
-
在 docker-compose.yml 中声明变量(推荐使用 environment 显式透传):
services: api: build: . environment: - DATABASE_URL - SECRET_KEY - NEW_FEATURE_ENABLED # ← 新增变量必须在此显式列出 # env_file: .env # 不推荐:会将整个文件内容注入,存在安全与覆盖风险
-
确保 .env 文件位于 docker-compose.yml 同级目录,格式为纯键值对:
DATABASE_URL=postgresql://user:pass@db:5432/app SECRET_KEY=dev-secret-key NEW_FEATURE_ENABLED=true
-
每次修改 .env 后,执行完整重启流程:
# 停止并移除旧容器(不删镜像也可) docker-compose down
重新构建(可选 --no-cache)并启动,强制重读 .env
docker-compose up --build -d
> ⚠️ 注意:`docker-compose up --build` 是关键——仅 `build` 或仅 `up` 都不会刷新环境变量。 ### ❌ 常见误区排查 - **误以为 `docker-compose build` 会读 `.env`** → 实际上它只读构建上下文,`.env` 变量需经 `docker-compose.yml` 中转; - **未在 `environment` 中声明新变量** → 即使 `.env` 已添加,容器内也无法访问; - **使用 `env_file: .env` 但路径错误或权限受限** → 推荐优先用 `environment` + `.env` 替换方式,更可控; - **在容器内修改 `.env` 文件** → 容器内 `.env` 对宿主机无影响,且重启后丢失(应始终修改宿主机上的 `.env`)。 ### ? 补充建议:开发环境快速验证 可在 `docker-compose.yml` 中临时加入调试命令,确认变量是否生效: ```yaml command: sh -c "echo 'DB: $$DATABASE_URL' && echo 'NEW: $$NEW_FEATURE_ENABLED' && uvicorn app.main:app --host 0.0.0.0:8000"
注意:$$ 是 YAML 中转义 $ 的写法,确保变量在容器启动时展开。
总结来说,Docker Compose 的环境变量传递是“静态声明 + 启动时注入”模型。保持 .env 与 docker-compose.yml 声明一致,并坚持 down + up --build 流程,即可彻底解决变量不更新问题。










