Back to Docker Practice

7.3 Add

07_dockerfile/7.3_add.md

1.11.05.1 KB
Original Source

7.3 ADD 更高级的复制文件

何时使用 ADD?何时用 COPY?

在开始前,让我们直言不讳:在大多数情况下,你应该使用 COPY,而不是 ADD

ADDCOPY 基础上增加了两个额外功能。它不是 COPY 的通用替代品,但在少数场景中更合适:

  1. 自动解压 tar 压缩包(有时你想复制一个 .tar.gz 本身,而 ADD 会意外地解压它)
  2. 支持从 URL 下载公开远程文件,并可配合 --checksum 做校验

实践中的建议:本地普通文件默认用 COPY;本地 tar 自动解压或公开远程 artifact 下载并校验时用 ADD;需要认证、请求头、重试或自定义解压流程时用 RUN curl/wget

7.3.1 基本语法

docker
ADD [选项] <源路径>... <目标路径>
ADD [选项] ["<源路径>", ... "<目标路径>"]

ADDCOPY 基础上增加了两个功能:

  1. 自动解压 tar 压缩包
  2. 支持从 URL 下载文件

7.3.2 ADD vs COPY 详细对比

特性COPYADD
复制本地文件
自动解压 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:<digest> 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:<digest> 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:<digest> 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