管理 Docker 容器环境变量时,你面临的核心问题不是“怎么设”,而是“在哪里设、何时设、以及如何保证安全”。本文将直接给出判断路径:先确定变量的作用域(运行时还是构建时),再选择注入方式(命令行、文件、Compose 或 secrets),最后考虑安全与可维护性。若你正在使用 Kubernetes 或 OpenTelemetry 等云原生生态,环境变量的管理思路同样适用,但本文聚焦 Docker 本身。
运行时注入:-e 与 –env-file 的选择
最直接的方式是 docker run -e "KEY=VALUE",适用于临时测试或少量变量。但当你需要管理大量变量,或希望变量可复用、可版本控制时,应改用 --env-file。此选项从文件中读取键值对,每行一条,支持注释(以 # 开头)。
判断路径:变量少于 5 个且不重复使用,用 -e;否则用文件。注意 --env-file 不会自动忽略空行,且变量值中的空格会被保留,若值包含特殊字符(如 $),需使用单引号包裹以避免 shell 展开。
使用 docker-compose 统一管理
对于多容器应用,docker-compose 是更好的选择。在 docker-compose.yml 中,通过 environment 键直接定义,或使用 env_file 引用外部文件。更推荐的是使用 ${VAR} 语法引用宿主机环境变量或 .env 文件,实现“配置与代码分离”。
例如:
services:
web:
image: nginx
environment:
- DEBUG=${DEBUG:-false}
env_file:
- ./web.env
这里 ${DEBUG:-false} 表示若宿主变量未设置则取默认值。注意:Compose 会先加载 .env 文件,再加载 shell 环境变量,后者优先级更高。
构建时 ARG 与运行时 ENV 的区分
许多新手混淆 ARG 和 ENV。关键区别:ARG 只在构建阶段有效,用于传递构建参数(如版本号),不会保留在最终镜像中;ENV 则写入镜像,成为容器运行时的默认环境变量。若你希望构建时使用某值,但运行时覆盖,应同时定义 ARG 和 ENV,例如:
ARG VERSION=1.0
ENV APP_VERSION=$VERSION
失败条件:若在 Dockerfile 中仅使用 ARG,而运行容器时用 -e 覆盖同名变量,不会生效,因为 ARG 不进入运行时环境。反之,若将敏感信息(如密码)设为 ENV,则镜像中可能残留,存在泄露风险。
敏感信息:使用 secrets 而非环境变量
环境变量并非为保密而设计,任何能执行 docker inspect 的人都能看到它们。对于密码、密钥等敏感数据,Docker 提供了 secrets 机制(在 Swarm 或 Compose 中支持)。在 Compose 中,你可以这样声明:
secrets:
db_password:
file: ./db_password.txt
services:
app:
secrets:
- db_password
容器内会挂载为文件 /run/secrets/db_password,应用需读取该文件。这比环境变量更安全,因为 secrets 不会出现在 inspect 输出中。
环境变量的优先级与覆盖规则
当同名的环境变量在多个位置定义时,优先级从高到低为:docker run 命令行 -e > Compose 中 environment > env_file > Dockerfile 中的 ENV > 镜像默认值。理解这一点可避免“为什么我改了没生效”的困惑。
常见误区:在 Compose 中使用 environment: 时,若值未加引号,Compose 会将其视为字符串,不会进行变量替换。例如 - KEY=$HOSTNAME 会字面传递 $HOSTNAME,而非宿主机变量。正确做法是使用 ${HOSTNAME} 语法。
日志与排错:如何查看容器环境变量
排查问题时,你需要查看容器实际获得的环境变量。使用 docker inspect <container> 可查看全部配置,但更简洁的方式是 docker exec <container> env,直接列出运行时变量。若变量未显示,检查是否在构建阶段被覆盖,或容器启动脚本中是否有 unset 操作。
与云原生生态的衔接
在 Kubernetes 中,环境变量的管理方式类似,但引入了 ConfigMap 和 Secret 资源,它们可以挂载为文件或注入为环境变量。OpenTelemetry 等可观测性框架也常通过环境变量配置导出器端点。虽然这些属于更广的容器生态,但 Docker 阶段养成的“将配置与镜像分离”习惯,会帮助你平滑迁移到这些平台。
参考资料
延伸阅读
