Add more content

This commit is contained in:
Baohua Yang
2026-01-30 16:48:39 -08:00
parent c58f61dbed
commit fec2e506d9
39 changed files with 8202 additions and 1063 deletions

View File

@@ -1,33 +1,141 @@
# SHELL 指令
格式`SHELL ["executable", "parameters"]`
`SHELL` 指令可以指定 `RUN` `ENTRYPOINT` `CMD` 指令的 shellLinux 中默认为 `["/bin/sh", "-c"]`
## 基本语法
```docker
SHELL ["executable", "parameters"]
```
`SHELL` 指令允许覆盖 Docker 默认的 shell
- **Linux 默认**`["/bin/sh", "-c"]`
- **Windows 默认**`["cmd", "/S", "/C"]`
该指令会影响后续的 `RUN`, `CMD`, `ENTRYPOINT` 指令当它们使用 shell 格式时
---
## 为什么要用 SHELL 指令
### 1. 使用 bash 特性
默认的 `/bin/sh`通常是 dash alpine ash功能有限如果你需要使用 bash 的特有功能如数组`{}` 扩展`pipefail` 可以切换 shell
```docker
FROM ubuntu:24.04
# 切换到 bash
SHELL ["/bin/bash", "-c"]
# 现在可以使用 bash 特性了
RUN echo {a..z}
```
### 2. 增强错误处理 (pipefail)
默认情况下管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功整个指令就视为成功这可能掩盖构建错误
```docker
# ❌ 这里的 wget 失败了,但构建继续(因为 tar 成功了)
RUN wget -O - https://invalid-url | tar xz
```
使用 `SHELL` 启用 `pipefail`
```docker
# ✅ 启用 pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# 如果 wget 失败,整个 RUN 就会失败
RUN wget -O - https://invalid-url | tar xz
```
### 3. Windows 环境
Windows 容器中经常需要在 `cmd` `powershell` 之间切换
```docker
FROM mcr.microsoft.com/windows/servercore:ltsc2022
# 默认是 cmd
RUN echo Default shell is cmd
# 切换到 powershell
SHELL ["powershell", "-command"]
RUN Write-Host "Hello from PowerShell"
# 切回 cmd
SHELL ["cmd", "/S", "/C"]
```
---
## 作用范围
`SHELL` 指令可以出现多次每次只影响其后的指令
```docker
FROM ubuntu:24.04
# 使用默认 sh
RUN echo "Using sh"
SHELL ["/bin/bash", "-c"]
# 使用 bash
RUN echo "Using bash"
SHELL ["/bin/sh", "-c"]
RUN lll ; ls
SHELL ["/bin/sh", "-cex"]
RUN lll ; ls
# 回到 sh
RUN echo "Using sh again"
```
两个 `RUN` 运行同一命令第二个 `RUN` 运行的命令会打印出每条命令并当遇到错误时退出
---
`ENTRYPOINT` `CMD` shell 格式指定时`SHELL` 指令所指定的 shell 也会成为这两个指令的 shell
## 对其他指令的影响
`SHELL` 影响的是所有使用 **shell 格式** 的指令
| 指令格式 | 是否受 SHELL 影响 |
|---------|-------------------|
| `RUN command` | |
| `RUN ["exec", "param"]` | |
| `CMD command` | |
| `CMD ["exec", "param"]` | |
| `ENTRYPOINT command` | |
| `ENTRYPOINT ["exec", "param"]` | |
---
## 最佳实践
### 1. 推荐开启 pipefail
对于使用 bash 的镜像强烈建议开启 `pipefail`以确保构建过程中的错误能被及时捕获
```docker
SHELL ["/bin/sh", "-cex"]
# /bin/sh -cex "nginx"
ENTRYPOINT nginx
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
```
```docker
SHELL ["/bin/sh", "-cex"]
### 2. 明确意图
# /bin/sh -cex "nginx"
CMD nginx
```
如果由于脚本需求必须更改 shell最好在 Dockerfile 中显式声明而不是依赖默认行为
### 3. 尽量保持一致
避免在 Dockerfile 中频繁切换 SHELL这会使构建过程难以理解和调试尽量在头部定义一次即可
---
## 本章小结
| 要点 | 说明 |
|------|------|
| **作用** | 更改 RUN/CMD/ENTRYPOINT 的默认 shell |
| **Linux 默认** | `["/bin/sh", "-c"]` |
| **Windows 默认** | `["cmd", "/S", "/C"]` |
| **推荐用法** | `SHELL ["/bin/bash", "-o", "pipefail", "-c"]` |
| **影响范围** | 后续所有使用 shell 格式的指令 |
## 延伸阅读
- [RUN 指令](../../image/build.md)执行命令
- [Dockerfile 最佳实践](../../appendix/best_practices.md)错误处理与调试