在Dockerfile中,“COPY”和“ADD”命令有什么区别?

3021

COPYADD 命令在 Dockerfile 中有什么区别?我应该何时使用其中一个而不是另一个?

COPY <src> <dest>

COPY指令会将<src>中的新文件复制到容器文件系统的路径<dest>

ADD <src> <dest>

ADD 指令将从 <src> 复制新文件,并将其添加到容器的文件系统中的路径 <dest>


16
查看最佳实践:https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#add-or-copy - acanimal
24
截至2018年6月,参考文献表示ADD将文件添加到镜像(即静态文件),而COPY将其添加到容器中(即镜像的运行时实例)。这是否意味着每次运行Docker镜像时都会执行COPY操作?或者这只是术语不一致的情况? - Chris Robinson
1
@ChrisRobinson 在主机上运行 docker cp(Docker 命令行)将复制文件到/从正在运行的容器。Dockerfile 中的 COPY 指令用于构建镜像。 - Jurn Ho
17个回答

2899
你应该查看ADDCOPY的文档,以获取更详细的行为描述,但简而言之,主要区别在于ADDCOPY功能更强大:
  • ADD允许<src>是一个URL
  • 根据下面的评论,ADD文档中指出:

如果<src>是一个本地tar归档文件,且是已知的压缩格式(identity,gzip,bzip2或xz),则它将被解压为一个目录。来自远程URL的资源不会被解压缩。

请注意,编写Dockerfile的最佳实践建议在不需要ADD的神奇功能时使用COPY。否则,你(因为你不得不查找这个答案)可能会在某一天感到惊讶,当你想要将keep_this_archive_intact.tar.gz复制到你的容器中时,却意外地将其内容喷洒到你的文件系统上。

806

COPY 是相同于 'ADD' 的命令,但不涉及 tar 和远程 URL 处理。

该命令与 'ADD' 相同,但没有处理 tar 和远程 URL 的功能。

参考自源代码


4
这是我读过的最好的答案。 - kukelia
2
称赞简短可靠的回答,加1点赞为实际源代码链接! - theoctober19th

166

这一点有官方文档说明:Dockerfile 最佳实践

由于镜像大小的问题,强烈不建议使用 ADD 命令从远程 URL 获取软件包;您应该使用 curl 或者 wget 替代。这样,您可以在文件被解压后删除不再需要的文件,并且无需在您的镜像中添加另一个层。

RUN mkdir -p /usr/src/things \
  && curl -SL http://example.com/big.tar.gz \
    | tar -xJC /usr/src/things \
  && make -C /usr/src/things all
对于不需要 ADD 自动解压能力的其他项目(文件、目录),您应始终使用 COPY。

147

来自Docker文档:

ADD或COPY

虽然ADD和COPY在功能上类似,但一般而言,COPY更受欢迎。这是因为它比ADD更透明。COPY仅支持将本地文件基本复制到容器中,而ADD具有一些特性(例如仅限本地的tar文件提取和远程URL支持),这些特性不是立即明显的。因此,ADD最好用于将本地tar文件自动提取到镜像中,例如ADD rootfs.tar.xz /。

更多信息:编写Dockerfile的最佳实践


71
如果您想将一个 xx.tar.gz 添加到容器内的 /usr/local 中,请先解压缩它,然后删除无用的压缩包。

对于 COPY 指令:

COPY resources/jdk-7u79-linux-x64.tar.gz /tmp/
RUN tar -zxvf /tmp/jdk-7u79-linux-x64.tar.gz -C /usr/local
RUN rm /tmp/jdk-7u79-linux-x64.tar.gz

对于注意力缺陷障碍(ADD):

ADD resources/jdk-7u79-linux-x64.tar.gz /usr/local/

ADD支持本地解压tar文件,而COPY将使用三个层级,但ADD只使用一个层级。


56
创建Dockerfile时,有两个命令可以用来将文件/目录复制到其中 - ADDCOPY。虽然它们的功能范围略有不同,但本质上执行相同的任务。
那么,为什么我们有两个命令,以及如何知道何时使用其中之一?
DOCKER ADD 命令

===

首先,我们要注意到ADD命令比COPY命令更早。自Docker平台推出以来,ADD指令一直是其命令列表的一部分。
该命令将文件/目录复制到指定容器的文件系统中。 ADD命令的基本语法如下:
ADD <src><dest>

它包括您想要复制的源文件(<src>),然后是您想要存储它的目标位置(<dest>)。如果源文件是一个目录,ADD会复制其中的所有内容(包括文件系统元数据)。

例如,如果文件在本地可用,并且您想将其添加到图像目录中,您可以输入:

ADD /source/file/path  /destination/path

ADD还可以从URL复制文件。它可以下载外部文件并将其复制到所需的目标位置。例如:

ADD http://source.file/url  /destination/path

