Wie kann ich einem vorhandenen Docker-Container ein Volume hinzufügen?

297

Ich habe einen Docker-Container, den ich einfach erstellt habe, indem ich Docker unter Ubuntu installiert habe und Folgendes getan habe:

sudo docker run -i -t ubuntu /bin/bash

Ich begann sofort mit der Installation von Java und einigen anderen Tools, verbrachte einige Zeit damit und stoppte den Container

exit

Dann wollte ich ein Volume hinzufügen und stellte fest, dass dies nicht so einfach ist, wie ich es mir vorgestellt hatte. Wenn ich sudo docker -v /somedir run ...dann verwende, erhalte ich einen neuen Container, also müsste ich Java installieren und das tun, was ich bereits getan habe, um zu einem Container mit einem gemounteten Volume zu gelangen.

Die gesamte Dokumentation zum Mounten eines Ordners vom Host scheint zu implizieren, dass das Mounten eines Volumes beim Erstellen eines Containers durchgeführt werden kann. Die einzige Option, die ich vermeiden muss, um einen neuen Container von Grund auf neu zu konfigurieren, besteht darin, den vorhandenen Container in ein Repository zu übertragen und diesen als Basis für einen neuen zu verwenden, während das Volume bereitgestellt wird.

Ist dies tatsächlich die einzige Möglichkeit, einem vorhandenen Container ein Volume hinzuzufügen?

Mahonya
quelle
1
Nach den Containern wurden diese ein wesentlicher Bestandteil der Programmierer und daher werden solche Fragen hier häufiger gestellt. Fragen, die hier mit dockerTag gepostet werden, sind 34k + , was weit mehr ist als diese beiden Websites stackoverflow.com/questions/tagged/docker
MA Hossain Tonu

Antworten:

394

Sie können Ihren vorhandenen Container festschreiben (dh aus den Änderungen des Containers ein neues Image erstellen) und es dann mit Ihren neuen Bereitstellungen ausführen.

Beispiel:

$ docker ps  -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED              STATUS                          PORTS               NAMES
    5a8f89adeead        ubuntu:14.04          "/bin/bash"              About a minute ago   Exited (0) About a minute ago                       agitated_newton

$ docker commit 5a8f89adeead newimagename

$ docker run -ti -v "$PWD/dir1":/dir1 -v "$PWD/dir2":/dir2 newimagename /bin/bash

Wenn alles in Ordnung ist, stoppen Sie Ihren alten Container und verwenden Sie diesen neuen.

Das ist es :)

Leonardo Cuquejo
quelle
22
Wenn der neue Container aus irgendeinem Grund den alten Namen annehmen soll, verwenden Sie Docker Rename, nachdem Sie den alten entfernt haben.
Dirk
10
Ich wollte nur darauf hinweisen, dass Sie oben erwähnen, newnameofcontainerdass dies wahrscheinlich benannt werden sollte new_image_name- weil docker commitein neues Image auf Ihrem System erstellt wird. Wenn Sie dann im Folgenden eine ausführen, verwenden docker runSie tatsächlich den Namen des Bildes , von dem aus Sie einen neuen Container ausführen möchten. Das Obige funktioniert, wollte aber nur für andere klarstellen, dass der Platzhalter newnameofcontainer oben tatsächlich der Name für ein neues Bild ist. Vielen Dank! tolle Antwort. Oh, Sie können das neu erstellte Bild aus dem ersten Docker-Commit-Befehl mitdocker image ls
FireDragon
3
Tatsächlich müssen Sie keinen neuen Container festschreiben, wenn Sie von einem Image ausgehen möchten. Ist einfach docker run -v /srv/a:/tmp ubuntu:14.04gut.
YongHao Hu
Ich habe bereits einen Container mit allen Dateien. Wenn die obige Methode einen neuen Container erstellt, kann ich nicht alles noch einmal erstellen. Gibt es eine Möglichkeit, dies zu vermeiden und zu mounten, ohne einen neuen Container oder ein neues Image erstellen zu müssen?
Dhinar
Behält dies die alten Volume-Zuordnungen vom alten Container bei oder sollte ich sie auch mit dem neuen Container erneut deklarieren?
Thebeancounter
79

