Kopieren von Dateien vom Docker-Container zum Host

1708

Ich denke darüber nach, Docker zu verwenden, um meine Abhängigkeiten von einem Continuous Integration (CI) -Server zu erstellen, damit ich nicht alle Laufzeiten und Bibliotheken auf den Agenten selbst installieren muss.

Um dies zu erreichen, müsste ich die Build-Artefakte, die im Container erstellt wurden, zurück in den Host kopieren. Ist das möglich?

user2668128
quelle
euch könnte meine Hacker-Methode hier gefallen
colin lamarre
1
Die richtige und tatsächliche Antwort des Hafenkapitäns am Ende der Antworten.
Burtsevyg

Antworten:

2948

Um eine Datei von einem Container auf den Host zu kopieren, können Sie den Befehl verwenden

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

Hier ist ein Beispiel:

$ sudo docker cp goofy_roentgen:/out_read.jpg .

Hier ist goofy_roentgen der Containername, den ich vom folgenden Befehl erhalten habe:

$ 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

Sie können auch (einen Teil) der Container-ID verwenden . Der folgende Befehl entspricht dem ersten

$ sudo docker cp 1b4a:/out_read.jpg .
knarren
quelle
42
Hier ist eine praktische Möglichkeit, um an Ihren neuesten Container zu gelangen, wenn Sie Docker einfach für eine temporäre Linux-Umgebung verwenden : docker ps -alq.
Josh Habdas
37
dieser Befehl cp arbeitet als Service - Leistung für das Kopieren von Verzeichnisbäumen als auch ( und nicht nur eine einzelne Datei).
Öko
88
In neueren Versionen von Docker Sie können in zwei Richtungen (Host Container oder Behälter zu Host) kopieren mitdocker cp ...
Freedom_Ben
9
Ich musste docker cp -LSymlinks kopieren
Harrison Powers
24
HINWEIS: Der Container muss nicht ausgeführt werden, um den Befehl cp verwenden zu können. Praktisch, wenn Ihr Container ständig abstürzt.
Martlark
219

Sie müssen nicht verwenden docker run .

Sie können es mit tun docker create .

Aus den Dokumenten :

Der docker createBefehl erstellt eine beschreibbare Containerebene über dem angegebenen Image und bereitet sie für die Ausführung des angegebenen Befehls vor. Die Container-ID wird dann gedruckt STDOUT. Dies ist ähnlich, docker run -daußer dass der Container nie gestartet wird.

Sie können also Folgendes tun:

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

Hier startet man nie den Container. Das sah für mich von Vorteil aus.

Ishan Bhatt
quelle
19
Dies erfordert mehr Upvotes. Ideal, wenn Sie nur etwas in einem Container erstellen und dann die Ausgaben kopieren müssen.
Honza Kalfus
4
@ HonzaKalfus Ich stimme zu, dass dies höher sein muss. Genau das war ich. Ich habe dies verwendet, um einige Binärdateien in einer bekannten Umgebung (Amazon Linux in einer bestimmten Version) zu erstellen. konnte ein Shell-Skript erstellen, das den Docker vollständig erstellt und die resultierende Binärdatei daraus extrahiert hat! Perfekt.
Mark
1
Ist -tierforderlich und basherforderlich?
18.
@jII, ich hatte es getan, weil ich später Docker darauf laufen lasse. In einfachen Fällen wird es nicht benötigt, aber es schadet auch hier nicht.
Ishan Bhatt
Ist es irgendwie möglich, Platzhalter zu verwenden? Ich meine ... Ich kenne den genauen Namen der Datei, die ich kopieren muss, nicht, da sie eine Versionsnummer enthält.
Juzzlin
87

Hängen Sie ein "Volume" ein und kopieren Sie die Artefakte dorthin:

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

Wenn der Build abgeschlossen ist und der Container nicht mehr ausgeführt wird, wurden die Artefakte aus dem Build bereits in den kopiert artifacts Verzeichnis auf dem Host .

Bearbeiten

