Comment puis-je ajouter un volume à un conteneur Docker existant?

297

J'ai un conteneur Docker que j'ai créé simplement en installant Docker sur Ubuntu et en faisant:

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

J'ai immédiatement commencé à installer Java et quelques autres outils, à y passer du temps et à arrêter le conteneur en

exit

Ensuite, j'ai voulu ajouter un volume et j'ai réalisé que ce n'était pas aussi simple que je le pensais. Si j'utilise sudo docker -v /somedir run ...alors je me retrouve avec un nouveau conteneur frais, donc j'aurais installé Java et faire ce que j'ai déjà fait auparavant juste pour arriver à un conteneur avec un volume monté.

Toute la documentation sur le montage d'un dossier à partir de l'hôte semble impliquer que le montage d'un volume est quelque chose qui peut être fait lors de la création d'un conteneur. Donc, la seule option que j'ai pour éviter de reconfigurer un nouveau conteneur à partir de zéro est de valider le conteneur existant dans un référentiel et de l'utiliser comme base d'un nouveau lors du montage du volume.

Est-ce en effet la seule façon d'ajouter un volume à un conteneur existant?

mahonya
la source
1
Après les conteneurs, ceux-ci sont devenus une partie intégrante des programmeurs et, par conséquent, de telles questions sont affichées plus souvent ici. Les questions postées ici en utilisant la dockerbalise sont 34k + , ce qui est bien plus que ces deux sites stackoverflow.com/questions/tagged/docker
MA Hossain Tonu

Réponses:

394

Vous pouvez valider votre conteneur existant (c'est-à-dire créer une nouvelle image à partir des modifications du conteneur), puis l'exécuter avec vos nouvelles montures.

Exemple:

$ 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

Si tout va bien, arrêtez votre ancien conteneur et utilisez ce nouveau.

C'est tout :)

Leonardo Cuquejo
la source
22
Et si vous avez besoin du nouveau conteneur pour prendre l'ancien nom pour une raison quelconque, utilisez docker renommer après avoir supprimé l'ancien.
Dirk
10
je voulais juste souligner que ci-dessus où vous mentionnez newnameofcontainerque cela devrait probablement être nommé new_image_name- car docker commitcrée une nouvelle image sur votre système. Ensuite, lorsque vous effectuez une opération, docker runvous utilisez le nom de l' image à partir de laquelle vous souhaitez exécuter un nouveau conteneur. Ce qui précède fonctionne, mais je voulais simplement clarifier pour d'autres que l'espace réservé newnameofcontainer ci-dessus est en fait le nom d'une nouvelle image. Merci! réponse géniale. oh, vous pouvez voir l'image nouvellement créée à partir de la première commande docker commit à l'aide dedocker image ls
FireDragon
3
En fait, vous n'avez pas besoin de valider un nouveau conteneur si vous voulez commencer à partir d'une image. C'est juste docker run -v /srv/a:/tmp ubuntu:14.04bon.
YongHao Hu
J'ai déjà un conteneur fonctionnant avec tous les fichiers. si la méthode ci-dessus crée un nouveau conteneur, je ne peux pas tout construire à nouveau. Existe-t-il un moyen d'éviter cela et de monter sans avoir à créer un nouveau conteneur ou une nouvelle image?
dhinar
Cela conservera-t-il les anciens mappages de volume de l'ancien conteneur ou devrais-je également les déclarer à nouveau avec le nouveau conteneur?
thebeancounter
79

Nous n'avons aucun moyen d'ajouter du volume dans le conteneur en cours d'exécution, mais pour atteindre cet objectif, vous pouvez utiliser les commandes ci-dessous:

Copiez des fichiers / dossiers entre un conteneur et le système de fichiers local: -

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

Pour référence, voir:

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

user128364
la source
47
Il y a une énorme différence entre monter un volume et copier des fichiers vers et depuis un conteneur ...
Jules
31
Quoi qu'il en soit, cela m'a aidé. Je ne connaissais pas la commande 'docker cp', et j'essayais d'obtenir exactement cela - copier les fichiers du conteneur en cours d'exécution vers l'hôte.
Ivan
3
ce n'est pas une monture, mais c'est pratique pour ramener des fichiers et les faire mousser entre le conteneur et l'hôte local.
linehrr le
Bien que cela résout le problème de la réplication locale du contenu du conteneur, cela n'est pas près d'être équivalent à monter un volume et ne doit pas être considéré comme une alternative. A savoir, la réplication doit être gérée par l'utilisateur, et les données existent maintenant à deux endroits.
Sebastian Gaweda
1
Je ne comprends pas pourquoi tant de votes positifs, c'est une très mauvaise réponse à la question posée.
João Matos
33

J'ai réussi à monter le /home/<user-name>dossier de mon hôte dans le /mntdossier du conteneur existant (pas en cours d'exécution). Vous pouvez le faire de la manière suivante:

  1. Ouvrez le fichier de configuration correspondant au conteneur arrêté, qui peut être trouvé à /var/lib/docker/containers/99d...1fb/config.v2.json(peut être config.jsonpour les anciennes versions de docker).

  2. Trouvez la MountPointssection qui était vide dans mon cas: "MountPoints":{}. Remplacez ensuite le contenu par quelque chose comme ceci (vous pouvez copier le contenu approprié d'un autre conteneur avec les paramètres appropriés):

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

ou le même (formaté):

  "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. Redémarrez le service Docker: service docker restart

Cela fonctionne pour moi avec Ubuntu 18.04.1 et Docker 18.09.0

Igor Bendrup
la source
3
Merci d'avoir répondu. L'étape 3 est cruciale. J'ajouterais également qu'il vaut mieux arrêter le conteneur docker avant de faire l'écriture.
buzypi
7
C'est la meilleure réponse car elle préserve totalement le conteneur existant. Voici ce que j'ai fait: 1. Arrêtez le moteur docker: systemctl stop docker.service2. Éditez config.v2.json: vim <(jq . /var/lib/docker/containers/<container-ID>/config.v2.json)3. Enregistrez les mises à jour dans un fichier: :w config.v2.json4. Quittez vim: :q!5. Mettez à jour le fichier existant: jq -c . config.v2.json > /var/lib/docker/containers/<container-ID>/config.v2.json6. Démarrez le moteur docker: systemctl start docker.service7. Démarrez le conteneur si nécessaire : docker start <container-name/ID>8. Profitez :-)
Contrôle Android
2
Une étape clé est service docker restart. J'ai essayé de docker restart <container>ne pas reprendre la nouvelle configuration, et elle est écrasée par l'ancienne configuration.
KFL
1
jqCela aidera également à imprimer le JSON afin qu'il soit modifiable par l'homme:cat config.v2.json | jq . > config.json
KFL
14

