Was ist der Unterschied zwischen den Befehlen 'COPY' und 'ADD' in einer Docker-Datei?


2196

Was ist der Unterschied zwischen den Befehlen COPYund ADDin einer Docker-Datei und wann würde ich einen über den anderen verwenden?

COPY <src> <dest>

Die COPY-Anweisung kopiert neue Dateien aus <src>und fügt sie dem Dateisystem des Containers unter Pfad hinzu<dest>

ADD <src> <dest>

Die ADD-Anweisung kopiert neue Dateien aus <src>und fügt sie dem Dateisystem des Containers unter Pfad hinzu <dest>.



9
Im Juni 2018 heißt es in der Referenz, dass ADD dem Image (dh einer statischen Datei) hinzugefügt wird, während COPY dem Container (dh einer Laufzeitinstanz des Image) hinzugefügt wird. Dies impliziert sicherlich, dass COPY jedes Mal ausgeführt wird, wenn das Image von Docker ausgeführt wird, oder ist dies einfach ein Fall inkonsistenter Terminologie?
Chris Robinson

14
Ich denke, das ist inkonsistente Terminologie
Daniel Stevens

6
@ChrisRobinson, es wäre unmöglich, das COPYbei jeder Ausführung auszuführen, da es nicht unbedingt Zugriff auf den ursprünglichen Kontext hat, um den Inhalt abzurufen.
Ken Williams

Antworten:


2167

Sie sollten die Dokumentation ADDund die COPYDokumentation überprüfen, um eine detailliertere Beschreibung ihres Verhaltens zu erhalten. Kurz gesagt, der Hauptunterschied besteht darin, dass ADDmehr möglich ist als COPY:

  • ADDerlaubt <src>eine URL zu sein
  • In Bezug auf die folgenden Kommentare heißt es in der ADD Dokumentation :

    Wenn es sich um ein lokales Tar-Archiv in einem erkannten Komprimierungsformat (Identität, gzip, bzip2 oder xz) handelt, wird es als Verzeichnis entpackt. Ressourcen von Remote-URLs werden nicht dekomprimiert.

Beachten Sie, dass die Best Practices für das Schreiben von Docker-Dateien die Verwendung COPYdort empfehlen , wo die Magie von ADDnicht erforderlich ist. Andernfalls werden Sie ( da Sie diese Antwort nachschlagen mussten ) wahrscheinlich eines Tages überrascht sein, wenn Sie keep_this_archive_intact.tar.gzin Ihren Container kopieren möchten. Stattdessen sprühen Sie den Inhalt auf Ihr Dateisystem.


65
Ich wollte nur etwas klarstellen: Die Verwendung von ADD mit einer URL zu einer .tar.gz-Datei extrahiert das Archiv NICHT in das Dateisystem (ich habe es jetzt noch einmal überprüft, um sicherzugehen, und es ist bestätigt)
Cecile

42
Dies sind wichtige Informationen und es ist ein Verbrechen, dass die offizielle Dockerfile-Referenz den Unterschied auf diese Weise nicht verdeutlicht.
Cheeso

1
Ich bin mir nicht sicher, ob dies für ein Bild von Bild zu Bild unterschiedlich ist. Ich habe Busybox Image und ADD für eine Zip-Datei verwendet. Es wurde einfach im Zielverzeichnis angezeigt, ohne es zu entpacken. Ich nehme an, die Extraktion erfolgt nur für den Tarball, aber das habe ich jetzt noch nicht überprüft.
Santosh Kumar Arjunan

4
@ SantoshKumarArjunan: Docker-Dokumente geben Folgendes über ADD und automatische If <src> is a local tar archive in a recognized compression format (identity, gzip, bzip2 or xz) then it is unpacked as a directory. Resources from remote URLs are not decompressed.
Teerextraktion an

1
COPY erlaubt --from = <name | index>, wo ich nicht die gleiche Unterstützung für ADD finden kann
Brandon

474

COPY ist

Wie 'HINZUFÜGEN', jedoch ohne die Behandlung von Tar und Remote-URLs.

Referenz direkt aus dem Quellcode .


15
Habe ich das richtig sehen: ADDauch schafft nicht vorhandene Verzeichnisse . Also, obwohl es in diesem ganzen Thread irgendwie entmutigt ist, hat es einen Vorteil gegenüber, COPYweil Sie nicht laufen mkdirund einige Eingaben speichern müssen
eli

3
COPY macht das auch @eli
bhordupur