Vorsichtsmaßnahme: Wenn Sie dies tun, können Probleme mit der Benutzer-ID des Docker-Benutzers auftreten, die mit der Benutzer-ID des aktuell ausgeführten Benutzers übereinstimmt. Das heißt, die Dateien in /artifactswerden als Eigentum des Benutzers mit der UID des Benutzers angezeigt , der im Docker-Container verwendet wird. Eine Möglichkeit, dies zu umgehen, besteht darin, die UID des anrufenden Benutzers zu verwenden:

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
djhaskin987
quelle
7
Tatsächlich können Sie den chownBefehl verwenden, um die Benutzer-ID und die Gruppen-ID auf dem Host-Computer abzugleichen.
Dimchansky
@Frondor Siehe Volume-Konfigurationsreferenz docs.docker.com/compose/compose-file/…
djhaskin987
Schon getan, und das wird nicht funktionieren. Sobald der Container zum ersten Mal Dateien auf das Volume kopiert hat, ist das Volume beim nächsten Mal nicht mehr leer und die Dateien werden nicht von den neueren überschrieben. Der Container gibt den Hostdateien Priorität (diejenigen, die beim ersten Mounten des Container-Images kopiert wurden).
Frondor
klingt wie etwas, das seine eigene SO-Frage sein könnte @Frondor
djhaskin987
1
Ich kaufe dir einen Bierkameraden! Vielen Dank!
Dimitar Vukman
27

Mounten Sie ein Volume, kopieren Sie die Artefakte, passen Sie die Eigentümer-ID und die Gruppen-ID an:

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
Dimchansky
quelle
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

Beschreibung

docker runmit einem Host-Volume chowndas Artefakt, cpdas Artefakt zum Host-Volume:

$ 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

Dieser Trick funktioniert, weil der chownAufruf innerhalb des Heredocs dauert$(id -u):$(id -g) Werte von außerhalb des laufenden Behälter; dh der Docker-Host.

Die Vorteile sind:

  • du musst nicht docker container run --nameoderdocker container create --name vorher
  • du musst nicht docker container rmdanach
Rubicks
quelle
2
Upvoted für den Vergleich zwischen cpund volumenbasierten Antworten. Auch für den idTrick für den Besitz, das ist manchmal ein echtes
Problem
18

Die meisten Antworten geben nicht an, dass der Container ausgeführt werden muss, bevor er docker cpfunktioniert:

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
cmcginty
quelle
3
BTW, ob der Behälter muss / kann seinen Lauf / gestoppt / entweder scheint davon abzuhängen Art von Host / Virtualisierung-Technik . Das aktuelle Docker-Dokument sagt: "Der CONTAINER kann ein laufender oder gestoppter Container sein." Mehrere Stellen auf SO, einschließlich eines Kommentars zur akzeptierten Antwort, sagen "Dies funktioniert auch bei einem gestoppten Container". Unter Windows Hyper-Vist es anscheinend notwendig , den Container zu stoppen, bevor eine Datei kopiert wird .
ToolmakerSteve
Das Kopieren funktioniert auch, wenn der Container gestoppt ist.
Luke W
17

Wenn Sie keinen laufenden Container haben, nur ein Bild, und davon ausgehen, dass Sie nur eine Textdatei kopieren möchten, können Sie Folgendes tun:

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

Ich poste dies für alle, die Docker für Mac verwenden. Das hat bei mir funktioniert:

 $ mkdir mybackup # local directory on Mac

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

Beachten Sie, dass , wenn ich mit Halterung , -vdassbackup Verzeichnis automatisch erstellt wird.

Ich hoffe, dass dies eines Tages für jemanden nützlich ist. :) :)

Paul
quelle
Wenn Sie Docker-Compose verwenden, sind Volumes von ab Version 3 veraltet.
Mulg0r
Informationen zum Hinzufügen des Kommentars von mulg0r finden Sie unter stackoverflow.com/a/45495380/199364. In Version 3 platzieren Sie einen volumesBefehl im Stammverzeichnis von config.yml, damit Volumes für mehrere Container zugänglich sind.
ToolmakerSteve
5

Wenn Sie nur eine Datei aus einem Image (anstelle eines laufenden Containers) ziehen möchten, können Sie Folgendes tun:

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

Dadurch wird der Container aufgerufen, die neue Datei geschrieben und der Container entfernt. Ein Nachteil ist jedoch, dass die Dateiberechtigungen und das Änderungsdatum nicht erhalten bleiben.

sg
quelle
5

Mit der Version von Docker 19.03 können Sie das Erstellen des Containers und sogar das Erstellen eines Images überspringen. Bei BuildKit-basierten Builds gibt es eine Option zum Ändern des Ausgabeziels. Sie können dies verwenden, um die Ergebnisse des Builds in Ihr lokales Verzeichnis und nicht in ein Image zu schreiben. Beispiel: Hier ist ein Build einer Go-Binärdatei:

$ 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

Aus der obigen Docker-Datei erstelle ich die artifactBühne, die nur die Dateien enthält, die ich exportieren möchte. Mit dem neu eingeführten --outputFlag kann ich diese in ein lokales Verzeichnis anstatt in ein Bild schreiben. Dies muss mit der BuildKit-Engine durchgeführt werden, die mit 19.03 ausgeliefert wird:

