Files
docker_practice/07_dockerfile/7.1_run.md

181 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 7.1 RUN 执行命令
本节涵盖了相关内容与详细描述主要探讨以下几个方面
### 基本语法
如下代码块所示展示了相关示例
```docker
RUN <command>
RUN ["executable", "param1", "param2"]
```
`RUN` 指令是 Dockerfile 中最常用的指令之一它在**当前镜像层**之上创建一个新层执行指定的命令并提交结果
---
### 两种格式对比
本节涵盖了相关内容与详细描述主要探讨以下几个方面
#### 1Shell 格式
如下代码块所示展示了相关示例
```docker
RUN apt-get update
```
- **特点**默认通过 `/bin/sh -c` 执行
- **优势**可以使用环境变量管道重定向等 Shell 特性
- **示例**
```docker
RUN echo "Hello" > /test.txt
```
#### 2Exec 格式
如下代码块所示展示了相关示例
```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
```
---