Copia dei file dal contenitore Docker all'host


1709

Sto pensando di utilizzare Docker per creare le mie dipendenze su un server di integrazione continua (CI), in modo da non dover installare tutti i runtime e le librerie sugli agenti stessi.

Per raggiungere questo obiettivo avrei bisogno di copiare nell'host gli artefatti di build che sono stati creati all'interno del contenitore. È possibile?


voi ragazzi potreste gradire il mio metodo di hacker qui: stackoverflow.com/a/55876794/990618
Colin Lamarre

1
La risposta corretta ed effettiva del capitano docker in fondo alle risposte.
Burtsevyg,

Risposte:


2951

Per copiare un file da un contenitore all'host, è possibile utilizzare il comando

docker cp <containerId>:/file/path/within/container /host/path/target

Ecco un esempio:

$ sudo docker cp goofy_roentgen:/out_read.jpg .

Qui goofy_roentgen è il nome del contenitore che ho ottenuto dal seguente comando:

$ sudo docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                                            NAMES
1b4ad9311e93        bamos/openface      "/bin/bash"         33 minutes ago      Up 33 minutes       0.0.0.0:8000->8000/tcp, 0.0.0.0:9000->9000/tcp   goofy_roentgen

È inoltre possibile utilizzare (parte di) l' ID contenitore . Il seguente comando è equivalente al primo

$ sudo docker cp 1b4a:/out_read.jpg .

42
Ecco un modo pratico per arrivare al vostro ultimo contenitore se si sta semplicemente usando finestra mobile per un ambiente Linux temp: docker ps -alq.
Josh Habdas,

37
questo comando cp funziona così com'è anche per copiare alberi di directory (non solo un singolo file).
ecoe

88
Nelle versioni più recenti della finestra mobile è possibile copiare in modo bidirezionale (da host a container o da container a host) condocker cp ...
Freedom_Ben

9
Avevo bisogno docker cp -Ldi copiare i symlink
Harrison Powers il

24
NOTA: non è necessario che il contenitore sia in esecuzione per utilizzare il comando cp. Comodo se il contenitore si blocca costantemente.
Martlark,

219

Non è necessario per l'uso docker run.

Puoi farlo con docker create.

Dai documenti :

Il docker createcomando crea un livello contenitore scrivibile sull'immagine specificata e lo prepara per l'esecuzione del comando specificato. L'ID contenitore viene quindi stampato su STDOUT. Questo è simile ad docker run -deccezione del fatto che il contenitore non viene mai avviato.

Quindi, puoi fare:

docker create -ti --name dummy IMAGE_NAME bash
docker cp dummy:/path/to/file /dest/to/file
docker rm -f dummy

Qui, non si avvia mai il contenitore. Mi è sembrato utile.


19
Ciò richiede più voti. Ottimo per quando hai solo bisogno di costruire qualcosa in un contenitore e quindi copiare gli output.
Honza Kalfus,

4
@HonzaKalfus Sono d'accordo che questo deve essere più alto. Questo è esattamente quello che stavo cercando. L'ho usato in modo da poter creare alcuni file binari usando un ambiente noto (Amazon Linux a una versione specifica). è stato in grado di creare uno script di shell che ha completamente costruito la finestra mobile ed ha estratto da esso il binario risultante! Perfetto.
Mark

1
È -tirichiesto e bashrichiesto?
jII

@jII, l'avevo fatto perché in seguito lo eseguo docker. In casi semplici, non è necessario ma non fa male anche qui.
Ishan Bhatt,

È in qualche modo possibile usare i caratteri jolly? Voglio dire ... Non conosco il nome esatto del file che devo copiare perché ha un numero di versione su di esso.
juzzlin,

87

Montare un "volume" e copiare gli artefatti lì:

mkdir artifacts
docker run -i -v ${PWD}/artifacts:/artifacts ubuntu:14.04 sh << COMMANDS
# ... build software here ...
cp <artifact> /artifacts
# ... copy more artifacts into `/artifacts` ...
COMMANDS

Quindi, quando la compilazione termina e il contenitore non è più in esecuzione, ha già copiato gli artefatti dalla compilazione nella artifactsdirectory sull'host.

modificare

