Dockerfile中的'COPY'和'ADD'命令有什么区别?

Dockerfile中的COPYADD命令有什么区别,什么时候我会使用一个而不是另一个?

COPY <src> <dest>

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

ADD <src> <dest>

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

948465 次浏览

您应该查看#0#1留档以获取有关其行为的更详细描述,但简而言之,主要区别在于ADD可以比COPY做得更多:

  • ADD允许<src>是URL
  • 关于下面的评论,ADD留档指出:

如果是公认的压缩格式(标识、gzip、bzip2或xz)的本地tar存档,则将其解压缩为目录。来自远程URL的资源不会解压缩。

请注意,编写Dockerfile的最佳实践建议在不需要ADD魔力的地方使用COPY。否则,当您打算将keep_this_archive_intact.tar.gz复制到容器中时(既然你要查这个答案)可能会感到惊讶,但相反,您将内容喷射到文件系统上。

COPY

与“ADD”相同,但没有tar和远程URL处理。

参考直接从源代码

关于这一点有一些官方留档:编写Dockerfile的最佳实践

由于图像大小很重要,强烈建议不要使用ADD从远程URL获取包;您应该使用curlwget代替。这样您就可以在提取后删除不再需要的文件,并且不必在图像中添加另一层。

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的tar自动提取功能的其他项目(文件、目录),您应该始终使用COPY

从Docker文档:

添加或复制

虽然ADD和COPY功能类似,但总体来说还是首选COPY。那是因为它比ADD透明,COPY只支持将本地文件基本拷贝到容器中,而ADD有一些特性(比如只提取本地tar,支持远程URL)不是很明显。因此ADD最好的用途是将本地tar文件自动提取到镜像中,就像ADDrootfs.tar.xz /.

更多:编写Dockerfile的最佳实践

如果要将xx.tar.gz添加到容器中的/usr/local,请将其解压缩,然后删除无用的压缩包。

复制:

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

对于添加:

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

ADD支持局部焦油提取。除此之外,COPY将使用三层,但ADD只使用一层。

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文件,就像ADDrootfs.tar.xz /.

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

例如:

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

与将COPY. /tmp/放在RUN步骤之前相比,会导致更少的缓存失效。

由于图像大小很重要,强烈建议不要使用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/thingsRUN 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。

docker build -t {image name} -v {host directory}:{temp build directory} .

这是将文件复制到图像中的另一种方法。-v选项临时创建我们在构建过程中使用的卷。

这与其他卷不同,因为它仅为构建安装主机目录。可以使用标准cp命令复制文件。

此外,与curl和wget一样,它可以在命令堆栈中运行(在单个容器中运行)而不会乘以图像大小。ADD和COPY不可堆叠,因为它们在独立容器中运行,并且在其他容器中执行的文件上的后续命令将乘以图像大小:

这样设置选项:

-v /opt/mysql-staging:/tvol

以下内容将在一个容器中执行:

RUN cp -r /tvol/mysql-5.7.15-linux-glibc2.5-x86_64 /u1 && \mv /u1/mysql-5.7.15-linux-glibc2.5-x86_64 /u1/mysql && \
mkdir /u1/mysql/mysql-files && \mkdir /u1/mysql/innodb && \mkdir /u1/mysql/innodb/libdata && \mkdir /u1/mysql/innodb/innologs && \mkdir /u1/mysql/tmp && \
chmod 750 /u1/mysql/mysql-files && \chown -R mysql /u1/mysql && \chgrp -R mysql /u1/mysql

#0将文件/目录从主机复制到映像。

#0将文件/目录从主机复制到映像,但也可以获取远程URL、提取TAR文件等…

使用#0简单地将文件和/或目录复制到构建上下文中。

使用#0下载远程资源、提取TAR文件等。

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

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

COPY接受src和目标。它只允许您将本地文件或目录从主机(构建Docker映像的机器)复制到Docker映像本身。

ADD也允许您这样做,但它也支持其他两个源。首先,您可以使用URL而不是本地文件/目录。其次,您可以从源直接提取tar文件到目标

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

如果要将本地文件复制到Docker映像,请始终使用COPY,因为它更显式。

由于Docker 17.05COPY多阶段构建中的--from标志一起使用,将工件从前一个构建阶段复制到当前构建阶段。

