Docker: come posso copiare un file da un'immagine a un host?


117

La mia domanda è relativa a questa domanda sulla copia dei file dai contenitori agli host; Ho un Dockerfile che recupera le dipendenze, compila un artefatto di build dall'origine ed esegue un eseguibile. Voglio anche copiare l'artefatto di build (nel mio caso è un .zipprodotto da sbt distin '../ target / `, ma penso che questa domanda si applichi anche a jar, binari, ecc.

docker cplavora sui contenitori, non sulle immagini; devo avviare un contenitore solo per estrarne un file? In uno script, ho provato a eseguire /bin/bashin modalità interattiva in background, copiando il file e quindi uccidendo il contenitore, ma questo sembra kludgey. C'è un modo migliore?

D'altra parte, vorrei evitare di decomprimere un .tarfile dopo l'esecuzione docker save $IMAGENAMEsolo per estrarne uno (ma questa sembra l'opzione più semplice, anche se la più lenta al momento).

Userei volumi docker, ad esempio:

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

ma sto eseguendo boot2dockerin OSX e non so come scrivere direttamente sul mio file system host Mac (i volumi di lettura-scrittura si stanno montando all'interno della mia VM boot2docker, il che significa che non posso condividere facilmente uno script con cui estrarre blah.zipda un'immagine altri Pensieri?

Risposte:


172

Per copiare un file da un'immagine, creare un contenitore temporaneo, copiare il file da esso e quindi eliminarlo:

id=$(docker create image-name)
docker cp $id:path - > local-tar-file
docker rm -v $id

Quale versione di docker era il createcomando aggiunto / rimosso (non è presente nella 1.01)
ThorSummoner

2
@ThorSummoner è docker createstato introdotto nella finestra mobile 1.3, blog.docker.com/2014/10/…
Igor Bukanov

1
Non so perché questa non sia selezionata come risposta corretta.
CentAu

1
Sicuramente la risposta giusta !!! Non fa affidamento su nulla all'interno del contenitore ... Per le immagini scratch Golang, questo è l'unico modo possibile!
Marcello de Sales

2
qualsiasi motivo per copiare su stdout e quindi indirizzarlo a un file locale? quando l'ho fatto, ha scaricato un gruppo di caratteri di controllo prima e dopo il contenuto del file. eseguendolo direttamente come ha docker cp $id:path > local-tar-filefunzionato perfettamente.
Yonatan,

62

Sfortunatamente non sembra esserci un modo per copiare i file direttamente dalle immagini Docker. È necessario creare prima un contenitore e quindi copiare il file dal contenitore.

Tuttavia, se la tua immagine contiene un catcomando (e lo farà in molti casi), puoi farlo con un singolo comando:

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

Se la tua immagine non contiene cat, crea semplicemente un contenitore e usa il docker cpcomando come suggerito nella risposta di Igor.


1
Fantastica soluzione. Impossibile accedere al mio contenitore poiché si è bloccato un secondo dopo l'avvio, ma era necessario prendere un file al suo interno. Ha funzionato perfettamente.
Mirodinho

23

Un'opzione molto più veloce è copiare il file dal contenitore in esecuzione su un volume montato:

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

0m0,446s reali

** VS **

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

0m9,014 reali


Questo probabilmente ha più a che fare con il file system sottostante che esegue una copia lenta / superficiale del file (si pensi alla copia su scrittura) nel primo esempio, rispetto alla copia effettiva dei byte del file nel secondo esempio. Un test utile sarebbe vedere se cat a >bvs cp a bhanno tempi simili come mostrato qui. Inoltre, se il percorso di origine e il percorso di destinazione risiedono su file system diversi, entrambi gli esempi porteranno a una copia completa byte per byte.
KevinOrr

14

Il commento dei genitori ha già mostrato come usare cat . Puoi anche usare tar in modo simile:

docker run yourimage tar -c -C /my/directory subfolder | tar x

1
Questa risposta è copiare le directory invece dei file come richiesto dalla domanda originale. Tuttavia, +1 perché funziona anche con i file e viene fornito con una funzionalità extra: autorizzazione e conservazione del proprietario. Grande!
caligari

5
In realtà, io usodocker 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

voleva fornire una soluzione a una linea

modifica: il contenitore non deve nemmeno essere eseguito in questa soluzione


1

Un'altra (breve) risposta a questo problema:

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

0

Sto usando boot2docker su MacOS. Posso assicurarti che gli script basati su "docker cp" sono portabili. Perché qualsiasi comando viene inoltrato all'interno di boot2docker ma poi il flusso binario viene ritrasmesso al client della riga di comando docker in esecuzione sul tuo Mac. Quindi le operazioni di scrittura dal client docker vengono eseguite all'interno del server e riscritte nell'istanza del client in esecuzione!

Sto condividendo uno script di backup per i volumi Docker con qualsiasi contenitore Docker che fornisco ei miei script di backup sono testati sia su Linux che su MacOS con boot2docker. I backup possono essere facilmente scambiati tra le piattaforme. Fondamentalmente sto eseguendo il seguente comando all'interno del mio script:

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

Esegue un nuovo contenitore busybox e monta il volume del mio contenitore jenkins con il nome jenkins_jenkins_1. L'intero volume viene scritto nel file backup / JenkinsBackup-2015-07-09-14-26-15.tar

Ho già spostato archivi tra il container Linux e il container Mac senza alcuna modifica allo script di backup o ripristino. Se questo è quello che vuoi, trovi l'intero script e un tutorial qui: blacklabelops / jenkins


0

È possibile associare un percorso locale sull'host a un percorso sul contenitore, quindi cpi file desiderati a quel percorso alla fine dello script.

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

Quindi non è necessario copiare in seguito.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.