Avvertenza: quando si esegue questa operazione, è possibile che si verifichino problemi con l'id utente dell'utente docker corrispondente all'ID utente dell'utente corrente in esecuzione. Cioè, i file in /artifactsverranno mostrati come posseduti dall'utente con l'UID dell'utente utilizzato all'interno del contenitore docker. Un modo per aggirare questo potrebbe essere quello di utilizzare l'UID dell'utente chiamante:

docker run -i -v ${PWD}:/working_dir -w /working_dir -u $(id -u) \
    ubuntu:14.04 sh << COMMANDS
# Since $(id -u) owns /working_dir, you should be okay running commands here
# and having them work. Then copy stuff into /working_dir/artifacts .
COMMANDS

7
In realtà è possibile utilizzare il chowncomando per abbinare l'id utente e l'id gruppo sul computer host.
Dimchansky,

@Frondor Vedi riferimento di configurazione del volume docs.docker.com/compose/compose-file/…
djhaskin987

Già fatto, e non funzionerà. Una volta che il contenitore ha copiato i file sul volume per la prima volta, la volta successiva, il volume non è più vuoto e i file non vengono sovrascritti da quelli più recenti. Il contenitore dà la priorità ai file host (quelli copiati la prima volta che hai montato l'immagine del contenitore).
Frondor,

suona come qualcosa che potrebbe essere la sua stessa domanda @Frondor
djhaskin987

1
Ti sto comprando un compagno di birra! Grazie!
Dimitar Vukman,

27

Montare un volume, copiare gli artefatti, regolare l'id proprietario e l'id gruppo:

mkdir artifacts
docker run -i --rm -v ${PWD}/artifacts:/mnt/artifacts centos:6 /bin/bash << COMMANDS
ls -la > /mnt/artifacts/ls.txt
echo Changing owner from \$(id -u):\$(id -g) to $(id -u):$(id -u)
chown -R $(id -u):$(id -u) /mnt/artifacts
COMMANDS

24

TLDR;

$ docker run --rm -iv${PWD}:/host-volume my-image sh -s <<EOF
chown $(id -u):$(id -g) my-artifact.tar.xz
cp -a my-artifact.tar.xz /host-volume
EOF

Descrizione

docker runcon un volume host, chownl'artefatto, cpl'artefatto del volume host:

$ docker build -t my-image - <<EOF
> FROM busybox
> WORKDIR /workdir
> RUN touch foo.txt bar.txt qux.txt
> EOF
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM busybox
 ---> 00f017a8c2a6
Step 2/3 : WORKDIR /workdir
 ---> Using cache
 ---> 36151d97f2c9
Step 3/3 : RUN touch foo.txt bar.txt qux.txt
 ---> Running in a657ed4f5cab
 ---> 4dd197569e44
Removing intermediate container a657ed4f5cab
Successfully built 4dd197569e44

$ docker run --rm -iv${PWD}:/host-volume my-image sh -s <<EOF
chown -v $(id -u):$(id -g) *.txt
cp -va *.txt /host-volume
EOF
changed ownership of '/host-volume/bar.txt' to 10335:11111
changed ownership of '/host-volume/qux.txt' to 10335:11111
changed ownership of '/host-volume/foo.txt' to 10335:11111
'bar.txt' -> '/host-volume/bar.txt'
'foo.txt' -> '/host-volume/foo.txt'
'qux.txt' -> '/host-volume/qux.txt'

$ ls -n
total 0
-rw-r--r-- 1 10335 11111 0 May  7 18:22 bar.txt
-rw-r--r-- 1 10335 11111 0 May  7 18:22 foo.txt
-rw-r--r-- 1 10335 11111 0 May  7 18:22 qux.txt

Questo trucco funziona perché l' chowninvocazione all'interno dell'ereditarietà prende $(id -u):$(id -g)valori dall'esterno del container in esecuzione; cioè, l'host docker.

I vantaggi sono:

  • non devi docker container run --nameo docker container create --nameprima
  • non devi docker container rmdopo

2
Eseguito l'upgrade per il confronto tra cpe risposte basate sul volume. Inoltre, per il idtrucco della proprietà, a volte è un vero mal di testa
Marc Ghorayeb,

18

La maggior parte delle risposte non indica che il contenitore deve essere eseguito prima docker cpfunzionerà:

docker build -t IMAGE_TAG .
docker run -d IMAGE_TAG
CONTAINER_ID=$(docker ps -alq)
# If you do not know the exact file name, you'll need to run "ls"
# FILE=$(docker exec CONTAINER_ID sh -c "ls /path/*.zip")
docker cp $CONTAINER_ID:/path/to/file .
docker stop $CONTAINER_ID

3
A proposito, se il contenitore deve / potrebbe essere in esecuzione / arrestato / sembra dipendere dal tipo di host / tecnica di virtualizzazione . Il documento docker corrente dice "CONTAINER può essere un contenitore in esecuzione o arrestato". Luoghi multipli su SO, incluso un commento sulla risposta accettata, dicono "funziona anche su un contenitore fermo". Sotto Windows Hyper-V, è apparentemente necessaria per fermare il contenitore prima di copiare un file .
ToolmakerSteve

La copia funziona anche quando il contenitore è fermo.
Luca W

17

Se non hai un contenitore in esecuzione, solo un'immagine e supponendo di voler copiare solo un file di testo, potresti fare qualcosa del genere:

docker run the-image cat path/to/container/file.txt > path/to/host/file.txt

7

Sto pubblicando questo per chiunque stia utilizzando Docker per Mac. Questo è ciò che ha funzionato per me:

 $ mkdir mybackup # local directory on Mac

 $ docker run --rm --volumes-from <containerid> \
    -v `pwd`/mybackup:/backup \  
    busybox \                   
    cp /data/mydata.txt /backup 

Nota che quando monto usando -vquella backupdirectory viene automaticamente creata.

Spero che questo possa essere utile a qualcuno un giorno. :)