一个附加功能是它能够复制压缩文件,并自动解压缩内容到指定目标位置。这个功能仅适用于本地存储的压缩文件/目录。
ADD source.file.tar.gz /temp

请记住,您无法从URL下载并解压缩压缩文件/目录。当将其复制到本地文件系统时,该命令不会解压外部包。DOCKER COPY命令。

===

由于某些功能问题,Docker 不得不引入了一个额外的命令来复制内容 - COPY

与其紧密相关的ADD命令不同,COPY只有一个分配的功能。它的作用是以现有格式在指定位置复制文件/目录。这意味着它不处理解压缩文件,而是直接复制。

该指令仅适用于本地存储的文件。因此,您不能使用它来复制外部文件到容器中的 URL。

要使用COPY指令,请按照基本命令格式进行操作:

输入源和要提取内容的位置,格式如下:

COPY <src> … <dest> 

例如:

COPY /source/file/path  /destination/path 

使用哪个命令?(最佳实践)

考虑到引入COPY命令的情况,很明显保留ADD是必要的。Docker发布了一份官方文档,概述了编写Dockerfile的最佳实践,明确建议不要使用ADD命令。

Docker的官方文档指出,COPY应该始终是首选指令,因为它比ADD更透明。

如果您需要将本地构建上下文复制到容器中,请坚持使用COPY

Docker团队还强烈反对使用ADD从URL下载和复制软件包。相反,更安全和高效的做法是在RUN命令中使用wget或curl。通过这样做,您可以避免创建额外的镜像层并节省空间。

参考:https://phoenixnap.com/kb/docker-add-vs-copy


5
你从 https://phoenixnap.com/kb/docker-add-vs-copy 复制了整个答案,请不要把别人的工作当做自己的。 - skomisa
1
他已经引用了来源,因此没有歪曲事实。 - brohjoe

49

COPY 命令可将文件/目录从主机复制到镜像。

ADD 命令不仅可以从主机复制文件/目录到镜像,还可以获取远程URL、提取TAR文件等等...

使用COPY仅将文件和/或目录简单地复制到构建环境中。

使用ADD下载远程资源,提取TAR文件等等...


23

根据Docker文档:https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#add-or-copy

"尽管ADD和COPY在功能上类似,但通常情况下,推荐使用COPY。因为它比ADD更加透明。COPY仅支持将本地文件简单复制到容器中,而ADD具有一些特性(例如仅本地tar文件提取和远程URL支持),这些特性不够明显。因此,ADD最佳用法是将本地tar文件自动解压缩到镜像中,例如:ADD rootfs.tar.xz /。

如果你的多个Dockerfile步骤需要从上下文中使用不同的文件,请逐个COPY它们,而不是一次性复制所有文件。这将确保每个步骤的构建缓存仅在特定所需文件更改时被失效(强制重新运行该步骤)。

例如:

 COPY requirements.txt /tmp/
 RUN pip install --requirement /tmp/requirements.txt
 COPY . /tmp/

RUN步骤中,如果您将COPY . /tmp/放在它之前,则会导致较少的缓存失效。

由于镜像大小很重要,强烈不建议使用ADD从远程URL获取软件包; 相反,您应该使用curl或wget。这样,在提取文件后,您可以删除不再需要的文件,而无需在镜像中添加另一层。例如,您应该避免执行以下操作:

 ADD http://example.com/big.tar.xz /usr/src/things/
 RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
 RUN make -C /usr/src/things all

相反,要做类似这样的事情:

 RUN mkdir -p /usr/src/things \
     && curl -SL htt,p://example.com/big.tar.xz \
     | tar -xJC /usr/src/things \
     && make -C /usr/src/things all

对于不需要 ADD 的 tar 自动解压功能的其他项目(文件、目录),您应该始终使用 COPY。


15

来源: https://nickjanetakis.com/blog/docker-tip-2-the-difference-between-copy-and-add-in-a-dockerile:

COPY和ADD都是Dockerfile指令,具有类似的用途。它们允许您将文件从特定位置复制到Docker镜像中。

COPY使用src和destination参数。它只允许您将本地文件或目录(即构建Docker镜像的主机)复制到Docker镜像本身中。

ADD也可以做到这一点,但它还支持另外两种来源。首先,您可以使用URL而不是本地文件/目录。其次,您可以直接将源中的tar文件提取到目标位置。

使用ADD的一个有效用例是,当您想要将本地tar文件提取到Docker镜像中的特定目录时。

如果要将本地文件复制到Docker镜像中,请始终使用COPY,因为它更明确。


10
自Docker 17.05以来,多阶段构建中使用--from标志与COPY一起复制先前构建阶段的工件到当前构建阶段。
来自文档
引用: 可选地,COPY接受一个--from=<name|index>标志,可用于设置源位置为之前的构建阶段(使用FROM..AS创建),而不是用户发送的构建上下文。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接