Wir haben keine Möglichkeit, dem laufenden Container Volumen hinzuzufügen, aber um dieses Ziel zu erreichen, können Sie die folgenden Befehle verwenden:

Kopieren Sie Dateien / Ordner zwischen einem Container und dem lokalen Dateisystem: -

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

Referenz siehe:

https://docs.docker.com/engine/reference/commandline/cp/

user128364
quelle
47
Es gibt einen großen Unterschied zwischen dem Mounten eines Volumes und dem Kopieren von Dateien in und aus einem Container ...
Jules
31
Jedenfalls hat es mir geholfen. Ich kannte den Befehl 'docker cp' nicht und versuchte genau dies zu erreichen - kopieren Sie Dateien vom laufenden Container auf den Host.
Ivan
3
Es ist kein Mount, aber es ist praktisch, Dateien zwischen Container und lokalem Host zurückzubringen.
Linehrr
Dies löst zwar das Problem der lokalen Replikation von Containerinhalten, entspricht jedoch nicht annähernd dem Mounten eines Volumes und sollte nicht als Alternative betrachtet werden. Die Replikation muss nämlich vom Benutzer verwaltet werden, und die Daten sind jetzt an zwei Stellen vorhanden.
Sebastian Gaweda
1
Ich verstehe nicht, warum so viele Stimmen abgegeben wurden. Dies ist eine sehr falsche Antwort auf die gestellte Frage.
João Matos
33

Ich habe den /home/<user-name>Ordner meines Hosts erfolgreich in den /mntOrdner des vorhandenen (nicht laufenden) Containers gemountet . Sie können dies folgendermaßen tun:

  1. Öffnen Sie die Konfigurationsdatei, die dem gestoppten Container entspricht und unter zu finden ist /var/lib/docker/containers/99d...1fb/config.v2.json(möglicherweise config.jsonfür ältere Docker-Versionen).

  2. Suchabschnitt MountPoints, der in meinem Fall leer war : "MountPoints":{}. Als nächstes ersetzen Sie den Inhalt durch so etwas (Sie können den richtigen Inhalt aus einem anderen Container mit den richtigen Einstellungen kopieren):

"MountPoints":{"/mnt":{"Source":"/home/<user-name>","Destination":"/mnt","RW":true,"Name":"","Driver":"","Type":"bind","Propagation":"rprivate","Spec":{"Type":"bind","Source":"/home/<user-name>","Target":"/mnt"},"SkipMountpointCreation":false}}

oder das gleiche (formatiert):

  "MountPoints": {
    "/mnt": {
      "Source": "/home/<user-name>",
      "Destination": "/mnt",
      "RW": true,
      "Name": "",
      "Driver": "",
      "Type": "bind",
      "Propagation": "rprivate",
      "Spec": {
        "Type": "bind",
        "Source": "/home/<user-name>",
        "Target": "/mnt"
      },
      "SkipMountpointCreation": false
    }
  }
  1. Starten Sie den Docker-Dienst neu: service docker restart

Dies funktioniert bei mir mit Ubuntu 18.04.1 und Docker 18.09.0

Igor Bendrup
quelle
3
Danke für die Antwort. Schritt 3 ist entscheidend. Ich würde auch hinzufügen, dass es besser ist, den Docker-Container zuerst anzuhalten, bevor Sie schreiben.
Buzypi
7
Dies ist die beste Antwort, da der vorhandene Container vollständig erhalten bleibt. Folgendes habe ich getan: 1. Stoppen Sie die Docker-Engine: systemctl stop docker.service2. Bearbeiten config.v2.json: vim <(jq . /var/lib/docker/containers/<container-ID>/config.v2.json)3. Speichern Sie Aktualisierungen in einer Datei: :w config.v2.json4. Beenden Sie vim: :q!5. Aktualisieren Sie die vorhandene Datei: jq -c . config.v2.json > /var/lib/docker/containers/<container-ID>/config.v2.json6. Starten Sie die Docker-Engine: systemctl start docker.service7. Starten Sie gegebenenfalls den Container : docker start <container-name/ID>8. Viel Spaß :-)
Android Control
2
Ein wichtiger Schritt ist service docker restart. Ich habe versucht, docker restart <container>dann wird die neue Konfiguration nicht übernommen und wird von der alten Konfiguration überschrieben.
KFL
1
Auch jqwird dazu beitragen , ziemlich die JSON drucken , so dass es der mroe menschlichen editierbare:cat config.v2.json | jq . > config.json
KFL
14