Se si utilizza la finestra mobile componi, i volumi da sono obsoleti nella versione 3 e successive.
mulg0r

Per aggiungere al commento di mulg0r, vedere stackoverflow.com/a/45495380/199364 - nella v.3, si inserisce un volumescomando nella radice di config.yml, affinché i volumi siano accessibili da più contenitori.
ToolmakerSteve

5

Se vuoi solo estrarre un file da un'immagine (invece che da un contenitore in esecuzione) puoi farlo:

docker run --rm <image> cat <source> > <local_dest>

Questo farà apparire il contenitore, scrivere il nuovo file, quindi rimuovere il contenitore. Uno svantaggio, tuttavia, è che le autorizzazioni del file e la data modificata non verranno conservate.



5

Con il rilascio di Docker 19.03, puoi saltare la creazione del contenitore e persino la creazione di un'immagine. C'è un'opzione con build basate su BuildKit per modificare la destinazione di output. Puoi usarlo per scrivere i risultati della build nella tua directory locale piuttosto che in un'immagine. Ad esempio, ecco una build di un go binario:

$ ls
Dockerfile  go.mod  main.go

$ cat Dockerfile
FROM golang:1.12-alpine as dev
RUN apk add --no-cache git ca-certificates
RUN adduser -D appuser
WORKDIR /src
COPY . /src/
CMD CGO_ENABLED=0 go build -o app . && ./app

FROM dev as build
RUN CGO_ENABLED=0 go build -o app .
USER appuser
CMD [ "./app" ]

FROM scratch as release
COPY --from=build /etc/passwd /etc/group /etc/
COPY --from=build /src/app /app
USER appuser
CMD [ "/app" ]

FROM scratch as artifact
COPY --from=build /src/app /app

FROM release

Dal file Docker sopra, sto costruendo il artifactpalcoscenico che include solo i file che voglio esportare. E il --outputflag appena introdotto mi permette di scriverli in una directory locale anziché in un'immagine. Questo deve essere eseguito con il motore BuildKit fornito con 19.03:

