## 7.3 ADD 更高级的复制文件 ### 何时使用 ADD?何时用 COPY? 在开始前,让我们直言不讳:**在大多数情况下,你应该使用 COPY,而不是 ADD**。 `ADD` 在 `COPY` 基础上增加了两个额外功能。它不是 `COPY` 的通用替代品,但在少数场景中更合适: 1. 自动解压 tar 压缩包(有时你想复制一个 .tar.gz 本身,而 ADD 会意外地解压它) 2. 支持从 URL 下载公开远程文件,并可配合 `--checksum` 做校验 **实践中的建议**:本地普通文件默认用 COPY;本地 tar 自动解压或公开远程 artifact 下载并校验时用 ADD;需要认证、请求头、重试或自定义解压流程时用 `RUN curl/wget`。 ### 7.3.1 基本语法 ```docker ADD [选项] <源路径>... <目标路径> ADD [选项] ["<源路径>", ... "<目标路径>"] ``` `ADD` 在 `COPY` 基础上增加了两个功能: 1. 自动解压 tar 压缩包 2. 支持从 URL 下载文件 --- ### 7.3.2 ADD vs COPY 详细对比 | 特性 | COPY | ADD | |------|------|-----| | 复制本地文件 | ✅ | ✅ | | 自动解压 tar | ❌ | ✅ | | 支持 URL | ❌ | ✅ (公开 artifact 可配合校验使用)| | 行为可预测性 | ✅ 高 | ⚠️ 低 | | 推荐程度 | ✅ **普通复制优先使用** | 解压、本地 Git/公开远程 artifact | > **笔者建议**:普通复制始终优先 COPY;只有当你明确需要 ADD 的额外语义时再使用 ADD,并把意图写清楚。 --- ### 7.3.3 自动解压功能 #### 基本用法:自动解压本地 tar ```docker ## 自动解压 tar.gz 到目标目录 ADD app.tar.gz /app/ ``` ADD 会识别并解压以下格式: - `.tar` - `.tar.gz` / `.tgz` - `.tar.bz2` / `.tbz2` - `.tar.xz` / `.txz` #### 实际应用 官方基础镜像通常使用 ADD 解压根文件系统: ```docker FROM scratch ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz / ``` #### 解压过程 ```bash ADD app.tar.gz /app/ │ ├─ 识别 .tar.gz 格式 ├─ 自动解压 └─ 内容放入 /app/ app.tar.gz 包含: /app/ 目录结果: ├── src/ ├── src/ │ └── main.py │ └── main.py └── config.json └── config.json ``` --- ### 7.3.4 URL 下载功能:谨慎使用 #### 基本用法 ```docker ## 从 URL 下载文件 ADD https://example.com/app.zip /app/app.zip ``` #### 使用边界 | 场景 | 建议 | |------|------| | 公开、版本固定的远程 artifact | 使用 `ADD --checksum=sha256:... URL dest` | | 需要认证、请求头或复杂重试 | 使用 `RUN curl/wget` | | 下载后需要复杂解压、校验或清理 | 使用 `RUN curl/wget`,把流程显式写出 | | URL 内容可变但无校验 | 不建议直接写入 Dockerfile | #### 推荐写法 ```docker ## ✅ 公开 artifact:使用 ADD 并固定校验值 ADD --checksum=sha256: https://example.com/app.tar.gz /tmp/app.tar.gz RUN tar -xzf /tmp/app.tar.gz -C /app && rm /tmp/app.tar.gz ## ✅ 需要认证、请求头或特殊处理:使用 RUN + curl RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app ``` `ADD --checksum` 的优势是缓存更精确,并且校验值直接绑定到 Dockerfile。`RUN curl/wget` 的优势是控制力更强,适合企业内网、认证下载或复杂处理。 --- ### 7.3.5 修改文件所有者 ```docker ADD --chown=node:node app.tar.gz /app/ ADD --chown=1000:1000 files/ /app/ ``` --- ### 7.3.6 何时使用 ADD #### ✅ 适合使用 ADD ```docker ## 解压本地 tar 文件 FROM scratch ADD rootfs.tar.gz / ## 解压应用包 ADD dist.tar.gz /app/ ## 下载公开 artifact 并校验 ADD --checksum=sha256: https://example.com/app.tar.gz /tmp/app.tar.gz ``` #### ❌ 不适合使用 ADD ```docker ## 复制普通文件(用 COPY) ADD package.json /app/ # ❌ COPY package.json /app/ # ✅ ## 需要认证或复杂下载逻辑(用 RUN + curl/wget) ADD https://example.com/file / # ❌ 无法传认证信息,也没有显式处理 RUN curl -fsSL ... -o /file # ✅ ## 需要保留 tar 不解压(用 COPY) ADD archive.tar.gz /archives/ # ❌ 会解压 COPY archive.tar.gz /archives/ # ✅ 保持原样 ``` --- ### 7.3.7 缓存行为 ADD 可能导致构建缓存失效: ```docker ## 如果 app.tar.gz 内容变化,此层及后续层都需重建 ADD app.tar.gz /app/ RUN npm install ``` **优化建议**: ```docker ## 先复制依赖文件 COPY package*.json /app/ RUN npm install ## 再添加应用代码 ADD app.tar.gz /app/ ``` --- ### 7.3.8 最佳实践 #### 1. 默认使用 COPY ```docker ## ✅ 大多数场景使用 COPY COPY . /app/ ``` #### 2. 仅在需要解压时使用 ADD ```docker ## ✅ 自动解压场景 ADD app.tar.gz /app/ ``` #### 3. 远程 artifact 使用 ADD 时必须固定校验值 ```docker ## ✅ 公开 artifact ADD --checksum=sha256: https://example.com/file.tar.gz /tmp/file.tar.gz ## ✅ 认证下载或复杂处理 RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app ``` #### 4. 解压后清理 ```docker ## 如果需要控制解压过程 COPY app.tar.gz /tmp/ RUN tar -xzf /tmp/app.tar.gz -C /app && \ rm /tmp/app.tar.gz ``` ---