COPY 和 ADD 指令有什么区别?在什么情况下应该优先使用 COPY?
在 Dockerfile 中,COPY 和 ADD 指令都用于将宿主机(构建上下文)中的文件或目录复制到容器镜像中。
尽管它们功能相似,但有明确的区别。官方推荐在绝大多数情况下优先使用 COPY。
一、 核心区别
| 特性 | COPY |
ADD |
|---|---|---|
| 基本复制功能 | 支持(本地文件/目录) | 支持(本地文件/目录) |
| 支持远程 URL | 不支持 | 支持(可以直接下载网络文件到镜像中) |
| 自动解压本地压缩包 | 不支持(仅作为普通文件复制) | 支持(会自动解压 tar.gz, tar.bz2, zip 等格式) |
| 语义清晰度 | 极高(只负责复制) | 较低(功能太多,容易产生副作用) |
1. 对远程 URL 的处理
COPY:不支持。如果你尝试COPY http://example.com/file.txt /app/,Docker 会报错。ADD:支持。ADD http://example.com/file.txt /app/会下载该文件并保存到容器中。
2. 对压缩包(Tar/Zip等)的处理
COPY:把压缩包当作普通文件复制过去。plaintextCOPY archive.tar.gz /app/ # 容器中会得到一个 archive.tar.gz 文件ADD:如果源文件是本地的已知压缩格式(tar, gzip, bzip2, xz 等),ADD会自动将其解压成目录。注意:如果是网络上的压缩包(URL),plaintextADD archive.tar.gz /app/ # 容器中会得到解压后的文件,而不是 tar.gz 压缩包ADD只会下载,不会自动解压。
二、 为什么以及在什么情况下应该优先使用 COPY?
Docker 官方的最佳实践指南明确指出:优先使用 COPY。原因如下:
1. 语义单一,意图明确
COPY 的功能非常纯粹,就是“复制”。当你看到 COPY 时,你确切地知道它只是把文件放进容器。而看到 ADD 时,你还需要猜测它是否会触发解压,或者是否在下载网络文件。
2. 避免镜像体积过大(针对网络下载)
虽然 ADD 可以下载网络文件,但极其不推荐这样做。
- 不推荐的做法:问题:在 Docker 中,每一条指令都会创建一个镜像层(Layer)。使用plaintext
ADD http://example.com/large-package.tar.gz /tmp/ RUN tar -xvf /tmp/large-package.tar.gz && rm /tmp/large-package.tar.gzADD下载的文件会永久保存在上一层中,即使你在下一行用rm删除了它,镜像体积也不会变小。 - 推荐的替代做法(使用
RUN+curl/wget):优势:下载、解压、删除在同一个plaintextRUN wget http://example.com/large-package.tar.gz \ && tar -xvf large-package.tar.gz \ && rm large-package.tar.gzRUN指令中完成,不会在最终镜像中留下无用的压缩包,镜像体积更小。
三、 什么时候应该使用 ADD?
只有在以下唯一的场景下,才推荐使用 ADD:
- 需要将本地的压缩包(如
.tar.gz)自动解压到容器中。
示例:
plaintext
# 制作基础系统镜像或安装本地打包好的软件
ADD rootfs.tar.xz /
ADD my-app-assets.tar.gz /app/
在这种情况下,ADD 一步完成了“复制 + 解压”两件事,比写 COPY 然后再写 RUN tar -xvf 更加简洁和高效。
总结
- 默认选择:一律使用
COPY。 - 唯一例外:需要导入本地
tar压缩包并自动解压时,使用ADD。