$ DOCKER_BUILDKIT=1 docker build --target artifact --output type=local,dest=. .
[+] Building 43.5s (12/12) FINISHED
 => [internal] load build definition from Dockerfile                                                                              0.7s
 => => transferring dockerfile: 572B                                                                                              0.0s
 => [internal] load .dockerignore                                                                                                 0.5s
 => => transferring context: 2B                                                                                                   0.0s
 => [internal] load metadata for docker.io/library/golang:1.12-alpine                                                             0.9s
 => [dev 1/5] FROM docker.io/library/golang:1.12-alpine@sha256:50deab916cce57a792cd88af3479d127a9ec571692a1a9c22109532c0d0499a0  22.5s
 => => resolve docker.io/library/golang:1.12-alpine@sha256:50deab916cce57a792cd88af3479d127a9ec571692a1a9c22109532c0d0499a0       0.0s
 => => sha256:1ec62c064901392a6722bb47a377c01a381f4482b1ce094b6d28682b6b6279fd 155B / 155B                                        0.3s
 => => sha256:50deab916cce57a792cd88af3479d127a9ec571692a1a9c22109532c0d0499a0 1.65kB / 1.65kB                                    0.0s
 => => sha256:2ecd820bec717ec5a8cdc2a1ae04887ed9b46c996f515abc481cac43a12628da 1.36kB / 1.36kB                                    0.0s
 => => sha256:6a17089e5a3afc489e5b6c118cd46eda66b2d5361f309d8d4b0dcac268a47b13 3.81kB / 3.81kB                                    0.0s
 => => sha256:89d9c30c1d48bac627e5c6cb0d1ed1eec28e7dbdfbcc04712e4c79c0f83faf17 2.79MB / 2.79MB                                    0.6s
 => => sha256:8ef94372a977c02d425f12c8cbda5416e372b7a869a6c2b20342c589dba3eae5 301.72kB / 301.72kB                                0.4s
 => => sha256:025f14a3d97f92c07a07446e7ea8933b86068d00da9e252cf3277e9347b6fe69 125.33MB / 125.33MB                               13.7s
 => => sha256:7047deb9704134ff71c99791be3f6474bb45bc3971dde9257ef9186d7cb156db 125B / 125B                                        0.8s
 => => extracting sha256:89d9c30c1d48bac627e5c6cb0d1ed1eec28e7dbdfbcc04712e4c79c0f83faf17                                         0.2s
 => => extracting sha256:8ef94372a977c02d425f12c8cbda5416e372b7a869a6c2b20342c589dba3eae5                                         0.1s
 => => extracting sha256:1ec62c064901392a6722bb47a377c01a381f4482b1ce094b6d28682b6b6279fd                                         0.0s
 => => extracting sha256:025f14a3d97f92c07a07446e7ea8933b86068d00da9e252cf3277e9347b6fe69                                         5.2s
 => => extracting sha256:7047deb9704134ff71c99791be3f6474bb45bc3971dde9257ef9186d7cb156db                                         0.0s
 => [internal] load build context                                                                                                 0.3s
 => => transferring context: 2.11kB                                                                                               0.0s
 => [dev 2/5] RUN apk add --no-cache git ca-certificates                                                                          3.8s
 => [dev 3/5] RUN adduser -D appuser                                                                                              1.7s
 => [dev 4/5] WORKDIR /src                                                                                                        0.5s
 => [dev 5/5] COPY . /src/                                                                                                        0.4s
 => [build 1/1] RUN CGO_ENABLED=0 go build -o app .                                                                              11.6s
 => [artifact 1/1] COPY --from=build /src/app /app                                                                                0.5s
 => exporting to client                                                                                                           0.1s
 => => copying files 10.00MB                                                                                                      0.1s

Al termine della compilazione il file appbinario è stato esportato:

$ ls
Dockerfile  app  go.mod  main.go

$ ./app
Ready to receive requests on port 8080

Docker ha altre opzioni per il --outputflag documentate nel loro repository BuildKit a monte: https://github.com/moby/buildkit#output


cache di build standard non usata per build con output, è male
burtsevyg

@burtsevyg Buildkit è un generatore diverso, che utilizza un ambiente cache diverso. È molto più efficiente nella cache.
BMitch

grazie migliorerò i miei nodi di build.
Burtsevyg,

4

Come soluzione più generale, c'è un plug-in CloudBees per Jenkins da compilare all'interno di un contenitore Docker . È possibile selezionare un'immagine da utilizzare da un registro Docker o definire un file Docker da compilare e utilizzare.

