7.3 ADD 更高階的複製檔案
何時使用 ADD?何時用 COPY?
在開始前,讓我們直言不諱:在大多數情況下,你應該使用 COPY,而不是 ADD。
ADD 在 COPY 基礎上增加了兩個額外功能。它不是 COPY 的通用替代品,但在少數場景中更合適:
- 自動解壓 tar 壓縮封裝(有時你想複製一個 .tar.gz 本身,而 ADD 會意外地解壓它)
- 支援從 URL 下載公開遠端檔案,並可配合
--checksum做校驗
實踐中的建議:本地普通檔案預設用 COPY;本地 tar 自動解壓或公開遠端 artifact 下載並校驗時用 ADD;需要認證、請求頭、重試或自定義解壓流程時用 RUN curl/wget。
7.3.1 基本語法
ADD [選項] <源路徑>... <目標路徑>
ADD [選項] ["<源路徑>", ... "<目標路徑>"]
ADD 在 COPY 基礎上增加了兩個功能:
- 自動解壓 tar 壓縮封裝
- 支援從 URL 下載檔案
7.3.2 ADD vs COPY 詳細對比
| 屬性 | COPY | ADD |
|---|---|---|
| 複製本地檔案 | ✅ | ✅ |
| 自動解壓 tar | ❌ | ✅ |
| 支援 URL | ❌ | ✅ (公開 artifact 可配合校驗使用) |
| 行為可預測性 | ✅ 高 | ⚠️ 低 |
| 推薦程度 | ✅ 普通複製優先使用 | 解壓、本地 Git/公開遠端 artifact |
筆者建議:普通複製始終優先 COPY;只有當你明確需要 ADD 的額外語義時再使用 ADD,並把意圖寫清楚。
7.3.3 自動解壓功能
基本用法:自動解壓本地 tar
## 自動解壓 tar.gz 到目標目錄
ADD app.tar.gz /app/
ADD 會識別並解壓以下格式:
.tar.tar.gz/.tgz.tar.bz2/.tbz2.tar.xz/.txz
實際應用
官方基礎映象通常使用 ADD 解壓根檔案系統:
FROM scratch
ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz /
解壓過程
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 下載功能:謹慎使用
基本用法
## 從 URL 下載檔案
ADD https://example.com/app.zip /app/app.zip
使用邊界
| 場景 | 建議 |
|---|---|
| 公開、版本固定的遠端 artifact | 使用 ADD --checksum=sha256:... URL dest |
| 需要認證、請求頭或複雜重試 | 使用 RUN curl/wget |
| 下載後需要複雜解壓、校驗或清理 | 使用 RUN curl/wget,把流程顯式寫出 |
| URL 內容可變但無校驗 | 不建議直接寫入 Dockerfile |
推薦寫法
## ✅ 公開 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 修改檔案所有者
ADD --chown=node:node app.tar.gz /app/
ADD --chown=1000:1000 files/ /app/
7.3.6 何時使用 ADD
✅ 適合使用 ADD
## 解壓本地 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
## 複製普通檔案(用 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 可能導致建立快取失效:
## 如果 app.tar.gz 內容變化,此層及後續層都需重建
ADD app.tar.gz /app/
RUN npm install
最佳化建議:
## 先複製依賴檔案
COPY package*.json /app/
RUN npm install
## 再新增應用程式碼
ADD app.tar.gz /app/
7.3.8 最佳實踐
1. 預設使用 COPY
## ✅ 大多數場景使用 COPY
COPY . /app/
2. 僅在需要解壓時使用 ADD
## ✅ 自動解壓場景
ADD app.tar.gz /app/
3. 遠端 artifact 使用 ADD 時必須固定校驗值
## ✅ 公開 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. 解壓後清理
## 如果需要控制解壓過程
COPY app.tar.gz /tmp/
RUN tar -xzf /tmp/app.tar.gz -C /app && \
rm /tmp/app.tar.gz