mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-10 20:04:36 +00:00
262 lines
4.9 KiB
Go
262 lines
4.9 KiB
Go
## 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 编写指南
|