Monterà lo spazio di lavoro nel contenitore come volume (con l'utente appropriato), lo imposterà come directory di lavoro, eseguirà tutti i comandi richiesti (all'interno del contenitore). Puoi anche usare il plugin docker-workflow (se preferisci il codice sull'interfaccia utente) per farlo, con il comando image.inside () {}.

Fondamentalmente tutto questo, inserito nel tuo server CI / CD e poi alcuni.


4

Ho usato PowerShell (Admin) con questo comando.

docker cp {container id}:{container path}/error.html  C:\\error.html

Esempio

docker cp ff3a6608467d:/var/www/app/error.html  C:\\error.html

2

Un'altra buona opzione è innanzitutto creare il contenitore e quindi eseguirlo usando il flag -c con l'interprete della shell per eseguire alcuni comandi

docker run --rm -i -v <host_path>:<container_path> <mydockerimage> /bin/sh -c "cp -r /tmp/homework/* <container_path>"

Il comando sopra fa questo:

-i = esegue il contenitore in modalità interattiva

--rm = rimosso il contenitore dopo l'esecuzione.

-v = ha condiviso una cartella come volume dal percorso host al percorso contenitore.

Infine, / bin / sh -c consente di introdurre un comando come parametro e tale comando copierà i file dei compiti nel percorso del contenitore.

Spero che questa risposta aggiuntiva possa aiutarti


1

Creare una directory di dati sul sistema host (all'esterno del contenitore) e montarla su una directory visibile dall'interno del contenitore. Ciò posiziona i file in una posizione nota sul sistema host e consente agli strumenti e alle applicazioni sul sistema host di accedere facilmente ai file

docker run -d -v /path/to/Local_host_dir:/path/to/docker_dir docker_image:tag

4
Ciò consente di iniettare una directory e i relativi contenuti dall'host nel contenitore. Non ti consente di copiare i file dal contenitore all'host.
BMitch,

Lo fa se la cartella host ha autorizzazioni molto ampie?
giorgiosironi,

0

Creare un percorso in cui si desidera copiare il file e quindi utilizzare:

docker run -d -v hostpath:dockerimag

0

È possibile utilizzare bindinvece volumese si desidera montare solo una cartella, non creare uno spazio di archiviazione speciale per un contenitore:

  1. Crea la tua immagine con il tag:

    docker build . -t <image>

  2. Esegui la tua immagine e associa la directory $ (pwd) corrente dove app.py memorizza e la mappa su / root / example / all'interno del tuo contenitore.

    docker run --mount type=bind,source="$(pwd)",target=/root/example/ <image> python app.py


0

Questo può essere fatto anche nell'SDK, ad esempio Python. Se hai già un container creato, puoi cercare il nome tramite console ( docker ps -a) il nome sembra essere una concatenazione di uno scienziato e un aggettivo (ad esempio "relaxed_pasteur").

Dai un'occhiata help(container.get_archive):

Help on method get_archive in module docker.models.containers:

get_archive(path, chunk_size=2097152) method of docker.models.containers.Container instance
    Retrieve a file or folder from the container in the form of a tar
    archive.

    Args:
        path (str): Path to the file or folder to retrieve
        chunk_size (int): The number of bytes returned by each iteration
            of the generator. If ``None``, data will be streamed as it is
            received. Default: 2 MB

    Returns:
        (tuple): First element is a raw tar data stream. Second element is
        a dict containing ``stat`` information on the specified ``path``.

    Raises:
        :py:class:`docker.errors.APIError`
            If the server returns an error.

    Example:

        >>> f = open('./sh_bin.tar', 'wb')
        >>> bits, stat = container.get_archive('/bin/sh')
        >>> print(stat)
        {'name': 'sh', 'size': 1075464, 'mode': 493,
         'mtime': '2018-10-01T15:37:48-07:00', 'linkTarget': ''}
        >>> for chunk in bits:
        ...    f.write(chunk)
        >>> f.close()

Quindi qualcosa del genere verrà estratto dal percorso specificato (/ output) nel contenitore sul computer host e decomprimerà il tar.

import docker
import os
import tarfile

# Docker client
client = docker.from_env()
#container object
container = client.containers.get("relaxed_pasteur")
#setup tar to write bits to
f = open(os.path.join(os.getcwd(),"output.tar"),"wb")
#get the bits
bits, stat = container.get_archive('/output')
#write the bits
for chunk in bits:
    f.write(chunk)
f.close()
#unpack
tar = tarfile.open("output.tar")
tar.extractall()
tar.close()
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.