Jak mogę dodać wolumin do istniejącego kontenera Docker?

297

Mam kontener Docker, który utworzyłem, po prostu instalując Docker na Ubuntu i wykonując:

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

Natychmiast zacząłem instalować Javę i niektóre inne narzędzia, spędziłem z nią trochę czasu i zatrzymałem kontener

exit

Potem chciałem dodać tom i zdałem sobie sprawę, że nie jest to tak proste, jak się spodziewałem. Jeśli sudo docker -v /somedir run ...użyję, skończę z nowym, nowym kontenerem, więc zainstalowałbym Javę i zrobiłbym to, co już zrobiłem, by dotrzeć do kontenera z zamontowanym woluminem.

Cała dokumentacja dotycząca montowania folderu z hosta wydaje się sugerować, że montowanie woluminu jest czymś, co można zrobić podczas tworzenia kontenera. Tak więc jedyną opcją, której muszę unikać od nowa konfigurowania nowego kontenera od zera, jest zatwierdzenie istniejącego kontenera w repozytorium i wykorzystanie go jako podstawy nowego podczas montowania woluminu.

Czy to rzeczywiście jedyny sposób na dodanie woluminu do istniejącego kontenera?

Mahonya
źródło
1
Po kontenerach stały się one integralną częścią programistów i stąd takie pytania są tutaj częściej zadawane. Pytania zamieszczone tutaj przy użyciu dockertagu to 34k + , czyli znacznie więcej niż te dwie strony stackoverflow.com/questions/tagged/docker
MA Hossain Tonu

Odpowiedzi:

394

Możesz zatwierdzić swój istniejący kontener (czyli utworzyć nowy obraz ze zmian kontenera), a następnie uruchomić go z nowymi wierzchowcami.

Przykład:

$ 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

Jeśli wszystko jest w porządku, zatrzymaj stary pojemnik i użyj tego nowego.

Otóż ​​to :)

Leonardo Cuquejo
źródło
22
Jeśli z jakiegoś powodu potrzebujesz nowego kontenera, aby wziąć starą nazwę, użyj nazwy dokera po usunięciu starej.
Dirk
10
chciałem tylko zaznaczyć, że powyżej, o którym wspominasz, newnameofcontainerże prawdopodobnie należy to nazwać new_image_name- ponieważ docker committworzy nowy obraz w twoim systemie. Następnie w poniższym przykładzie docker runużyjesz nazwy obrazu , z którego chcesz uruchomić nowy kontener. Powyższe działa, ale chciałem wyjaśnić innym, że symbol zastępczy newname ofcontainer powyżej jest w rzeczywistości nazwą nowego obrazu. dzięki! niesamowita odpowiedź. och, możesz zobaczyć nowo utworzony obraz z pierwszej komendy docker image ls
dokowania
3
W rzeczywistości nie musisz zatwierdzać nowego kontenera, jeśli chcesz zacząć od obrazu. Po prostu docker run -v /srv/a:/tmp ubuntu:14.04jest dobrze.
YongHao Hu
Mam już kontener z wszystkimi plikami. jeśli powyższa metoda tworzy nowy kontener, nie mogę zbudować wszystkiego od nowa. Czy istnieje sposób, aby tego uniknąć i zamontować bez konieczności tworzenia nowego kontenera lub obrazu?
dhinar,
Czy to spowoduje zachowanie starych mapowań woluminów ze starego kontenera, czy też powinienem je ponownie zadeklarować w nowym kontenerze?
thebeancounter
79

Nie mamy żadnego sposobu na dodanie woluminu w uruchomionym kontenerze, ale aby osiągnąć ten cel, możesz użyć poniższych poleceń:

Skopiuj pliki / foldery między kontenerem a lokalnym systemem plików: -

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

W celach informacyjnych patrz:

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

użytkownik128364
źródło
47
Istnieje ogromna różnica między montowaniem woluminu a kopiowaniem plików do iz kontenera ...
Jules
31
W każdym razie pomogło mi to. Nie znałem polecenia „docker cp” i starałem się osiągnąć dokładnie to - skopiować pliki z uruchomionego kontenera na host.
Ivan
3
to nie jest mount, ale przydaje się przywracanie plików i pienienie między kontenerem a hostem lokalnym.
linehrr
Chociaż rozwiązuje to problem lokalnej replikacji zawartości kontenera, nie jest to bliskie równoważności z zamontowaniem woluminu i nie powinno być traktowane jako alternatywa. Mianowicie replikacją musi zarządzać użytkownik, a dane istnieją teraz w dwóch miejscach.
Sebastian Gaweda
1
Nie rozumiem, dlaczego tak dużo głosów, to bardzo zła odpowiedź na zadane pytanie.
João Matos,
33

Pomyślnie zamontowałem /home/<user-name>folder mojego hosta w /mntfolderze istniejącego (nie uruchomionego) kontenera. Możesz to zrobić w następujący sposób:

  1. Otwórz plik konfiguracyjny odpowiadający zatrzymanemu kontenerowi, który można znaleźć w /var/lib/docker/containers/99d...1fb/config.v2.json(może dotyczyć config.jsonstarszych wersji dokera).

  2. Znajdź MountPointssekcję, która była pusta w moim przypadku: "MountPoints":{}. Następnie zamień zawartość na coś takiego (możesz skopiować odpowiednią zawartość z innego pojemnika z odpowiednimi ustawieniami):

