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

时间:2014-07-25 14:31:20

标签: docker copy dockerfile

Dockerfile中的COPYADD命令有什么区别,我何时使用其中一个?

COPY <src> <dest>
  

COPY指令将从<src>复制新文件,并将其添加到路径<dest>

的容器文件系统中
ADD <src> <dest>
  

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

17 个答案:

答案 0 :(得分:1818)

您应该查看ADDCOPY文档,详细了解其行为,但简而言之,主要区别在于ADD可以做的不仅仅是COPY

  • ADD允许<src>成为网址
  • 如果<src>的{​​{1}}参数是已识别压缩格式的存档,则会将其解压缩

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

答案 1 :(得分:379)

COPY

  

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

参考straight from the source code

答案 2 :(得分:127)

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

  

由于图片大小很重要,因此强烈建议不要使用ADD从远程网址获取包。您应该使用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

答案 3 :(得分:104)

来自Docker文档:

  

添加或复制

     

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

更多:Best practices for writing Dockerfiles

答案 4 :(得分: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仅使用一层。

答案 5 :(得分:20)

创建Dockerfile时,有两个命令可用于将文件/目录复制到其中 ADD {{1 }} 。尽管它们的功能范围略有不同,但它们实际上执行相同的任务。

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

DOCKER COPY命令

首先请注意 ADD 命令早于 ADD 。自从Docker平台启动以来, COPY 指令已成为其命令列表的一部分。

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

ADD 命令的基本语法为:

ADD

它包括要复制的源( ADD <src> … <dest> ),后跟要存储它的目标( <src> )。如果源是目录,则 <dest> 复制其中的所有内容(包括文件系统元数据)。

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

ADD

ADD /source/file/path /destination/path 也可以从URL复制文件。它可以下载外部文件并将其复制到所需的目的地。例如:

ADD

另一个功能是,它可以复制压缩文件,自动提取给定目标中的内容。此功能仅适用于本地存储的压缩文件/目录。

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

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

DOCKER ADD source.file.tar.gz /temp 命令

由于某些功能问题,Docker必须引入一个额外的命令来复制内容– COPY

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

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

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

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

COPY

例如:

COPY <src> … <dest> 

要使用哪个命令?(最佳做法)

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

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

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

Docker团队还强烈不鼓励使用 COPY 从URL下载和复制软件包。相反,在 ADD 命令中使用wget或curl更安全,更有效。这样可以避免创建额外的图像层并节省空间。

答案 6 :(得分:12)

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

&#34;虽然ADD和COPY在功能上相似,但一般来说,COPY是首选。那是因为它比ADD更透明。 COPY仅支持将本地文件基本复制到容器中,而ADD具有一些功能(如仅限本地的tar提取和远程URL支持),这些功能并不是很明显。因此,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。&#34;

答案 7 :(得分:7)

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

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

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

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

答案 8 :(得分:5)

复制

这会将一个或多个本地文件或文件夹复制到Docker映像内的目标位置。

COPY < src> < dest >

COPY ["< source >",... "< destination >"] 

(对于包含空格的路径,此格式是必需的)

使用COPY的示例Dockerfile 这就是在Dockerfile中为Ruby应用程序使用COPY的方式。

FROM ruby:2.5.1
WORKDIR /usr/src/app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
CMD ["./your-daemon-or-script.rb"]

它从父图像ruby:2.5.1(使用FROM定义)开始,分层构建图像。

Docker指令WORKDIR为其后的COPYADD指令定义了一个工作目录。

通过复制Gemfiles后跟RUN bundle install,将使用已安装的Ruby Gems创建一个图像层,该图像层可以进行缓存。最后两条Docker指令将应用程序的文件复制到映像中,并使用CMD设置默认命令。

这意味着,如果您更改了应用程序的任何文件,则可以使用缓存的父层和中间层重建Docker映像。这比从头开始构建所有组件要有效得多。

添加

此指令的语法与COPY相似。

ADD < src> < dest >

ADD ["< source >",... "< destination >"] (this form is required for paths containing whitespace)

除了将本地文件和目录复制到Docker映像内的目标位置之外,它还具有一些其他功能:

如果<source>是采用公认压缩格式的本地tar归档文件,则它将作为目录自动解压缩到Docker映像中。例如:ADD rootfs.tar.xz /

如果<source>是URL,则它将下载文件并将其复制到Docker映像内的目标位置。但是,Docker不鼓励为此目的使用ADD。

从URL复制的Dockerfile最佳实践

Docker建议使用ADD从URL复制通常效率不高,并且最佳实践是使用其他策略来包含所需的远程文件。

由于图像大小很重要,因此强烈建议不要使用ADD从远程URL获取程序包;您应该使用curl或wget代替。这样,您可以删除提取后不再需要的文件,而不必在图像中添加其他图层。 — Dockerfile最佳实践

例如,您应该避免做以下事情:

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 http://example.com/big.tar.xz \
    | tar -xJC /usr/src/things \
    && make -C /usr/src/things all

对于不需要ADD的tar自动提取功能的其他项目(文件,目录),应始终使用COPY

答案 9 :(得分:4)

  1. COPY 不支持带有 URL 架构的 <src>
  2. COPY 不会解压压缩文件。
    对于 instruction <src> <dest>,如果 <src> 是 tar 压缩文件并且 <dest> 不以斜杠结尾:
    ADD<dest> 视为目录并将 <src> 解压到其中。
    COPY<dest> 视为文件并将 <src> 写入其中。
  3. COPY 支持通过 --from 参数覆盖构建上下文。

答案 10 :(得分:3)

来源: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文件从源文件直接提取到目标文件中

     

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

     

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

答案 11 :(得分:2)

重要提示

我必须在我的docker镜像中var givenNameClaim = new IdentityUserClaim<string>() { ClaimType = "given_name", ClaimValue = model.FirstName }; var familyNameClaim = new IdentityUserClaim<string>() { ClaimType = "family_name", ClaimValue = model.LastName }; var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; user.Claims.Add(givenNameClaim); user.Claims.Add(familyNameClaim); 并解压缩java包。 当我比较使用ADD创建的docker镜像大小时,它比使用COPY创建的大一倍,tar -xzf * .tar.gz和rm * .tar.gz

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

答案 12 :(得分:2)

假设您有一个tar文件,并且要在将其放入容器后将其解压缩,然后将其删除,则可以使用COPY命令执行此操作。但是,各种命令都是:1)将tar文件复制到目标位置; 2)。解压缩,3)删除tar文件。如果您分3个步骤进行操作,则每个步骤之后都会创建一个新图像。您可以使用&一步完成此操作,但这很麻烦。

但是您使用了ADD,那么Doc​​ker将为您处理所有事情,并且只会创建一个中间映像。

答案 13 :(得分:1)

自Docker 17.05 COPYmulti-stage builds中的--from标志一起使用以来,便将工件从先前的构建阶段复制到了当前的构建阶段。

来自documentation

  

(可选)COPY接受标志--from=<name|index>,该标志可用于将源位置设置为将使用的先前构建阶段(使用FROM .. AS创建),而不是用户发送的构建上下文。

答案 14 :(得分: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

答案 15 :(得分:0)

ADD和COPY都具有将文件和目录从源复制到目标的相同功能,但是ADD具有文件提取和URL文件提取功能。最佳实践是仅在复制操作中使用COPY,以避免ADD太多。该链接将通过一些简单的示例difference between COPY and ADD in dockerfile

对其进行说明。

答案 16 :(得分:0)

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

示例

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

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

示例

COPY Gemfile Gemfile.lock ./
COPY ./src/ /var/www/html/