Beste Erklärung bisher. Warum ist es nicht die akzeptierte Antwort?
xdevx32

141

Zu diesem Punkt gibt es einige offizielle Dokumentationen: Best Practices für das Schreiben von Docker-Dateien

Da die Bildgröße wichtig ist, ADDwird dringend davon abgeraten, Pakete von Remote-URLs abzurufen. Sie sollten curloder wgetstattdessen verwenden. Auf diese Weise können Sie die Dateien löschen, die Sie nach dem Extrahieren nicht mehr benötigen, und Sie müssen Ihrem Bild keine weitere Ebene hinzufügen.

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

Für andere Elemente (Dateien, Verzeichnisse), für die keine ADDautomatische Teerextraktion erforderlich ist, sollten Sie immer verwenden COPY.



18
Docker sagt zu bevorzugen COPY, weil es transparenter ist. Aus den Best Practices der Docker-Datei (15.12.2014): Although ADD and COPY are functionally similar, generally speaking, COPY is preferred. That’s because it’s more transparent than ADD. COPY only supports the basic copying of local files into the container, while ADD has some features that are not immediately obvious.
Schema

115

Aus Docker-Dokumenten:

HINZUFÜGEN oder KOPIEREN

Obwohl ADD und COPY funktionell ähnlich sind, wird COPY im Allgemeinen bevorzugt. Das liegt daran, dass es transparenter als ADD ist. COPY unterstützt nur das grundlegende Kopieren lokaler Dateien in den Container, während ADD einige Funktionen (wie die lokale Teerextraktion und die Unterstützung von Remote-URLs) bietet, die nicht sofort offensichtlich sind. Folglich ist die beste Verwendung für ADD die automatische Extraktion lokaler TAR-Dateien in das Image, wie in ADD rootfs.tar.xz /.

Mehr: Best Practices zum Schreiben von Dockerfiles


46

Wenn Sie einem /usr/localIn-Container eine xx.tar.gz hinzufügen möchten , entpacken Sie diese und entfernen Sie das unbrauchbare komprimierte Paket.

Für KOPIE:

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

Für ADD:

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

ADD unterstützt die lokale Teerextraktion. Außerdem verwendet COPY drei Ebenen, ADD jedoch nur eine Ebene.


3
Gibt es einen Grund, warum nicht nur zwei Schichten? RUN tar -zxvf /tmp/jdk-7u79-linux-x64.tar.gz -C /usr/local && rm /tmp/jdk-7u79-linux-x64.tar.gz
Stephen C

25

COPY kopiert eine Datei / ein Verzeichnis von Ihrem Host auf Ihr Image.

ADD kopiert eine Datei / ein Verzeichnis von Ihrem Host auf Ihr Image, kann aber auch Remote-URLs abrufen, TAR-Dateien extrahieren usw.

Verwenden Sie COPYfür einfaches Kopieren von Dateien und / oder Verzeichnisse in den Build - Kontext.

Verwenden Sie ADDfür Remote - Ressourcen Herunterladen, Extrahieren von TAR - Dateien, etc ..


5
perfekte Erklärung für einen Noob wie mich
uneq95

17

Aus Docker-Dokumenten: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#add-or-copy

"Obwohl ADD und COPY funktional ähnlich sind, wird COPY im Allgemeinen bevorzugt. Dies liegt daran, dass es transparenter als ADD ist. COPY unterstützt nur das grundlegende Kopieren lokaler Dateien in den Container, während ADD einige Funktionen bietet (wie die lokale Teerextraktion und Remote-URL-Unterstützung), die nicht sofort offensichtlich sind. Folglich ist die beste Verwendung für ADD die automatische Extraktion lokaler TAR-Dateien in das Image, wie in ADD rootfs.tar.xz /.

Wenn Sie mehrere Dockerfile-Schritte haben, die unterschiedliche Dateien aus Ihrem Kontext verwenden, kopieren Sie diese einzeln und nicht alle gleichzeitig. Dadurch wird sichergestellt, dass der Build-Cache jedes Schritts nur ungültig wird (wodurch der Schritt erneut ausgeführt werden muss), wenn sich die speziell erforderlichen Dateien ändern.

Zum Beispiel:

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

Dies führt zu weniger Cache-Ungültigmachungen für den RUN-Schritt als beim Kopieren. / tmp / davor.

