Docker - Wie kann ich eine Datei von einem Image auf einen Host kopieren?

114

Meine Frage bezieht sich auf diese Frage zum Kopieren von Dateien von Containern auf Hosts. Ich habe eine Docker-Datei, die Abhängigkeiten abruft, ein Build-Artefakt aus dem Quellcode kompiliert und eine ausführbare Datei ausführt. Ich möchte auch das Build-Artefakt kopieren (in meinem Fall ist es ein .zipvon sbt dist'../ target /' erstelltes, aber ich denke, diese Frage gilt auch für Gläser, Binärdateien usw.).

docker cparbeitet an Containern, nicht an Bildern; Muss ich einen Container starten, um eine Datei daraus zu erhalten? In einem Skript habe ich versucht, /bin/bashim interaktiven Modus im Hintergrund zu laufen , die Datei zu kopieren und dann den Container zu beenden, aber das scheint kludgey. Gibt es einen besseren Weg?

Andererseits möchte ich vermeiden, dass eine .tarDatei nach dem Ausführen entpackt wirddocker save $IMAGENAME entpacken, um nur eine Datei herauszuholen (aber das scheint derzeit die einfachste, wenn auch langsamste Option zu sein).

Ich würde Docker-Volumes verwenden, z.

docker run -v hostdir:out $IMAGENAME /bin/cp/../blah.zip /out

