Files
docker_practice/04_image/dockerfile/copy.md
2026-02-09 09:32:05 -08:00

262 lines
4.9 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

## 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)优化镜像大小
- [最佳实践](../../15_appendix/15.1_best_practices.md)Dockerfile 编写指南