基于本文回答

播面 播面

文解图解播客视频,多维讲透八股文
0
评论

COPY 和 ADD 指令有什么区别?在什么情况下应该优先使用 COPY?

在 Dockerfile 中,COPYADD 指令都用于将宿主机(构建上下文)中的文件或目录复制到容器镜像中。

尽管它们功能相似,但有明确的区别。官方推荐在绝大多数情况下优先使用 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:把压缩包当作普通文件复制过去。
    plaintext
    COPY archive.tar.gz /app/  # 容器中会得到一个 archive.tar.gz 文件
  • ADD:如果源文件是本地的已知压缩格式(tar, gzip, bzip2, xz 等),ADD 会自动将其解压成目录。
    plaintext
    ADD archive.tar.gz /app/  # 容器中会得到解压后的文件,而不是 tar.gz 压缩包
    注意:如果是网络上的压缩包(URL),ADD 只会下载,不会自动解压。

二、 为什么以及在什么情况下应该优先使用 COPY

Docker 官方的最佳实践指南明确指出:优先使用 COPY。原因如下:

1. 语义单一,意图明确

COPY 的功能非常纯粹,就是“复制”。当你看到 COPY 时,你确切地知道它只是把文件放进容器。而看到 ADD 时,你还需要猜测它是否会触发解压,或者是否在下载网络文件。

2. 避免镜像体积过大(针对网络下载)

虽然 ADD 可以下载网络文件,但极其不推荐这样做。

  • 不推荐的做法
    plaintext
    ADD http://example.com/large-package.tar.gz /tmp/
    RUN tar -xvf /tmp/large-package.tar.gz && rm /tmp/large-package.tar.gz
    问题:在 Docker 中,每一条指令都会创建一个镜像层(Layer)。使用 ADD 下载的文件会永久保存在上一层中,即使你在下一行用 rm 删除了它,镜像体积也不会变小。
  • 推荐的替代做法(使用 RUN + curl/wget):
    plaintext
    RUN wget http://example.com/large-package.tar.gz \
        && tar -xvf large-package.tar.gz \
        && rm large-package.tar.gz
    优势:下载、解压、删除在同一个 RUN 指令中完成,不会在最终镜像中留下无用的压缩包,镜像体积更小。

三、 什么时候应该使用 ADD

只有在以下唯一的场景下,才推荐使用 ADD

  • 需要将本地的压缩包(如 .tar.gz)自动解压到容器中

示例:

plaintext
# 制作基础系统镜像或安装本地打包好的软件
ADD rootfs.tar.xz /
ADD my-app-assets.tar.gz /app/

在这种情况下,ADD 一步完成了“复制 + 解压”两件事,比写 COPY 然后再写 RUN tar -xvf 更加简洁和高效。

总结

  • 默认选择:一律使用 COPY
  • 唯一例外:需要导入本地 tar 压缩包并自动解压时,使用 ADD