留档

可选地,COPY接受一个标志--from=<name|index>,该标志可用于将源位置设置为将用于代替用户发送的构建上下文的上一个构建阶段(使用from… AS创建)。

创建Dockerfile时,有两个命令可用于复制文件/目录进入它-#0#1。虽然它们的功能范围略有不同,但它们基本上执行相同的任务。

那么,为什么我们有两个命令,我们如何知道何时使用一个或另一个?

DOCKERADD命令

===

让我们首先注意#0命令比#1早。自Docker平台推出以来,#0指令一直是其命令列表的一部分。

该命令将文件/目录复制到指定容器的文件系统。

#0命令的基本语法是:

ADD <src> … <dest>

它包括要复制的源(#0),然后是要存储它的目标(#1)。如果源是一个目录,#2复制其中的所有内容(包括文件系统元数据)。

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

ADD /source/file/path  /destination/path

#0还可以从URL复制文件。它可以下载外部文件并将其复制到所需的目的地。例如:

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

一个附加功能是它复制压缩文件,自动将内容提取到给定目的地。此功能仅适用于本地存储的压缩文件/目录。

ADD source.file.tar.gz /temp

请记住,您不能从URL下载和提取压缩文件/目录。将外部包复制到本地文件系统时,该命令不会解包。

DOCKERCOPY命令

===

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

与密切相关的#0命令不同,#1只有一个分配的功能。它的作用是以现有格式复制指定位置的文件/目录。这意味着它不处理提取压缩文件,而是按原样复制它。

该指令只能用于本地存储的文件。因此,您不能将其与URL一起使用以将外部文件复制到您的容器。

要使用COPY指令,请遵循基本命令格式:

输入源代码以及您希望命令提取内容的位置,如下所示:

COPY <src> … <dest>

例如:

COPY /source/file/path  /destination/path

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

考虑到#0命令引入的环境,很明显保留#1是必要的。Docker发布了一份官方文档,概述了编写Dockerfile的最佳实践,其中明确建议不要使用#1命令。

Docker的官方留档指出,#0应该始终是首选指令,因为它比#1更透明。

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

Docker团队也强烈反对使用#0从URL下载和复制包。相反,在#1命令中使用wget或curl更安全、更高效。这样做可以避免创建额外的图像层并节省空间。

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

假设您有一个tar文件,并且您想在将其放入容器后解压它,将其删除,您可以使用COPY命令执行此操作。但是各种命令将是1)将tar文件复制到目标,2)。解压它,3)删除tar文件。如果您分3步完成此操作,那么每个步骤后都会创建一个新图像。您可以使用&在一步中完成此操作,但它会变得很麻烦。

但是您使用了ADD,那么Docker将为您处理一切,并且只会创建一个中间映像。

ADD和COPY都具有将文件和目录从源复制到目标的相同功能,但ADD具有额外的文件提取和URL文件提取功能。最佳做法是仅在复制操作中使用COPY,仅避免ADD有很多方面。链接将用一些简单的示例来解释它dockerfile中COPY和ADD的区别

ADD指令从本地或远程源复制文件或文件夹,并将它们添加到容器的文件系统中。它用于复制本地文件,这些文件必须位于工作目录中。ADD指令将本地.tar文件解压缩到目标映像目录。

示例

ADD http://someserver.com/filename.pdf /var/www/html

COPY从工作目录复制文件并将它们添加到容器的文件系统中。使用其URL和此Dockerfile指令无法复制远程文件。

示例

COPY Gemfile Gemfile.lock ./COPY ./src/ /var/www/html/
  1. COPY不支持<src>的URL方案。
  2. COPY没有解压压缩文件。
    对于instruction <src> <dest>,如果<src>是tar压缩文件并且<dest>不以尾随斜杠结尾:
    ADD<dest>视为目录并将<src>解压缩到它。
    COPY<dest>视为一个文件并将<src>写入其中。
  3. COPY支持通过--from参数覆盖构建上下文。

如果您有一个foo.tar.gz文件,比较以下命令。ADD命令创建的图层比COPY命令少,并且在推送docker镜像时节省了大量的网络流量。

ADD foo.tar.gz /
COPY foo.tar.gz /RUN tar -zxvf foo.tar.gzRUN rm -rf foo.tar.gz