2703

Dockerfile 中的COPY和命令有什么区别,我什么时候可以使用其中一个?ADD

COPY <src> <dest>

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

ADD <src> <dest>

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

4

16 回答 16

2637

您应该查看ADDCOPY文档以获取对其行为的更详细描述,但简而言之,主要区别在于ADD可以做的更多COPY

  • ADD允许<src>成为 URL
  • 参考下面的评论,ADD 文档指出:

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

请注意,编写 Dockerfiles 的最佳实践建议使用COPY不需要魔法的地方ADD。否则,当您打算复制到容器中时,您(因为您必须查找此答案keep_this_archive_intact.tar.gz)可能会感到惊讶,而是将内容喷到您的文件系统上。

于 2014-07-25T14:52:38.900 回答
635

COPY

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

直接从源代码中引用。

于 2014-09-30T16:13:40.500 回答
157

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

因为图像大小很重要,ADD所以强烈建议不要使用从远程 URL 获取包;你应该使用curlorwget代替。这样,您可以在提取后删除不再需要的文件,而无需在图像中添加另一层。

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

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

于 2014-10-02T08:21:42.590 回答
135

来自 Docker 文档:

添加或复制

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

更多:编写 Dockerfile 的最佳实践

于 2015-08-10T15:19:31.900 回答
56

如果要在/usr/localin container中添加一个xx.tar.gz,解压,然后去掉无用的压缩包。

对于复制:

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 resources/jdk-7u79-linux-x64.tar.gz /usr/local/

ADD 支持仅本地的 tar 提取。除此之外,COPY 将使用三层,而 ADD 仅使用一层。

于 2016-04-25T07:07:18.660 回答
45

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

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

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

用于ADD下载远程资源、提取 TAR 文件等。

于 2018-05-31T12:11:18.563 回答
37

创建 Dockerfile 时,您可以使用两个命令将文件/目录复制到其中 -ADDCOPY. 尽管它们的功能范围略有不同,但它们基本上执行相同的任务。

那么,为什么我们有两个命令,我们怎么知道什么时候使用其中一个呢?

码头工人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 下载和提取压缩文件/目录。该命令在将外部包复制到本地文件系统时不会对其进行解包。

码头工人COPY命令

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

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

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

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

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

COPY <src> … <dest> 

例如:

COPY /source/file/path  /destination/path 

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

考虑到COPY命令被引入的环境,很明显,遵守ADD是必要的。Docker 发布了一份官方文档,概述了编写 Dockerfiles 的最佳实践,其中明确建议不要使用该ADD命令。

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

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

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

于 2020-03-10T14:14:06.893 回答
22

来自 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 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。”

于 2016-06-12T05:29:48.207 回答
15

资料来源: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,因为它更明确。

于 2018-08-16T07:10:51.780 回答
9

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

文档

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

于 2019-08-28T20:31:15.047 回答
7
  1. COPY不支持<src>URL 方案。
  2. COPY不解压压缩文件。
    对于instruction <src> <dest>, if<src>是一个 tar 压缩文件并且<dest>不以斜杠结尾:将其
    ADD视为<dest>一个目录并解压缩<src>到它。
    COPY考虑<dest>作为一个文件并写入<src>它。
  3. COPY支持通过--fromarg 覆盖构建上下文。
于 2021-04-29T07:32:05.327 回答
5

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

例子

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

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

例子

COPY Gemfile Gemfile.lock ./
COPY ./src/ /var/www/html/
于 2021-02-24T06:17:18.823 回答
2

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

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

于 2020-06-30T01:33:33.270 回答
2

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

ADD foo.tar.gz /
COPY foo.tar.gz /
RUN tar -zxvf foo.tar.gz
RUN rm -rf foo.tar.gz
于 2021-10-01T13:23:41.830 回答
1

ADD 和 COPY 都具有将文件和目录从源复制到目标的相同功能,但 ADD 具有额外的文件提取和 URL 文件提取功能。最好的做法是在只复制操作中使用 COPY,只避免 ADD 是许多区域。该链接将通过dockerfile 中 COPY 和 ADD 之间的一些简单示例进行说明

于 2020-12-14T00:59:29.590 回答
-1
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
于 2016-09-23T19:32:40.240 回答