Bloglet: Docker — Was ist der Unterschied zwischen ADD und COPY?

Joachim Baumann
Digital Frontiers — Das Blog
3 min readDec 18, 2020

Eine der Aufgaben, die wir im Dockerfile erledigen, ist das Kopieren von Quelldateien in unser Docker-Image. Neben der eigentlichen Funktion der Befehle ist die Dokumentation unserer Absicht, welche Quelldateien wo landen, für den Leser des Dockerfiles sehr wichtig.

Der erste Befehl, den wir hierzu gelernt haben, ist ...

Der Befehl ADD

Dieser Befehl erlaubt es uns, Daten aus einer beliebigen Quelle in unser Docker-Image zu kopieren. Ein simples Beispiel:

ADD datei* /verzeichnis/

Dieser Befehl kopiert alle Dateien, deren Name mit datei beginnt, in das Verzeichnis /verzeichnis/ . Beliebige Muster können verwendet werden, um die Quellen zu beschreiben.

Zusätzlich kann dieser Befehl auch Quellen aus komprimierten Archiven entpacken. Dies funktioniert sehr einfach und zuverlässig. Auch hier ein Beispiel:

ADD datei.tar.gz /verzeichnis/

Und natürlich geht dies nicht nur mit lokalen Dateien, sondern auch mit Dateien oder Archiven, die wir aus einer URL über HTTP oder HTTPS laden (die Beispieldatei existiert nicht wirklich):

ADD https://www.digitalfrontiers.de/datei.txt /verzeichnis/

Effizienz

Wenn wir uns mit der Effizienz der Befehle beschäftigen, dann ist ein Hinweis in der Docker-Dokumentation (Link), dass das Entpacken von Archiven, die aus einer URL geladen werden, besser mit wget/curlund explizitem Entpacken gemacht wird als mit dem Befehl ADD, da dadurch die Größe des entstehenden Docker-Images kleiner gehalten werden kann.

Warum? Der Hintergrund ist, dass in den meisten Fällen die entpackten Dateien noch modifiziert werden. Wenn wir den Weg über ADD gehen, dann haben wir einen Layer, in dem wir das Entpacken durchführen, und einen zweiten Layer, in dem wir zum Beispiel mit RUN und folgendem rm die Modifikation durchführen. Damit verbleibt aber das gesamte Archiv im ersten Layer und sorgt damit für ein Aufblähen des Images.

Wenn wir hingegen den in der Docker-Dokumentation vorgeschlagenen Weg gehen, dann können wir mit einer kombinierten Befehlsfolge RUN curl … && unzip … && rm … dafür sorgen, dass nur ein Layer geschrieben wird, der exakt den von uns gewünschten Endzustand ohne die gelöschten Dateien enthält.

Die dadurch entstehende Befehlsfolge ist aber deutlich schwerer zu lesen und behindert damit den Ansatz der Dokumentation unserer Absicht. Wir müssen also abwägen, ob uns jeweils die Dokumentation oder die Größe des Images wichtiger sind.

Die vom Befehl ADD zur Verfügung gestellte Funktionalität genügt, um alle Kopieraufgaben (aus lokalen und entfernten Quellen) zu erledigen. Und tatsächlich stoppen viele an dieser Stelle und stolpern nicht mehr über die nächste Möglichkeit…

Der Befehl COPY

Der Befehl COPY sieht dem Befehl ADD sehr ähnlich, kopiert aber ausschließlich lokale Dateien und entpackt keine Archive. Die Syntax ist hierbei vergleichbar mit der des Befehls ADD:

COPY datei* /verzeichnis/

Dieser Befehl kopiert alle Dateien, deren Name mit datei beginnt, in das Verzeichnis /verzeichnis/ . Auch hier können Muster verwendet werden.

Was sollten wir verwenden?

Die Idee hinter den verschiedenen Befehlen ist, unsere Absicht klar zu kommunizieren. Wenn jemand das Docker-File liest und sieht, dass wir den Befehl COPY verwenden, dann ist ganz klar, dass die kopierten Dateien aus dem lokalen Dateisystem kommen, ohne dass die Befehlszeile vollständig gelesen werden muss. Das sorgt für leichtere Lesbarkeit und ein schnelleres Verstehen dessen, was das Docker-File tatsächlich tut.

Damit ist klar, dass wir den Befehl COPY immer verwenden sollten, außer wir sind auf die zusätzliche Funktionalität des Befehls ADD (entfernte Quellen oder Entpacken von Archiven) angewiesen.

Vielen Dank fürs Lesen und ich freue mich auf Feedback. Weitere interessante Artikel erscheinen im Blog der Digital Frontiers und werden auch auf unserem Twitter-Account angekündigt.

--

--