Ich arbeite jedoch unter boot2dockerOSX und weiß nicht, wie ich direkt in mein Mac-Host-Dateisystem schreiben soll (Lese- / Schreib-Volumes werden in meiner boot2docker-VM bereitgestellt, was bedeutet, dass ich ein Skript zum Extrahieren blah.zipaus einem Image nicht einfach freigeben kann andere. Gedanken?

Kennzeichen
quelle

Antworten:

171

Um eine Datei aus einem Bild zu kopieren, erstellen Sie einen temporären Container, kopieren Sie die Datei daraus und löschen Sie sie dann:

id=$(docker create image-name)
docker cp $id:path - > local-tar-file
docker rm -v $id
Igor Bukanov
quelle
Welche Version von Docker war der createBefehl hinzugefügt / entfernt (es ist nicht in 1.01 vorhanden)
ThorSummoner
2
@ThorSummoner docker createwurde in Docker 1.3, blog.docker.com/2014/10/…
Igor Bukanov
1
Ich weiß nicht, warum dies nicht als die richtige Antwort ausgewählt ist.
CentAu
1
Auf jeden Fall die richtige Antwort !!! Verlässt sich nicht auf irgendetwas im Container ... Für Golang-Scratch-Bilder ist dies der einzig mögliche Weg!
Marcello de Sales
2
Gibt es einen Grund, nach stdout zu kopieren und dann in eine lokale Datei zu leiten? Als ich dies tat, wurden eine Reihe von Steuerzeichen vor und nach dem Inhalt der Datei ausgegeben. direkt laufen wie es docker cp $id:path > local-tar-fileperfekt funktioniert hat.
Yonatan
61

Leider scheint es keine Möglichkeit zu geben, Dateien direkt von Docker-Images zu kopieren. Sie müssen zuerst einen Container erstellen und dann die Datei aus dem Container kopieren.

Wenn Ihr Image jedoch einen catBefehl enthält (und dies in vielen Fällen der Fall ist), können Sie dies mit einem einzigen Befehl tun:

docker run --rm --entrypoint cat yourimage  /path/to/file > path/to/destination

Wenn Ihr Bild nicht enthält cat, erstellen Sie einfach einen Container und verwenden Sie den docker cpin Igor's Antwort vorgeschlagenen Befehl.

fons
quelle
1
Fantastische Lösung. Ich konnte nicht auf meinen Container zugreifen, da er eine Sekunde nach dem Start abgestürzt ist, musste jedoch eine Datei darin abrufen. Das hat perfekt funktioniert.
Mirodinho
23

Eine viel schnellere Option besteht darin, die Datei vom laufenden Container auf ein bereitgestelltes Volume zu kopieren:

docker run -v $PWD:/opt/mount --rm --entrypoint cp image:version /data/libraries.tgz /opt/mount/libraries.tgz

echte 0m0.446s

** VS **

docker run --rm --entrypoint cat image:version /data/libraries.tgz > libraries.tgz

echte 0m9.014s

Mikko
quelle
Dies hat wahrscheinlich mehr damit zu tun, dass das zugrunde liegende Dateisystem im ersten Beispiel eine verzögerte / flache Kopie der Datei ausführt (Think Copy-on-Write), als im zweiten Beispiel die Bytes der Datei tatsächlich zu kopieren. Ein nützlicher Test wäre zu sehen, ob cat a >bvs cp a bähnliche Timings wie hier gezeigt haben. Wenn sich der Quell- und der Zielpfad auf verschiedenen Dateisystemen befinden, führen beide Beispiele zu einer vollständigen Byte-für-Byte-Kopie.
KevinOrr
14

Der Kommentar der Eltern zeigte bereits, wie man Katze benutzt . Sie können Teer auch auf ähnliche Weise verwenden:

docker run yourimage tar -c -C /my/directory subfolder | tar x
wedesoft
quelle
1
Diese Antwort besteht darin, Verzeichnisse anstelle von Dateien zu kopieren, wie in der ursprünglichen Frage angegeben. +1, da es auch mit Dateien funktioniert und eine zusätzliche Funktion bietet: Berechtigung und Eigentümererhaltung. Toll!
Caligari
5
Eigentlich benutze ichdocker run --rm --entrypoint tar _image_ cC _img_directory_ . | tar xvC _host_directory_
Caligari
6
docker cp $(docker create registry.example.com/ansible-base:latest):/home/ansible/.ssh/id_rsa ./hacked_ssh_key

wollte eine einzeilige Lösung liefern

edit: container muss in dieser lösung nicht einmal ausgeführt werden

Elytscha Smith
quelle
1

Eine weitere (kurze) Antwort auf dieses Problem:

docker run -v $PWD:/opt/mount --rm -ti image:version bash -c "cp /source/file /opt/mount/"
freedev
quelle
0

Ich benutze boot2docker unter MacOS. Ich kann Ihnen versichern, dass Skripte, die auf "Docker CP" basieren, portabel sind. Da jeder Befehl in boot2docker weitergeleitet wird, wird der Binärstrom dann an den Docker-Befehlszeilenclient zurückgeleitet, der auf Ihrem Mac ausgeführt wird. Schreibvorgänge vom Docker-Client werden also im Server ausgeführt und in die ausführende Client-Instanz zurückgeschrieben!

Ich teile ein Backup-Skript für Docker-Volumes mit jedem Docker-Container, den ich zur Verfügung stelle, und meine Backup-Skripte werden sowohl unter Linux als auch unter MacOS mit boot2docker getestet. Die Backups können problemlos zwischen Plattformen ausgetauscht werden. Grundsätzlich führe ich den folgenden Befehl in meinem Skript aus:

docker run --name=bckp_for_volume --rm --volumes-from jenkins_jenkins_1 -v /Users/github/jenkins/backups:/backup busybox tar cf /backup/JenkinsBackup-2015-07-09-14-26-15.tar /jenkins

Führt einen neuen Busybox-Container aus und stellt das Volume meines Jenkins-Containers mit dem Namen jenkins_jenkins_1 bereit. Das gesamte Volume wird in die Dateisicherungen / JenkinsBackup-2015-07-09-14-26-15.tar geschrieben

Ich habe bereits Archive zwischen dem Linux-Container und meinem Mac-Container verschoben, ohne das Sicherungs- oder Wiederherstellungsskript anzupassen. Wenn Sie dies möchten, finden Sie im gesamten Skript ein Tutorial: blacklabelops / jenkins

Blacklabelops
quelle
0

Sie können einen lokalen Pfad auf dem Host an einen Pfad im Container binden und dann cpdie gewünschten Dateien an diesen Pfad am Ende Ihres Skripts.

$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  nginx:latest

Danach muss nicht mehr kopiert werden.

Ryanjdillon
quelle