Docker Compose 环境变量详解:.env 和 env_file 有什么区别
前言
使用 Docker Compose 部署应用时,经常会遇到需要配置端口、运行模式、数据库地址等参数的情况。
为了避免把所有参数直接写进 compose.yaml,很多项目都会提供一个 .env 文件。但实际使用时,有时明明已经在 .env 中配置了变量,容器启动后却没有读取到。
这其实涉及 Docker Compose 中两个不同的概念:配置文件的变量替换,以及容器运行时的环境变量。
下面结合具体示例,介绍 .env、env_file 和 environment 的区别。
一、.env 文件的作用
先看一个简单的 Compose 项目:
myapp/
├── compose.yaml
└── .env
假设 .env 中保存:
APP_PORT=8080
IMAGE_TAG=3.20
在 compose.yaml 中可以这样使用:
services:
demo:
image: "alpine:${IMAGE_TAG}"
command: ["sleep", "3600"]
运行:
docker compose config
Compose 会解析配置文件中的变量,把 ${IMAGE_TAG} 替换成 .env 中的值。
最终镜像名称会被解析为:
alpine:3.20
需要注意,.env 的主要用途是为 Compose 提供变量替换所需的值。
把变量写进 .env,并不代表这些变量会自动出现在容器内部。
这也是不少环境变量问题的来源。
二、environment:明确传递容器环境变量
如果希望容器内部的程序能够读取某个变量,可以使用 environment。
例如:
services:
demo:
image: alpine:3.20
command: ["sleep", "3600"]
environment:
APP_MODE: production
LOG_LEVEL: debug
启动容器后,应用程序可以通过环境变量读取 APP_MODE 和 LOG_LEVEL。
environment 既支持上面的键值映射形式,也支持列表形式:
environment:
- APP_MODE=production
- LOG_LEVEL=debug
两种写法都可以使用。
如果不想把具体值写死,也可以结合 .env:
environment:
APP_MODE: "${APP_MODE:-development}"
这里的 ${APP_MODE:-development} 表示:如果 APP_MODE 没有设置,或者值为空,就使用 development 作为默认值。
这种方式很适合需要在测试环境和生产环境之间切换的应用。
三、env_file:从文件批量传递变量
如果一个应用有很多环境变量,全部写在 compose.yaml 中可能会让配置变得很长。
这时可以使用 env_file。
例如项目结构:
myapp/
├── compose.yaml
└── app.env
app.env 内容:
APP_MODE=production
LOG_LEVEL=info
FEATURE_FLAG=on
Compose 配置:
services:
demo:
image: alpine:3.20
command: ["sleep", "3600"]
env_file:
- ./app.env
这样 app.env 中的变量就会被传递到容器环境中。
与前面的 .env 自动加载机制不同,env_file 是在服务配置中明确指定一个文件,让其中的变量成为容器环境变量。
另外,env_file 支持指定多个文件:
env_file:
- ./common.env
- ./production.env
如果两个文件定义了同名变量,后面的文件通常会覆盖前面的值。
这里的相对路径以 Compose 配置文件所在目录为基准。
四、environment 和 env_file 同时配置怎么办?
这是一个比较常见的情况。
假设 app.env 中写着:
APP_MODE=development
LOG_LEVEL=info
而 compose.yaml 中又指定:
services:
demo:
image: alpine:3.20
command: ["sleep", "3600"]
env_file:
- ./app.env
environment:
APP_MODE: production
最终容器中的 APP_MODE 会是 production,而 LOG_LEVEL 仍然是 info。
原因是对于同一个服务,environment 中明确声明的变量会覆盖 env_file 中的同名变量。
需要注意,环境变量还有其他来源,例如 Dockerfile 中的 ENV、运行命令中的 -e,以及 Compose 变量插值使用的终端环境变量。
因此不能只根据两个文件的内容就判断最终结果,需要结合实际启动方式。
五、如何检查实际生效的变量?
Docker Compose 提供了一个很有用的命令:
docker compose config
它会解析 Compose 文件、合并配置并替换变量,可以检查最终生成的服务配置。
如果只想查看 Compose 用于变量替换的环境,可以执行:
docker compose config --environment
需要注意,这里查看的是 Compose 插值使用的变量,不等于容器内部最终拥有的全部变量。
如果希望直接检查容器内部的环境,可以针对支持 Shell 的容器执行:
docker compose exec demo env
前提是 demo 服务已经运行,并且容器中存在 env 命令。
对于上面使用 Alpine 镜像的示例,也可以通过一次性容器测试:
docker compose run --rm demo env
这通常比反复修改配置、重启容器来猜测变量是否生效更直接。
但这些命令可能显示敏感信息,排查时不要随意将输出粘贴到公开论坛。
六、–env-file 和 env_file 不是一回事
这两个名字非常接近,但使用位置不同。
例如:
docker compose --env-file ./config/dev.env config
这里的 --env-file 是 Compose 命令行参数,主要用于指定变量替换时使用的环境文件。
而:
services:
demo:
env_file:
- ./config/dev.env
这里的 env_file 是服务配置项,用于把文件中的变量传递到容器。
两者可以配合使用,但并不等价。
还有一个路径细节:
- 命令行
--env-file的相对路径通常基于执行命令的当前工作目录。 - 服务中的
env_file相对路径基于 Compose 文件的位置。
如果通过脚本或者管理面板执行 Compose,工作目录不同,就可能出现找不到环境文件的情况。
七、修改环境变量后为什么没有生效?
有时修改了 .env 或 app.env,然后执行:
docker compose restart
却发现容器里还是原来的值。
原因是 restart 主要用于重新启动现有容器,并不会因为环境文件发生变化就自动重新创建容器。
容器创建时的环境变量一般已经确定。
如果确实需要将新的环境配置应用到容器,可以考虑:
docker compose up -d --force-recreate demo
这个命令会重新创建指定服务的容器。
执行前需要确认业务的持久化目录、数据卷和重建影响。对于数据库等有状态服务,不建议在没有检查配置和备份的情况下直接重建。
八、环境变量不适合保存所有秘密信息
实际部署中,很多项目会把数据库密码、API Key 等内容放进环境文件。
这种方式虽然方便,但不代表数据已经被安全保护。
容器环境变量可能通过检查命令、进程信息或调试输出暴露,环境文件本身也可能被错误提交到 Git 仓库。
对于敏感凭据,可以根据实际环境考虑使用 Docker Compose secrets 或专门的密钥管理方案。
如果仍需使用本地环境文件,至少应该正确设置文件权限,并避免将包含真实凭据的文件提交到公开仓库。
总结
Docker Compose 中的环境变量主要涉及三个概念:
| 配置方式 | 主要用途 |
|---|---|
.env |
为 Compose 配置提供变量替换值 |
environment |
明确设置容器的环境变量 |
env_file |
从文件批量设置容器环境变量 |
最重要的是区分 Compose 解析配置时使用的变量,以及容器创建后实际拥有的环境变量。
遇到变量不生效的问题时,建议先使用 docker compose config 检查配置解析结果,再查看容器内部的环境变量,最后确认容器是否已经根据新配置重新创建。
这样通常比反复重启容器更容易定位问题。
- 点赞
- 收藏
- 关注作者
评论(0)