Da die Bildgröße wichtig ist, wird dringend davon abgeraten, ADD zum Abrufen von Paketen von Remote-URLs zu verwenden. Sie sollten stattdessen Curl oder Wget verwenden. Auf diese Weise können Sie die Dateien löschen, die Sie nach dem Extrahieren nicht mehr benötigen, und Sie müssen Ihrem Bild keine weitere Ebene hinzufügen. Sie sollten beispielsweise Folgendes vermeiden:

 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

Und machen Sie stattdessen etwas wie:

 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

Für andere Elemente (Dateien, Verzeichnisse), für die die automatische Teerextraktionsfunktion von ADD nicht erforderlich ist, sollten Sie immer COPY verwenden. "


7

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

COPY und ADD sind beide Dockerfile-Anweisungen, die ähnlichen Zwecken dienen. Mit ihnen können Sie Dateien von einem bestimmten Speicherort in ein Docker-Image kopieren.

COPY nimmt einen Quellcode und ein Ziel auf. Sie können nur eine lokale Datei oder ein lokales Verzeichnis von Ihrem Host (dem Computer, auf dem das Docker-Image erstellt wird) in das Docker-Image selbst kopieren.

Mit ADD können Sie dies auch tun, es werden jedoch auch zwei andere Quellen unterstützt. Erstens können Sie eine URL anstelle einer lokalen Datei / eines lokalen Verzeichnisses verwenden. Zweitens können Sie eine TAR-Datei aus der Quelle direkt in das Ziel extrahieren

Ein gültiger Anwendungsfall für ADD ist, wenn Sie eine lokale TAR-Datei in ein bestimmtes Verzeichnis in Ihrem Docker-Image extrahieren möchten.

Wenn Sie lokale Dateien in Ihr Docker-Image kopieren, verwenden Sie immer COPY, da dies expliziter ist.


7

Beim Erstellen einer Docker-Datei gibt es zwei Befehle, mit denen Sie Dateien / Verzeichnisse in diese kopieren können - ADDund COPY. Obwohl es geringfügige Unterschiede im Umfang ihrer Funktion gibt, erfüllen sie im Wesentlichen dieselbe Aufgabe.

Warum haben wir zwei Befehle und woher wissen wir, wann wir den einen oder anderen verwenden müssen?

DOCKER ADDBEFEHL

Beginnen wir mit der Feststellung, dass der ADDBefehl älter als ist COPY. Seit dem Start der Docker-Plattform ist die ADDAnweisung Teil der Befehlsliste.

Der Befehl kopiert Dateien / Verzeichnisse in ein Dateisystem des angegebenen Containers.

Die grundlegende Syntax für den ADDBefehl lautet:

ADD <src> … <dest>

Es enthält die Quelle, die Sie kopieren möchten ( <src>), gefolgt von dem Ziel, an dem Sie es speichern möchten ( <dest>). Wenn die Quelle ein Verzeichnis ist,ADD kopiert sie alles darin (einschließlich der Metadaten des Dateisystems).

Wenn die Datei beispielsweise lokal verfügbar ist und Sie sie dem Verzeichnis eines Bildes hinzufügen möchten, geben Sie Folgendes ein:

ADD /source/file/path  /destination/path

ADDkann auch Dateien von einer URL kopieren. Es kann eine externe Datei herunterladen und an das gewünschte Ziel kopieren. Zum Beispiel:

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

Eine zusätzliche Funktion besteht darin, dass komprimierte Dateien kopiert werden und der Inhalt des angegebenen Ziels automatisch extrahiert wird. Diese Funktion gilt nur für lokal gespeicherte komprimierte Dateien / Verzeichnisse.

ADD source.file.tar.gz /temp

Beachten Sie, dass Sie eine komprimierte Datei / ein komprimiertes Verzeichnis nicht von einer URL herunterladen und extrahieren können. Der Befehl entpackt keine externen Pakete, wenn diese in das lokale Dateisystem kopiert werden.

DOCKER COPYBEFEHL

Aufgrund einiger Funktionsprobleme musste Docker einen zusätzlichen Befehl zum Duplizieren von Inhalten einführen COPY.

Im Gegensatz zu seinem eng verwandten ADDBefehl COPYhat nur eine Funktion zugewiesen. Seine Aufgabe besteht darin, Dateien / Verzeichnisse an einem bestimmten Ort in ihrem vorhandenen Format zu duplizieren. Dies bedeutet, dass es nicht darum geht, eine komprimierte Datei zu extrahieren, sondern sie so wie sie ist zu kopieren.

Die Anweisung kann nur für lokal gespeicherte Dateien verwendet werden. Daher können Sie es nicht mit URLs verwenden, um externe Dateien in Ihren Container zu kopieren.

