Files
docker_practice/07_dockerfile/7.6_env.md
T
yeasy 08e981018e fix(content): 修正四处书内自相矛盾的技术断言
1. FROM「必须是第一条指令」(4.5、7.16、summary 三处)与本书 7.7.4「FROM 之前的
   ARG」整节直接冲突。官方 Dockerfile 参考写的是 "A Dockerfile must begin with a
   FROM instruction. This may be after parser directives, comments, and globally
   scoped ARGs",且 "ARG is the only instruction that may precede FROM"。三处
   一并改成「第一条构建指令」并点明例外。

2. 12 章小结把 USER Namespace 列进「默认启用」的一档,并写「容器 root ≠ 宿主机
   root」;而同章 12.2.2 明写 USER Namespace 默认**不**启用、需 userns-remap 显式
   开启,18.1 更直说「在默认情况下,容器内的 root 用户(UID=0)就是宿主机上的
   root 用户」。小结按正文口径改回——这条读反了会直接误判容器逃逸的风险面。

3. 11.5「目前支持三种日志驱动类型」是 Compose 早期文本的残留。官方支持 json-file、
   local、syslog、journald、gelf、fluentd、awslogs、splunk、etwlogs、gcplogs、
   none 共十余种,本书 19 章小结自己就列了六种。改为给出常见取值并链到官方清单。

4. 7.8 与 7.5 的示例注释建议 postgres:latest / redis:latest,而 4.1、7.10、
   7.16、7 章小结、4.5 全都要求避免 latest(7.8 同一文件第 177 行也写「避免
   latest」)。按全书口径改掉这两处。

另:ENV 的空格分隔旧写法(7.6 的「格式一」、附录四的 PG_MAJOR/PATH 示例)改为等号
形式并加注。BuildKit 的 LegacyKeyValueFormat 检查会报
"ENV key=value" should be used instead of legacy "ENV key value" format,
而本书 10.2 与 07 章 README 正是在推荐 docker buildx build --check。
2026-08-07 23:26:12 -07:00

4.9 KiB
Raw Blame History

7.6 ENV 设置环境变量

7.6.1 基本语法

## 格式一:单个变量

ENV <key>=<value>

## 格式二:多个变量

ENV <key1>=<value1> <key2>=<value2> ...

⚠️ 用空格分隔的旧写法 ENV <key> <value>ARG 同理)虽然仍能构建,但已被官方弃用。BuildKit 的 LegacyKeyValueFormat 构建检查会报 "ENV key=value" should be used instead of legacy "ENV key value" formatdocker buildx build --check(见 10.2)会直接把它标出来。一律用等号。


7.6.2 基本用法

设置单个变量

ENV NODE_VERSION=20
ENV APP_ENV=production

设置多个变量

ENV NODE_VERSION=20 \
    APP_ENV=production \
    APP_NAME="My Application"

💡 包含空格的值用双引号括起来。


7.6.3 环境变量的作用

1. 后续指令中使用

ENV NODE_VERSION=20.10.0

## 在 RUN 中使用

RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz \
    | tar -xJ -C /usr/local --strip-components=1

## 在 WORKDIR 中使用

ENV APP_HOME=/app
WORKDIR $APP_HOME

## 在 COPY 中使用

COPY . $APP_HOME

2. 容器运行时使用

ENV DATABASE_URL=postgres://localhost/mydb

应用代码中可以读取:

import os
db_url = os.environ.get('DATABASE_URL')
const dbUrl = process.env.DATABASE_URL;

7.6.4 支持环境变量的指令

以下指令可以使用 $变量名${变量名} 格式:

指令 示例
RUN RUN echo $VERSION
CMD CMD ["sh", "-c", "echo $HOME"]
ENTRYPOINT 同上
COPY COPY . $APP_HOME
ADD ADD app.tar.gz $APP_HOME
WORKDIR WORKDIR $APP_HOME
EXPOSE EXPOSE $PORT
VOLUME VOLUME $DATA_DIR
USER USER $USERNAME
LABEL LABEL version=$VERSION
FROM FROM node:$NODE_VERSION

注意FROM 是上表中的特例——它只能引用在第一条 FROM 之前用 ARG 声明的变量,无法使用 ENV 定义的环境变量(ENV 要进入构建阶段后才生效)。其余指令才能引用 ENV 环境变量。


7.6.5 运行时覆盖

使用 -e--env 覆盖 Dockerfile 中定义的环境变量:

## 覆盖单个变量

$ docker run -e APP_ENV=development myimage

## 覆盖多个变量

$ docker run -e APP_ENV=development -e DEBUG=true myimage

## 从环境变量文件读取

$ docker run --env-file .env myimage

.env 文件格式

## .env

APP_ENV=development
DEBUG=true
DATABASE_URL=postgres://localhost/mydb

7.6.6 ENV vs ARG

特性 ENV ARG
生效时间 构建时 + 运行时 仅构建时
持久性 写入镜像,运行时可用 构建后消失
覆盖方式 docker run -e docker build --build-arg
适用场景 应用配置 构建参数 (如版本号)

组合使用

## ARG 接收构建时参数

ARG NODE_VERSION=20

## ENV 保存到运行时

ENV NODE_VERSION=$NODE_VERSION

## 后续指令使用

RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/...
## 构建时指定版本

$ docker build --build-arg NODE_VERSION=18 -t myapp .

7.6.7 最佳实践

1. 统一管理版本号

## ✅ 好:版本集中管理

ENV NGINX_VERSION=1.30 \
    NODE_VERSION=22 \
    PYTHON_VERSION=3.12

RUN apt-get install nginx=${NGINX_VERSION}

## ❌ 差:版本分散在各处

RUN apt-get install nginx=1.30

2. 不要存储敏感信息

## ❌ 错误:密码写入镜像

ENV DB_PASSWORD=secret123

## ✅ 正确:运行时传入

## docker run -e DB_PASSWORD=xxx myimage

...

3. 为应用提供合理默认值

ENV APP_ENV=production \
    APP_PORT=8080 \
    LOG_LEVEL=info

4. 使用有意义的变量名

## ✅ 好:清晰的命名

ENV REDIS_HOST=localhost \
    REDIS_PORT=6379

## ❌ 差:模糊的命名

ENV HOST=localhost \
    PORT=6379

7.6.8 常见问题

Q:环境变量在 CMD 中不展开

exec 格式不会自动执行 shell 展开,因此命令参数里的 $PORT 会按字面值传给进程;但环境变量本身仍会注入进程环境,应用可以通过语言运行时读取。

## ❌ 不会展开 $PORT

CMD ["python", "app.py", "--port", "$PORT"]

## ✅ 使用 shell 格式或显式调用 sh

CMD ["sh", "-c", "python app.py --port $PORT"]

Q:如何查看容器的环境变量

$ docker inspect mycontainer --format '{{json .Config.Env}}'
$ docker exec mycontainer env

Q:多行 ENV 还是多个 ENV

## ✅ 推荐:减少层数

ENV VAR1=value1 \
    VAR2=value2 \
    VAR3=value3

## ⚠️ 多个 ENV 会创建多层

ENV VAR1=value1
ENV VAR2=value2
ENV VAR3=value3