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

Dockerfile中的COPYADD命令之间有什么区别,以及什么时候使用另一个呢?


 COPY <src> <dest> 

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


 ADD <src> <dest> 

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

您应该检查ADDCOPY文档以详细描述它们的行为,但简而言之,主要区别在于ADD可以做的不仅仅是COPY

  • ADD允许<src>成为一个URL
  • 如果ADD<src>参数是以可识别的压缩格式存档,则它将被解压缩

请注意, 编写Dockerfiles的最佳实践build议使用COPY ,其中不需要ADD的魔力。 否则,当你将keep_this_archive_intact.tar.gz复制到你的容器中时,你(因为你不得不查找这个答案)可能会感到惊讶,而是将内容喷到你的文件系统上。

COPY

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

直接从源代码中引用。

关于这一点有一些官方文档: 写入Dockerfiles的最佳实践

由于图像大小很重要,强烈build议使用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自动提取function的其他项目(文件,目录),您应该始终使用COPY

从Docker文档:

ADD或COPY

尽pipeADD和COPY在function上是相似的,但一般来说,COPY是首选。 这是因为它比ADD更透明。 COPY只支持将本地文件复制到容器中,而ADD则具有一些特性(如仅限本地的tar提取和远程URL支持),这些function并不是很明显。 因此,ADD的最佳用法是将本地tar文件自动提取到映像中,如ADD rootfs.tar.xz /中所示。

更多: 编写Dockerfiles的最佳实践

如果要将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仅使用一层。

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

“虽然ADD和COPY在function上是相似的,但一般来说,COPY是首选,这是因为它比ADD更透明,COPY只支持将本地文件复制到容器中,而ADD具有一些function(如仅限本地的tar提取和远程URL支持),因此,ADD的最佳用途是将本地tar文件自动提取到映像中,如ADD rootfs.tar.xz /中所示。

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

例如:

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

导致RUN步骤中caching失效的次数比放置COPY的次数less。 / tmp /之前。

由于图像大小很重要,强烈build议使用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自动提取function的其他项目(文件,目录),您应该始终使用COPY。

COPY将适用于大多数情况。

ADD具有COPY所有function,并具有以下附加function:

允许在图像中的tar文件自动提取 ,例如,

 ADD app.tar.gz /opt/var/myapp. 

允许从远程URL下载文件。 但是,下载的文件将成为图像的一部分。 这会导致图像大小膨胀。 因此, build议使用cURL或Wget来明确下载存档,提取和删除存档。

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

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

这与其他卷不同,因为它仅为构build安装主机目录。 文件可以使用标准的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 

重要的提示

我不得不在我的docker镜像中复制和解压Java包。 当我比较使用ADD创build的docker图像大小时,它比使用COPY创build的大180MB,tar -xzf * .tar.gz和rm * .tar.gz

这意味着虽然ADD删除了tar文件,但它仍然保留在某个地方。 它使图像大!