$ 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

Nach Abschluss des Builds wurde die appBinärdatei exportiert:

$ ls
Dockerfile  app  go.mod  main.go

$ ./app
Ready to receive requests on port 8080

Docker hat andere Optionen für das --outputFlag, die in seinem vorgelagerten BuildKit-Repo dokumentiert sind: https://github.com/moby/buildkit#output

BMitch
quelle
Standard Build Cache nicht für Build mit Ausgabe verwendet, es ist schlecht
burtsevyg
@burtsevyg Buildkit ist ein anderer Builder, der eine andere Cache-Umgebung verwendet. Es ist viel effizienter im Cache.
BMitch
Danke, ich werde meine Build-Knoten verbessern.
Burtsevyg
4

Als allgemeinere Lösung gibt es ein CloudBees-Plugin, das Jenkins in einem Docker-Container erstellen kann . Sie können ein zu verwendendes Image aus einer Docker-Registrierung auswählen oder eine Docker-Datei definieren, die erstellt und verwendet werden soll.

Der Arbeitsbereich wird als Volume (mit dem entsprechenden Benutzer) in den Container eingebunden, als Arbeitsverzeichnis festgelegt und die von Ihnen angeforderten Befehle (innerhalb des Containers) ausgeführt. Sie können dazu auch das Docker-Workflow-Plugin (wenn Sie Code der Benutzeroberfläche vorziehen) mit dem Befehl image.inside () {} verwenden.

Grundsätzlich alles in Ihren CI / CD-Server und noch einige mehr.

BobMcGee
quelle
4

Ich habe PowerShell (Admin) mit diesem Befehl verwendet.

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

Beispiel

docker cp ff3a6608467d:/var/www/app/error.html  C:\\error.html
Khachornchit Songsaen
quelle
2

Eine weitere gute Option besteht darin, zuerst den Container zu erstellen und ihn dann mit dem Flag -c und dem Shell-Interpreter auszuführen, um einige Befehle auszuführen

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

Der obige Befehl führt dies aus:

-ich = Führe den Container im interaktiven Modus aus

--rm = hat den Container nach der Ausführung entfernt.

-v = hat einen Ordner als Volume von Ihrem Hostpfad zum Containerpfad freigegeben.

Schließlich können Sie mit / bin / sh -c einen Befehl als Parameter einführen, und dieser Befehl kopiert Ihre Hausaufgaben-Dateien in den Containerpfad.

Ich hoffe, diese zusätzliche Antwort kann Ihnen helfen

Dein Jaggy
quelle
1

Erstellen Sie ein Datenverzeichnis auf dem Hostsystem (außerhalb des Containers) und hängen Sie dieses in ein Verzeichnis ein, das innerhalb des Containers sichtbar ist. Dadurch werden die Dateien an einem bekannten Speicherort auf dem Hostsystem abgelegt, und Tools und Anwendungen auf dem Hostsystem können problemlos auf die Dateien zugreifen

docker run -d -v /path/to/Local_host_dir:/path/to/docker_dir docker_image:tag
Unschuldiger Anigbo
quelle
4
Auf diese Weise können Sie ein Verzeichnis und dessen Inhalt vom Host in den Container einfügen. Sie können keine Dateien aus dem Container zurück auf den Host kopieren.
BMitch
Es funktioniert, wenn der Host-Ordner sehr breite Berechtigungen hat?
Giorgiosironi
0

Erstellen Sie einen Pfad, in den Sie die Datei kopieren möchten, und verwenden Sie dann:

docker run -d -v hostpath:dockerimag
Chandra Pal
quelle
0

Sie können bindanstelle von verwenden, volumewenn Sie nur einen Ordner bereitstellen möchten, keinen speziellen Speicher für einen Container erstellen:

  1. Erstellen Sie Ihr Bild mit Tag:

    docker build . -t <image>

  2. Führen Sie Ihr Image aus und binden Sie das aktuelle Verzeichnis $ (pwd), in dem app.py gespeichert ist, und ordnen Sie es / root / example / in Ihrem Container zu.

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

zytfo
quelle
0

Dies kann auch im SDK erfolgen, beispielsweise in Python. Wenn Sie bereits einen Container erstellt haben, können Sie den Namen über die Konsole nachschlagen (docker ps -a suchen.) Der Name scheint eine Verkettung eines Wissenschaftlers und eines Adjektivs (dh "entspannter_Pasteur") zu sein.

Check out 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()

Dann wird so etwas aus dem angegebenen Pfad (/ output) im Container zu Ihrem Host-Computer gezogen und der Teer entpackt.

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()
John Drinane
quelle