Jérôme Petazzoni hat einen ziemlich interessanten Blog-Beitrag darüber, wie man ein Volume an einen Container anhängt, während dieser ausgeführt wird . Dies ist nicht sofort in Docker integriert, aber möglich.

Wie er auch betont

Dies funktioniert nicht auf Dateisystemen, die nicht auf Blockgeräten basieren.

Es funktioniert nur, wenn / proc / mounts den Blockgeräteknoten korrekt auflistet (was, wie wir oben gesehen haben, nicht unbedingt wahr ist).

Außerdem habe ich dies nur in meiner lokalen Umgebung getestet. Ich habe nicht einmal eine Cloud-Instanz oder ähnliches ausprobiert

YMMV

R0MANARMIE
quelle
8

Leider ist die Schalteroption zum Mounten eines Volumes nur im runBefehl enthalten.

docker run --help

-v, --volume list Bind mount a volume (default [])

Es gibt jedoch eine Möglichkeit, dies zu umgehen, sodass Sie die Anwendungen, die Sie bereits auf Ihrem Container eingerichtet haben, nicht neu installieren müssen.

  1. Exportieren Sie Ihren Container docker container export -o ./myimage.docker mycontainer
  2. Als Bild importieren docker import ./myimage.docker myimage
  3. Dann docker run -i -t -v /somedir --name mycontainer myimage /bin/bash
Adel Helal
quelle
1
Zu docker containerIhrer Information - ist in 1.11.2 kein gültiger Befehl (dies ist die neueste Version, die derzeit von Synology unterstützt wird). Ich kann jedoch keine Dokumente finden, die angeben, wann es hinzugefügt wurde. In diesem Fall ist der erste Befehl docker export -o ./myimage.docker mycontainer.
Chris R. Donnelly
2

Ein Hinweis zur Verwendung von Docker Windows-Containern, nachdem ich lange nach diesem Problem gesucht hatte!

Bedingungen:

  • Windows 10
  • Docker Desktop (neueste Version)
  • Verwenden von Docker Windows Container für Image Microsoft / MSSQL-Server-Windows-Entwickler

Problem:

  • Ich wollte ein Host-Wörterbuch in meinen Windows-Container einbinden.

Lösung wie hier teilweise beschrieben:

  • Docker-Container erstellen

docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y microsoft/mssql-server-windows-developer

  • Gehen Sie zur Befehlsshell im Container

docker exec -it <CONTAINERID> cmd.exe

  • Erstelle DIR

mkdir DirForMount

  • Behälter stoppen

docker container stop <CONTAINERID>

  • Container festschreiben

docker commit <CONTAINERID> <NEWIMAGENAME>

  • alten Container löschen

docker container rm <CONTAINERID>

  • Erstellen Sie einen neuen Container mit neuer Image- und Volume-Montage

docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y -v C:\DirToMount:C:\DirForMount <NEWIMAGENAME>

Danach habe ich dieses Problem auf Docker Windows Containern gelöst.

droebi
quelle
-3

Der beste Weg ist, alle Dateien und Ordner in einem Verzeichnis in Ihrem lokalen Dateisystem zu kopieren, indem Sie: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

SRC_PATH ist auf Container DEST_PATH ist auf localhost

Dann machen Sie docker-compose downein Volumen zum gleichen befestigenDEST_PATH und Docker - Containern laufen durch den Einsatzdocker-compose up -d

Fügen Sie Volumen hinzu, indem Sie folgen docker-compose.yml

volumes:
 - DEST_PATH:SRC_PATH
Vatsal Mishra
quelle
Es gibt oben andere, bessere Optionen.
MrR
In der Tat gibt es oben bessere Optionen, und beim Kopieren von Dateien werden diese nicht bereitgestellt. Darüber hinaus ist die für die Docker-Compose-Option angegebene "Volumes" -Definition umgekehrt: Volumes: - HOST_PATH: CONTAINER_PATH
Guillaume S.