讲解

「同一份镜像,不同环境不同配置」是容器化部署的核心诉求,环境变量是最通用的注入方式——十二要素应用方法论把它列为配置的首选载体。docker run -e KEY=VALUE 逐个传,-e KEY 不带值则透传宿主机的同名变量;变量多了用 --env-file 文件路径(每行一个 KEY=VALUE,支持 # 注释),文件不该进 git(密码、密钥),用 .env.example 记录键名、真值放部署系统。

应用侧的职责是「从环境读配置」而不是「为每个环境打一份镜像」。镜像里只放合理默认值(比如监听 0.0.0.0:80),环境特异性(数据库地址、功能开关、密钥引用)全部外置。这样测试环境、预发、生产跑的是逐比特相同的镜像,差异只在启动参数——排障时少了一个巨大的变量。

两个补充手段:一是配置文件挂载(上一章的绑定挂载),适合nginx.conf 这类结构化配置;二是编排层的 secret 管理(Docker Swarm secrets、Kubernetes Secret),环境变量对高敏信息有泄露面(docker inspect、/proc/*/environ 可见),生产密钥应走 secret 机制或启动时从 vault 拉取。理解层级:默认值在镜像,环境变量给环境,secret 给密钥。

示例

-e 传参,容器里读到:

docker run --rm -e APP_ENV=staging -e APP_REGION=cn-hangzhou alpine:3.21 sh -c 'echo "$APP_ENV / $APP_REGION"'

--env-file 批量注入(先在沙盒里准备 env 文件):

printf 'DB_HOST=db.internal\nDB_PORT=3306\nDB_NAME=shop\n' > app.env
docker run --rm --env-file app.env alpine:3.21 sh -c 'echo "连接 $DB_HOST:$DB_PORT/$DB_NAME"'

env 文件不进版本库——这是纪律也是默认约定(Compose 会自动读取 .env):

docker run --rm -e GREETING=hello busybox:1.37 sh -c 'echo "$GREETING from busybox"'

查看运行中容器的环境变量(排障常用,注意敏感值会明文显示):

docker run -d --name ohmydocs-verify-envdemo -e TOKEN=demo-token alpine:3.21 sleep 60
docker exec ohmydocs-verify-envdemo sh -c 'echo "容器内看到 TOKEN=$TOKEN"'
docker rm -f ohmydocs-verify-envdemo

常见坑

  • 把 .env 提交进仓库:密钥泄露事故的头号来源;.gitignore 里加上,历史提交里有过要轮换密钥。
  • env 文件里写 export 或引号:--env-file 的解析器不认 export 前缀,值里的引号会被当字面量(不同工具行为不一,Compose 与 docker CLI 还略有差异)——保持裸 KEY=VALUE。
  • 以为 -e 能改运行中的容器:环境变量在启动时固化进进程,改配置必须重建容器;这正是「不可变基础设施」的刻意设计。
  • inspect 泄露秘密:docker inspect 能看到全部环境变量,高敏值改用 secret 挂载文件。

小结

-e 单传、--env-file 批量、绑定挂载给结构化配置、secret 给密钥;镜像只带默认值,环境差异全部外置。下一章让容器之间互相找到对方:网络。