Jérôme Petazzoni a un article de blog assez intéressant sur la façon d' attacher un volume à un conteneur pendant son exécution . Ce n'est pas quelque chose qui est intégré à Docker hors de la boîte, mais possible d'accomplir.

Comme il le souligne également

Cela ne fonctionnera pas sur les systèmes de fichiers qui ne sont pas basés sur des périphériques bloc.

Cela ne fonctionnera que si / proc / mounts répertorie correctement le nœud de périphérique de bloc (qui, comme nous l'avons vu ci-dessus, n'est pas nécessairement vrai).

De plus, je n'ai testé cela que sur mon environnement local; Je n'ai même pas essayé sur une instance cloud ou quelque chose comme ça

YMMV

R0MANARMY
la source
8

Malheureusement, l'option de commutateur pour monter un volume ne se trouve que dans la runcommande.

docker run --help

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

Il existe cependant un moyen de contourner ce problème afin de ne pas avoir à réinstaller les applications que vous avez déjà configurées sur votre conteneur.

  1. Exportez votre conteneur docker container export -o ./myimage.docker mycontainer
  2. Importer en tant qu'image docker import ./myimage.docker myimage
  3. ensuite docker run -i -t -v /somedir --name mycontainer myimage /bin/bash
Adel Helal
la source
1
FYI - docker containern'est pas une commande valide sur 1.11.2 (qui est la dernière version prise en charge par Synology à ce jour). Cependant, je ne trouve aucun document indiquant quand il a été ajouté. Dans ce cas, la première commande est docker export -o ./myimage.docker mycontainer.
Chris R. Donnelly
2

Une note pour utiliser les conteneurs Docker Windows après avoir longtemps cherché ce problème!

Conditions:

  • Windows 10
  • Docker Desktop (dernière version)
  • à l'aide de Docker Windows Container pour l'image microsoft / mssql-server-windows-developer

Problème:

  • Je voulais monter un dictionnaire hôte dans mon conteneur Windows.

Solution partiellement décrite ici:

  • créer un conteneur docker

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

  • aller au shell de commande dans le conteneur

docker exec -it <CONTAINERID> cmd.exe

  • créer DIR

mkdir DirForMount

  • arrêter le conteneur

docker container stop <CONTAINERID>

  • commit container

docker commit <CONTAINERID> <NEWIMAGENAME>

  • supprimer l'ancien conteneur

docker container rm <CONTAINERID>

  • créer un nouveau conteneur avec un nouveau montage d'image et de volume

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

Après cela, j'ai résolu ce problème sur les conteneurs Windows Docker.

droebi
la source
-3

La meilleure façon est de copier tous les fichiers et dossiers dans un répertoire de votre système de fichiers local en: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

SRC_PATHest sur le conteneur DEST_PATHest sur l'hôte local

Ensuite , ne docker-compose downfixez un volume à la même DEST_PATHet exécuter des conteneurs Docker en utilisantdocker-compose up -d

Ajouter du volume en suivant dans docker-compose.yml

volumes:
 - DEST_PATH:SRC_PATH
Vatsal Mishra
la source
Il existe d'autres meilleures options ci-dessus.
MrR
En effet, il existe de meilleures options ci-dessus, et la copie de fichiers ne les monte pas. De plus, la définition des "volumes" donnée pour l'option docker-compose est l'inverse: volumes: - HOST_PATH: CONTAINER_PATH
Guillaume S.