This commit is contained in:
Baohua Yang
2026-02-09 12:56:12 -08:00
parent 63377d0431
commit b44c9acd6c
228 changed files with 326 additions and 271 deletions

307
07_dockerfile/7.2_copy.md Normal file
View File

@@ -0,0 +1,307 @@
## 7.2 COPY 复制文件
### 基本语法
具体内容如下
```docker
COPY [选项] <源路径>... <目标路径>
COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
```
`COPY` 指令将构建上下文中的文件或目录复制到镜像内
---
### 基本用法
#### 复制单个文件
具体内容如下
```docker
## 复制文件到指定目录
COPY package.json /app/
## 复制文件并重命名
COPY config.json /app/settings.json
```
#### 复制多个文件
具体内容如下
```docker
## 复制多个指定文件
COPY package.json package-lock.json /app/
## 使用通配符
COPY *.json /app/
COPY src/*.js /app/src/
```
#### 复制目录
具体内容如下
```docker
## 复制整个目录的内容(不是目录本身)
COPY src/ /app/src/
```
> **注意**复制目录时复制的是目录的**内容**不包含目录本身
```
构建上下文: 镜像内:
src/ /app/src/
├── index.js → ├── index.js
└── utils.js └── utils.js
```
---
### 通配符规则
COPY 支持 Go `filepath.Match` 通配符规则
| 通配符 | 说明 | 示例 |
|--------|------|------|
| `*` | 匹配任意字符序列 | `*.json` |
| `?` | 匹配单个字符 | `config?.json` |
| `[abc]` | 匹配括号内任一字符 | `[abc].txt` |
| `[a-z]` | 匹配范围内字符 | `file[0-9].txt` |
```docker
COPY hom* /mydir/ # home.txt, homework.md 等
COPY hom?.txt /mydir/ # home.txt, homy.txt 等
COPY app[0-9].js /app/ # app0.js ~ app9.js
```
---
### 目标路径
#### 绝对路径
具体内容如下
```docker
COPY app.js /usr/src/app/
```
#### 相对路径基于 WORKDIR
具体内容如下
```docker
WORKDIR /app
COPY package.json ./ # 复制到 /app/package.json
COPY src/ ./src/ # 复制到 /app/src/
```
#### 自动创建目录
如果目标目录不存在Docker 会自动创建
```docker
## /app/config/ 不存在也会自动创建
COPY settings.json /app/config/
```
---
### 修改文件所有者
使用 `--chown` 选项设置文件的用户和组
```docker
## 使用用户名和组名
COPY --chown=node:node package.json /app/
## 使用 UID 和 GID
COPY --chown=1000:1000 . /app/
## 只指定用户
COPY --chown=node . /app/
```
> 💡 结合 `USER` 指令使用确保应用以非 root 用户运行
---
### 保留文件元数据
COPY 会保留源文件的元数据
- 执行权限
- 修改时间
这对于脚本文件特别重要
```docker
## start.sh 的可执行权限会被保留
COPY start.sh /app/
```
---
### COPY vs ADD
| 特性 | COPY | ADD |
|------|------|-----|
| 复制本地文件 | | |
| 自动解压 tar | | |
| 支持 URL | | 不推荐 |
| 推荐程度 | **推荐** | 特殊场景使用 |
```docker
## 推荐:使用 COPY
COPY app.tar.gz /app/
RUN tar -xzf /app/app.tar.gz
## ADD 会自动解压(行为不明显,不推荐)
ADD app.tar.gz /app/
```
> 笔者建议除非需要自动解压 tar 文件否则始终使用 COPY明确的行为比隐式的魔法更好
---
### 多阶段构建中的 COPY
#### 从其他构建阶段复制
具体内容如下
```docker
## 构建阶段
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
## 生产阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
```
#### 使用 --link 优化缓存BuildKit
具体内容如下
```docker
## 使用 --link 后,文件以独立层添加,不依赖前序指令
COPY --link --from=builder /app/dist /usr/share/nginx/html
```
`--link` 的优势
- 更高效利用构建缓存
- 并行化构建过程
- 加速多阶段构建
---
### .dockerignore
使用 `.dockerignore` 排除不需要复制的文件
```gitignore
## .dockerignore
node_modules
.git
.env
*.log
Dockerfile
.dockerignore
```
这可以
- 减小构建上下文大小
- 加速构建
- 避免复制敏感文件
---
### 最佳实践
#### 1. 利用缓存先复制依赖文件
具体内容如下
```docker
## ✅ 好:先复制依赖定义,再安装,最后复制代码
COPY package.json package-lock.json ./
RUN npm install
COPY . .
## ❌ 差:一次性复制所有文件,代码变更会导致重新 npm install
COPY . .
RUN npm install
```
#### 2. 使用 .dockerignore
具体内容如下
```docker
## 确保 node_modules 不被复制
COPY . .
## .dockerignore 中应包含 node_modules
具体内容如下:
```
#### 3. 明确复制路径
具体内容如下
```docker
## ✅ 好:明确的路径
COPY src/ /app/src/
COPY package.json /app/
## ❌ 差:过于宽泛
COPY . .
```
---
### 本章小结
| 操作 | 示例 |
|------|------|
| 复制文件 | `COPY app.js /app/` |
| 复制多个文件 | `COPY *.json /app/` |
| 复制目录内容 | `COPY src/ /app/src/` |
| 修改所有者 | `COPY --chown=node:node . /app/` |
| 从构建阶段复制 | `COPY --from=builder /app/dist ./` |
### 延伸阅读
- [ADD 指令](add.md)复制和解压
- [WORKDIR 指令](workdir.md)设置工作目录
- [多阶段构建](../multistage-builds.md)优化镜像大小
- [最佳实践](../../16_appendix/16.1_best_practices.md)Dockerfile 编写指南