COPYBefolgen Sie zur Verwendung der Anweisung das grundlegende Befehlsformat:

Geben Sie die Quelle ein und geben Sie an, wo der Befehl den Inhalt wie folgt extrahieren soll:

COPY <src> … <dest> 

Zum Beispiel:

COPY /source/file/path  /destination/path 

Welcher Befehl soll verwendet werden? (Best Practice)

In Anbetracht der Umstände, unter denen der COPYBefehl eingeführt wurde, ist es offensichtlich, dass das Halten ADDeine Notwendigkeit war. Docker hat ein offizielles Dokument veröffentlicht, in dem Best Practices für das Schreiben von Docker-Dateien beschrieben sind. Es wird ausdrücklich davon abgeraten, die zu verwendenADD Befehls .

In der offiziellen Dokumentation von Docker wird darauf hingewiesen, dass dies COPYimmer die Anlaufstelle sein sollte, da sie transparenter ist als ADD.

Wenn Sie aus dem lokalen Build-Kontext in einen Container kopieren müssen, bleiben Sie bei der Verwendung COPY.

Das Docker-Team rät außerdem dringend davon ab, ADDein Paket von einer URL herunterzuladen und zu kopieren. Stattdessen ist es sicherer und effizienter, wget oder curl innerhalb eines RUNBefehls zu verwenden. Auf diese Weise vermeiden Sie das Erstellen einer zusätzlichen Bildebene und sparen Platz.


4

Wichtige Notiz

Ich musste COPYund entpacke Java-Paket in meinem Docker-Image. Beim Vergleich der mit ADD erstellten Docker-Bildgröße war sie 180 MB größer als die mit COPY, tar -xzf * .tar.gz und rm * .tar.gz erstellte

Dies bedeutet, dass ADD die TAR-Datei zwar entfernt, aber dennoch irgendwo aufbewahrt wird. Und es macht das Bild größer !!


Gilt das immer noch für die neueste Version von Docker?
Navin

3

Da Docker 17.05 COPYmit dem --fromFlag in mehrstufigen Builds verwendet wird, um Artefakte aus früheren Build-Phasen in die aktuelle Build -Phase zu kopieren.

aus der Dokumentation

Optional akzeptiert COPY ein Flag --from=<name|index>, mit dem der Quellspeicherort auf eine vorherige Erstellungsphase (erstellt mit FROM .. AS) gesetzt werden kann, die anstelle eines vom Benutzer gesendeten Erstellungskontexts verwendet wird.


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

Dies ist eine weitere Möglichkeit, Dateien in ein Bild zu kopieren. Die Option -v erstellt vorübergehend ein Volume, das wir während des Erstellungsprozesses verwendet haben.

Dies unterscheidet sich von anderen Volumes, da ein Hostverzeichnis nur für den Build bereitgestellt wird. Dateien können mit einem Standardbefehl cp kopiert werden.

Ebenso wie Curl und Wget kann es in einem Befehlsstapel ausgeführt werden (wird in einem einzelnen Container ausgeführt) und die Bildgröße nicht multipliziert. ADD und COPY sind nicht stapelbar, da sie in einem eigenständigen Container ausgeführt werden und nachfolgende Befehle für Dateien, die in zusätzlichen Containern ausgeführt werden, die Bildgröße multiplizieren:

Mit den folgenden Optionen:

-v /opt/mysql-staging:/tvol

Folgendes wird in einem Container ausgeführt:

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

1
In welcher Docker-Version sehen Sie diese Option? Es ist nicht dokumentiert und funktioniert auf meinem 1.12.1-Client nicht.
BMitch

2
Eigentlich war diese Funktion noch nicht in der Hauptversion enthalten, und es gibt immer noch viele Diskussionen zu diesem Thema, daher sollten wir nicht lange damit rechnen ... Weitere Informationen finden Sie im Fehlerbericht: github.com/ Docker / Docker / Issues / 14080 .
Jwatkins

1
Ja, es gibt keine solche Option (in der neuesten Version 17.06 aktiviert). Diese Antwort ist irreführend. unknown shorthand flag: 'v' in -v
Kirby

Irreführender Kommentar in der Tat
Guido van Steen

Docker-Bände hatten hier in der Antwort nichts zu tun, bitte, wenn Sie dürfen, beantworten Sie die direkte Frage :), es ist leicht die Downvote-Antwort.
Majid Ali Khan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.