Release v1.5.0: Restructure chapters and update for Docker v30.x

This commit is contained in:
Baohua Yang
2026-02-04 22:12:38 -08:00
parent b4b0d4160a
commit fdb879dcf2
304 changed files with 1314 additions and 364 deletions

181
04_image/dockerfile/run.md Normal file
View File

@@ -0,0 +1,181 @@
# RUN 执行命令
## 基本语法
```docker
RUN <command>
RUN ["executable", "param1", "param2"]
```
`RUN` 指令是 Dockerfile 中最常用的指令之一它在**当前镜像层**之上创建一个新层执行指定的命令并提交结果
---
## 两种格式对比
### 1. Shell 格式
```docker
RUN apt-get update
```
- **特点**默认通过 `/bin/sh -c` 执行
- **优势**可以使用环境变量管道重定向等 Shell 特性
- **示例**
```docker
RUN echo "Hello" > /test.txt
```
### 2. Exec 格式
```docker
RUN ["apt-get", "update"]
```
- **特点**直接调用可执行文件不经过 Shell
- **优势**避免 Shell 字符串解析问题适用于参数中包含特殊字符的情况
- **注意**无法使用 `$VAR` 环境变量替换除非显式调用 shell
---
## 常见最佳实践
### 1. 组合命令减少层数
每一个 `RUN` 指令都会新建一层镜像为了减少镜像体积和层数应使用 `&&` 连接命令
** 糟糕的写法**创建 3
```docker
RUN apt-get update
RUN apt-get install -y nginx
RUN rm -rf /var/lib/apt/lists/*
```
** 推荐写法**创建 1
```docker
RUN apt-get update && \
apt-get install -y nginx && \
rm -rf /var/lib/apt/lists/*
```
### 2. 清理缓存
在安装完软件后立即清除缓存可以显著减小镜像体积
- **Debian/Ubuntu**:
```docker
RUN apt-get update && apt-get install -y package-bar \
&& rm -rf /var/lib/apt/lists/*
```
- **Alpine**:
```docker
RUN apk add --no-cache package-bar
```
### 3. 使用 `set -e` `pipefail`
默认情况下管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功整个 `RUN` 就视为成功
** 隐蔽的错误**
```docker
# 如果下载失败gzip 可能会报错,但如果不影响后续,构建可能继续
RUN wget http://error-url | gzip -d > file
```
** 推荐写法**
```docker
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN wget http://url | gzip -d > file
```
---
## 常见问题
### Q: 为什么 `RUN cd /app` 不生效
```docker
RUN cd /app
RUN touch hello.txt
```
**结果**`hello.txt` 会出现在根目录 `/`而不是 `/app`
**原因**每个 `RUN` 都在一个新的 Shell/容器 环境中执行`cd` 只影响当前 `RUN` 的环境
**解决**使用 `WORKDIR` 指令
```docker
WORKDIR /app
RUN touch hello.txt
```
### Q: 环境变量不生效
```docker
RUN export MY_VAR=hello
RUN echo $MY_VAR
```
**结果**输出为空
**原因**同上环境变量只在当前 `RUN` 有效
**解决**使用 `ENV` 指令或在同一行 `RUN` 中导出
```docker
ENV MY_VAR=hello
RUN echo $MY_VAR
```
---
## 高级技巧
### 1. 使用 BuildKit 的挂载缓存
BuildKit 支持在 `RUN` 指令中使用 `--mount` 挂载缓存加速构建
```docker
# 缓存 apt 包
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y gcc
```
```docker
# 缓存 Go 模块
RUN --mount=type=cache,target=/go/pkg/mod \
go build -o app
```
### 2. 挂载密钥
安全地使用 SSH 密钥或 Token而不将其记录在镜像中
```docker
RUN --mount=type=secret,id=mysecret \
cat /run/secrets/mysecret
```
---
## 本章小结
| 要点 | 说明 |
|------|------|
| **作用** | 在新层执行命令 |
| **原则** | 合并命令清理缓存 |
| **格式** | Shell (常用) vs Exec |
| **陷阱** | `cd` 不持久环境变量不持久 |
| **进阶** | 使用 Cache Mount 加速构建 |
## 延伸阅读
- [CMD 容器启动命令](cmd.md)容器启动时的命令
- [WORKDIR 指定工作目录](workdir.md)改变目录
- [Dockerfile 最佳实践](../../15_appendix/best_practices.md)