绝大多数情况下用 COPY,只在明确需要自动解压本地 tar 包或从 URL 下载文件时才考虑 ADD;COPY 语义清晰、缓存友好、行为可预测,而 ADD 因支持解压和 URL 下载,易导致缓存失效与不可预期行为。

直接说结论:绝大多数情况下用 COPY,只在明确需要自动解压本地 tar 包或从 URL 下载文件时才考虑 ADD。
COPY 是默认选择,语义清晰、缓存友好
COPY 只做一件事:把构建上下文里的文件或目录原样复制进镜像。它不碰 URL,不解压,不额外处理,行为完全可预期。
- 源路径必须在构建上下文中(比如
docker build .当前目录下的文件) - 支持通配符(如
COPY *.py /app/),也支持--chown设置属主 - 文件元数据(权限、时间戳等)会被保留,对 Git 管理的项目很友好
- 只要源文件内容没变,该层就能命中构建缓存,后续指令也能复用
ADD 的特殊能力:解压和拉取 URL
ADD 比 COPY 多两个功能,但它们是“有代价的”:
- 如果
<src>是本地的.tar.gz、.bz2或.xz文件,ADD 会自动解压后复制内容(不是把压缩包放进去) - 支持从 HTTP/HTTPS URL 下载文件(如
ADD https://example.com/config.json /etc/) - 但注意:URL 下载无法认证,且每次构建都会重新下载,必然失效缓存
- 解压行为不可关闭——哪怕你只想把 tar 包原样放进去,ADD 也会强行解压
哪些情况该用 ADD?
真要用 ADD,得满足以下任一条件,且能接受它的副作用:
- 你有一份本地压缩包(比如
app.tar.gz),希望构建时直接解到目标目录,且确认不需要保留原始压缩包 - 你需要从公开无认证的 URL 获取一个配置文件或小资源(但更推荐用
RUN curl -o+COPY,可控性更强)
其他所有场景——复制代码、配置、二进制、静态资源——一律用 COPY。
别踩的坑
几个常见误用点:
- 用 ADD 复制普通文件(如
ADD nginx.conf /etc/nginx/)——完全没必要,还可能意外触发解压逻辑 - 用 ADD 拉取需要登录的私有 URL ——会失败,应改用
RUN wget --header="Authorization: ..." -O - 把 ADD 放在 Dockerfile 前面 ——一旦 URL 不稳定或 tar 内容变动,整个后续构建都失去缓存


















