mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-08-10 16:37:34 +00:00
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。
254 lines
4.9 KiB
Go
254 lines
4.9 KiB
Go
## 7.6 ENV 设置环境变量
|
||
|
||
### 7.6.1 基本语法
|
||
|
||
```docker
|
||
## 格式一:单个变量
|
||
|
||
ENV <key>=<value>
|
||
|
||
## 格式二:多个变量
|
||
|
||
ENV <key1>=<value1> <key2>=<value2> ...
|
||
```
|
||
> ⚠️ 用空格分隔的旧写法 `ENV <key> <value>`(`ARG` 同理)虽然仍能构建,但已被官方弃用。BuildKit 的
|
||
> [LegacyKeyValueFormat](https://docs.docker.com/reference/build-checks/legacy-key-value-format/) 构建检查会报
|
||
> `"ENV key=value" should be used instead of legacy "ENV key value" format`,`docker buildx build --check`(见 [10.2](../10_buildx/10.2_buildx.md))会直接把它标出来。一律用等号。
|
||
|
||
---
|
||
|
||
### 7.6.2 基本用法
|
||
|
||
#### 设置单个变量
|
||
|
||
```docker
|
||
ENV NODE_VERSION=20
|
||
ENV APP_ENV=production
|
||
```
|
||
|
||
#### 设置多个变量
|
||
|
||
```docker
|
||
ENV NODE_VERSION=20 \
|
||
APP_ENV=production \
|
||
APP_NAME="My Application"
|
||
```
|
||
> 💡 包含空格的值用双引号括起来。
|
||
|
||
---
|
||
|
||
### 7.6.3 环境变量的作用
|
||
|
||
#### 1. 后续指令中使用
|
||
|
||
```docker
|
||
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. 容器运行时使用
|
||
|
||
```docker
|
||
ENV DATABASE_URL=postgres://localhost/mydb
|
||
```
|
||
应用代码中可以读取:
|
||
|
||
```python
|
||
import os
|
||
db_url = os.environ.get('DATABASE_URL')
|
||
```
|
||
```javascript
|
||
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 中定义的环境变量:
|
||
|
||
```bash
|
||
## 覆盖单个变量
|
||
|
||
$ docker run -e APP_ENV=development myimage
|
||
|
||
## 覆盖多个变量
|
||
|
||
$ docker run -e APP_ENV=development -e DEBUG=true myimage
|
||
|
||
## 从环境变量文件读取
|
||
|
||
$ docker run --env-file .env myimage
|
||
```
|
||
|
||
#### .env 文件格式
|
||
|
||
```bash
|
||
## .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` |
|
||
| **适用场景** | 应用配置 | 构建参数 (如版本号)|
|
||
|
||
#### 组合使用
|
||
|
||
```docker
|
||
## ARG 接收构建时参数
|
||
|
||
ARG NODE_VERSION=20
|
||
|
||
## ENV 保存到运行时
|
||
|
||
ENV NODE_VERSION=$NODE_VERSION
|
||
|
||
## 后续指令使用
|
||
|
||
RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/...
|
||
```
|
||
```bash
|
||
## 构建时指定版本
|
||
|
||
$ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||
```
|
||
---
|
||
|
||
### 7.6.7 最佳实践
|
||
|
||
#### 1. 统一管理版本号
|
||
|
||
```docker
|
||
## ✅ 好:版本集中管理
|
||
|
||
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. 不要存储敏感信息
|
||
|
||
```docker
|
||
## ❌ 错误:密码写入镜像
|
||
|
||
ENV DB_PASSWORD=secret123
|
||
|
||
## ✅ 正确:运行时传入
|
||
|
||
## docker run -e DB_PASSWORD=xxx myimage
|
||
|
||
...
|
||
```
|
||
|
||
#### 3. 为应用提供合理默认值
|
||
|
||
```docker
|
||
ENV APP_ENV=production \
|
||
APP_PORT=8080 \
|
||
LOG_LEVEL=info
|
||
```
|
||
|
||
#### 4. 使用有意义的变量名
|
||
|
||
```docker
|
||
## ✅ 好:清晰的命名
|
||
|
||
ENV REDIS_HOST=localhost \
|
||
REDIS_PORT=6379
|
||
|
||
## ❌ 差:模糊的命名
|
||
|
||
ENV HOST=localhost \
|
||
PORT=6379
|
||
```
|
||
---
|
||
|
||
### 7.6.8 常见问题
|
||
|
||
#### Q:环境变量在 CMD 中不展开
|
||
|
||
exec 格式不会自动执行 shell 展开,因此命令参数里的 `$PORT` 会按字面值传给进程;但环境变量本身仍会注入进程环境,应用可以通过语言运行时读取。
|
||
|
||
```docker
|
||
## ❌ 不会展开 $PORT
|
||
|
||
CMD ["python", "app.py", "--port", "$PORT"]
|
||
|
||
## ✅ 使用 shell 格式或显式调用 sh
|
||
|
||
CMD ["sh", "-c", "python app.py --port $PORT"]
|
||
```
|
||
|
||
#### Q:如何查看容器的环境变量
|
||
|
||
```bash
|
||
$ docker inspect mycontainer --format '{{json .Config.Env}}'
|
||
$ docker exec mycontainer env
|
||
```
|
||
|
||
#### Q:多行 ENV 还是多个 ENV
|
||
|
||
```docker
|
||
## ✅ 推荐:减少层数
|
||
|
||
ENV VAR1=value1 \
|
||
VAR2=value2 \
|
||
VAR3=value3
|
||
|
||
## ⚠️ 多个 ENV 会创建多层
|
||
|
||
ENV VAR1=value1
|
||
ENV VAR2=value2
|
||
ENV VAR3=value3
|
||
```
|
||
---
|