"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}}

lub taki sam (sformatowany):

  "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. Uruchom ponownie usługę dokowania: service docker restart

Działa to dla mnie z Ubuntu 18.04.1 i Docker 18.09.0

Igor Bendrup
źródło
3
Dziękuję za odpowiedź. Krok 3 jest kluczowy. Dodałbym również, że lepiej jest najpierw zatrzymać kontener dokera przed napisaniem.
buzypi
7
To najlepsza odpowiedź, ponieważ całkowicie zachowuje istniejący pojemnik. Tak zrobiłem: 1. Zatrzymaj silnik dokera: systemctl stop docker.service2. Edytuj config.v2.json: vim <(jq . /var/lib/docker/containers/<container-ID>/config.v2.json)3. Zapisz aktualizacje do pliku: :w config.v2.json4. Wyjdź z vima: :q!5. Zaktualizuj istniejący plik: jq -c . config.v2.json > /var/lib/docker/containers/<container-ID>/config.v2.json6. Uruchom silnik dokera: systemctl start docker.service7. Uruchom kontener, jeśli to konieczne : docker start <container-name/ID>8. Ciesz się :-)
Kontrola Androida
2
Kluczowym krokiem jest service docker restart. Próbowałem docker restart <container>wtedy, aby nowa konfiguracja nie została odczytana i została zastąpiona przez starą konfigurację.
KFL
1
jqPomoże również ładnie wydrukować JSON, więc można edytować go jako człowieka:cat config.v2.json | jq . > config.json
KFL
14

Jérôme Petazzoni ma całkiem interesujący post na blogu, w jaki sposób dołączyć wolumin do kontenera podczas jego działania . To nie jest coś, co jest wbudowane w Docker po wyjęciu z pudełka, ale możliwe do osiągnięcia.

Jak również wskazuje

To nie będzie działać na systemach plików, które nie są oparte na urządzeniach blokowych.

Działa to tylko wtedy, gdy / proc / mounts poprawnie wyświetla węzeł urządzenia blokowego (co, jak widzieliśmy powyżej, niekoniecznie jest prawdą).

Testowałem to tylko w moim lokalnym środowisku; Nie próbowałem nawet wystąpienia w chmurze ani nic takiego

YMMV

R0MANARMY
źródło
8

Niestety opcja przełączania do montowania woluminu znajduje się tylko w runpoleceniu.

docker run --help

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

Istnieje jednak sposób obejścia tego problemu, dzięki czemu nie trzeba ponownie instalować aplikacji, które zostały już skonfigurowane w kontenerze.

  1. Wyeksportuj swój kontener docker container export -o ./myimage.docker mycontainer
  2. Importuj jako obraz docker import ./myimage.docker myimage
  3. Następnie docker run -i -t -v /somedir --name mycontainer myimage /bin/bash
Adel Helal
źródło
1
FYI - docker containernie jest prawidłowym poleceniem w wersji 1.11.2 (która jest najnowszą wersją obsługiwaną przez Synology od tego momentu). Nie mogę jednak znaleźć żadnych dokumentów mówiących, kiedy został dodany. W tym przypadku pierwszym poleceniem jest docker export -o ./myimage.docker mycontainer.
Chris R. Donnelly,
2

Uwaga dotycząca używania kontenerów Docker Windows po tym, jak musiałem długo szukać tego problemu!

Warunki:

  • Windows 10
  • Docker Desktop (najnowsza wersja)
  • za pomocą Docker Windows Container dla obrazu microsoft / mssql-server-windows-developer

Problem:

  • Chciałem zamontować słownik hosta w moim kontenerze Windows.

Rozwiązanie częściowo opisane tutaj:

  • utwórz kontener dokerów

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

  • przejdź do powłoki poleceń w kontenerze

docker exec -it <CONTAINERID> cmd.exe

  • utwórz DIR

mkdir DirForMount

  • zatrzymać pojemnik

docker container stop <CONTAINERID>

  • zatwierdzić kontener

docker commit <CONTAINERID> <NEWIMAGENAME>

  • usuń stary pojemnik

docker container rm <CONTAINERID>

  • stwórz nowy pojemnik z nowym montażem obrazu i woluminu

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

Po tym rozwiązałem ten problem w kontenerach Windows dokerów.

droebi
źródło
-3

Najlepszym sposobem jest skopiowanie wszystkich plików i folderów w katalogu w lokalnym systemie plików poprzez: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

SRC_PATHjest na kontenerze DEST_PATHjest na localhost

Następnie docker-compose downpodłącz wolumin do tego samego DEST_PATHi uruchom kontenery Docker za pomocądocker-compose up -d

Dodaj wolumin, postępując zgodnie z docker-compose.yml

volumes:
 - DEST_PATH:SRC_PATH
Vatsal Mishra
źródło
Istnieją inne, lepsze opcje powyżej.
MrR
Rzeczywiście, istnieją lepsze opcje powyżej, a kopiowanie plików nie powoduje ich montowania. Ponadto definicja „woluminów” podana w opcji dokowania-komponowania jest odwrotna: woluminy: - ŚCIEŻKA_HOSTA: ŚCIEŻKA_WYJŚCIA
Guillaume S.