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

问题描述 投票:1812回答:11

Dockerfile中的COPYADD命令之间的区别是什么?我何时使用其中一个?

COPY <src> <dest>

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

ADD <src> <dest>

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

docker copy dockerfile
11个回答
1863
投票

您应该查看ADDCOPY文档以获得有关其行为的详尽描述,但简而言之,主要区别在于ADD可以做的不仅仅是COPY

  • ADD允许<src>成为URL
  • 参考下面的评论,ADD documentation明确指出: 如果是以识别的压缩格式(identity,gzip,bzip2或xz)的本地tar存档,则将其解压缩为目录。远程URL中的资源不会被解压缩。

请注意,Best practices for writing Dockerfiles建议使用COPY,其中不需要ADD的魔力。否则你(因为你必须查找这个答案)有一天你可能会感到惊讶,当你的意思是将keep_this_archive_intact.tar.gz复制到你的容器中,而是你把内容喷到你的文件系统上。


0
投票
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

385
投票

COPY

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

参考straight from the source code


128
投票

关于这一点,有一些官方文件:Best Practices for Writing Dockerfiles

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


106
投票

来自Docker文档:

添加或复制

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

更多:Best practices for writing Dockerfiles


35
投票

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


12
投票

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

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

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

例如:

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

与放置COPY相比,RUN步骤的缓存失效次数更少。 / 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。“


9
投票

COPY将主机中的文件/目录复制到您的映像。

ADD将主机中的文件/目录复制到您的映像,但也可以获取远程URL,提取TAR文件等...

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

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


4
投票

来源: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也允许您这样做,但它也支持其他2个来源。首先,您可以使用URL而不是本地文件/目录。其次,您可以将源文件中的tar文件直接提取到目标中

ADD的有效用例是当您要将本地tar文件解压缩到Docker镜像中的特定目录时。

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


2
投票

重要的提示

我不得不在我的docker镜像中使用COPY和解压缩java包。当我比较使用ADD创建的docker镜像大小时,它比使用COPY创建的大一倍,tar -xzf * .tar.gz和rm * .tar.gz

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

© www.soinside.com 2019 - 2024. All rights reserved.