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,36 +1,196 @@
# WORKDIR 指定工作目录
格式为 `WORKDIR <工作目录路径>`
使用 `WORKDIR` 指令可以来指定工作目录或者称为当前目录以后各层的当前目录就被改为指定的目录如该目录不存在`WORKDIR` 会帮你建立目录
之前提到一些初学者常犯的错误是把 `Dockerfile` 等同于 Shell 脚本来书写这种错误的理解还可能会导致出现下面这样的错误
## 基本语法
```docker
RUN cd /app
RUN echo "hello" > world.txt
WORKDIR <工作目录路径>
```
如果将这个 `Dockerfile` 进行构建镜像运行后会发现找不到 `/app/world.txt` 文件或者其内容不是 `hello`原因其实很简单 Shell 连续两行是同一个进程执行环境因此前一个命令修改的内存状态会直接影响后一个命令而在 `Dockerfile` 这两行 `RUN` 命令的执行环境根本不同是两个完全不同的容器这就是对 `Dockerfile` 构建分层存储的概念不了解所导致的错误
`WORKDIR` 指定后续指令的工作目录如果目录不存在Docker 会自动创建
之前说过每一个 `RUN` 都是启动一个容器执行命令然后提交存储层文件变更第一层 `RUN cd /app` 的执行仅仅是当前进程的工作目录变更一个内存上的变化而已其结果不会造成任何文件变更而到第二层的时候启动的是一个全新的容器跟第一层的容器更完全没关系自然不可能继承前一层构建过程中的内存变化
---
因此如果需要改变以后各层的工作目录的位置那么应该使用 `WORKDIR` 指令
## 基本用法
```docker
WORKDIR /app
RUN echo "hello" > world.txt
RUN pwd # 输出 /app
RUN echo "hello" > world.txt # 创建 /app/world.txt
COPY . . # 复制到 /app/
```
如果你的 `WORKDIR` 指令使用的相对路径那么所切换的路径与之前的 `WORKDIR` 有关
---
## 为什么需要 WORKDIR
### 常见错误
```docker
# ❌ 错误cd 在下一个 RUN 中无效
RUN cd /app
RUN echo "hello" > world.txt # 文件在根目录!
```
### 原因分析
```
RUN cd /app
启动容器 → cd /app仅内存变化→ 提交镜像层 → 容器销毁
↓ 工作目录未改变!
RUN echo "hello" > world.txt
启动新容器(工作目录在 /)→ 创建 /world.txt
```
每个 RUN 都在新容器中执行**前一个 RUN 的内存状态包括工作目录不会保留**
### 正确做法
```docker
# ✅ 正确:使用 WORKDIR
WORKDIR /app
RUN echo "hello" > world.txt # 创建 /app/world.txt
```
---
## 相对路径
WORKDIR 支持相对路径基于上一个 WORKDIR
```docker
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
RUN pwd # 输出 /a/b/c
```
`RUN pwd` 的工作目录为 `/a/b/c`
---
## 使用环境变量
```docker
ENV APP_HOME=/app
WORKDIR $APP_HOME
RUN pwd # 输出 /app
```
---
## 多阶段构建中的 WORKDIR
```docker
# 构建阶段
FROM node:20 AS builder
WORKDIR /build
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY --from=builder /build/dist .
```
---
## 最佳实践
### 1. 尽早设置 WORKDIR
```docker
FROM node:20
WORKDIR /app # 尽早设置
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "server.js"]
```
### 2. 使用绝对路径
```docker
# ✅ 推荐:绝对路径,意图明确
WORKDIR /app
# ⚠️ 避免:相对路径可能造成混淆
WORKDIR app
```
### 3. 不要用 RUN cd
```docker
# ❌ 避免
RUN cd /app && echo "hello" > world.txt
# ✅ 推荐
WORKDIR /app
RUN echo "hello" > world.txt
```
### 4. 适时重置 WORKDIR
```docker
WORKDIR /app
# ... 应用相关操作 ...
WORKDIR /data
# ... 数据相关操作 ...
```
---
## 与其他指令的关系
| 指令 | WORKDIR 的影响 |
|------|---------------|
| `RUN` | WORKDIR 中执行命令 |
| `CMD` | WORKDIR 中启动 |
| `ENTRYPOINT` | WORKDIR 中启动 |
| `COPY` | 相对目标路径基于 WORKDIR |
| `ADD` | 相对目标路径基于 WORKDIR |
```docker
WORKDIR /app
RUN pwd # /app
COPY . . # 复制到 /app
CMD ["./start.sh"] # /app/start.sh
```
---
## 运行时覆盖
使用 `-w` 参数覆盖工作目录
```bash
$ docker run -w /tmp myimage pwd
/tmp
```
---
## 本章小结
| 要点 | 说明 |
|------|------|
| **作用** | 设置后续指令的工作目录 |
| **语法** | `WORKDIR /path` |
| **自动创建** | 目录不存在会自动创建 |
| **持久性** | 影响后续所有指令直到下次 WORKDIR |
| **不要用** | `RUN cd /path`无效 |
## 延伸阅读
- [COPY 复制文件](copy.md)文件复制
- [RUN 执行命令](../../image/build.md)执行构建命令
- [最佳实践](../../appendix/best_practices.md)Dockerfile 编写指南