523

I have a Docker container that I've created simply by installing Docker on Ubuntu and doing:

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

I immediately started installing Java and some other tools, spent some time with it, and stopped the container by

exit

Then I wanted to add a volume and realised that this is not as straightforward as I thought it would be. If I use sudo docker -v /somedir run ... then I end up with a fresh new container, so I'd have to install Java and do what I've already done before just to arrive at a container with a mounted volume.

All the documentation about mounting a folder from the host seems to imply that mounting a volume is something that can be done when creating a container. So the only option I have to avoid reconfiguring a new container from scratch is to commit the existing container to a repository and use that as the basis of a new one whilst mounting the volume.

Is this indeed the only way to add a volume to an existing container?

Pang
  • 9,564
  • 146
  • 81
  • 122
mahonya
  • 9,247
  • 7
  • 39
  • 68
  • Not sure if that helps but when I did `docker exec -it d1a2cc990208 bash` from the same location, I was in the container with the mounted volume. – Samos Dec 22 '22 at 16:44

10 Answers10

668

You can commit your existing container (that is create a new image from container’s changes) and then run it with your new mounts.

Example:

$ 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/somedir":/somedir newimagename /bin/bash

If it's all OK, stop your old container, and use this new one.

You can also commit a container using its name, for example:

docker commit agitated_newton newimagename

That's it :)

Nagev
  • 10,835
  • 4
  • 58
  • 69
BigLeo
  • 6,906
  • 2
  • 13
  • 12
  • 48
    And if you need the new container to take the old name for some reason, use [docker rename](https://docs.docker.com/engine/reference/commandline/rename/) after removing the old one. – Dirk Oct 27 '16 at 13:57
  • 17
    just wanted to point out that above where you mention `newnameofcontainer` that this should probably be named `new_image_name` -- because `docker commit` creates a new *image* on your system. Then in the following when you do a `docker run` you actually use the name of the *image* that you want to run a new container from. The above works but just wanted to clarify for others that the placeholder newnameofcontainer above is actually the name for a new image. thanks! awesome answer. oh, you can see the newly created image from the first docker commit command using `docker image ls` – FireDragon May 26 '17 at 00:10
  • 6
    In fact, you don't need commit a new container if you want to start from a image. Just `docker run -v /srv/a:/tmp ubuntu:14.04` is good. – chris Oct 13 '17 at 10:26
  • I already have a container running with all files. if the above method creates new container, i can not build everything from once again. Is there a way i can avoid this and mount without having to create new container or image? – dhinar1991 Apr 05 '18 at 05:29
  • Will this keep the old volume mappings from the old container or should I re-declare them with the new container also? – thebeancounter Sep 25 '18 at 07:05
  • @YongHaoHu nice idea! But is it not dangerous to put it in `/tmp`? i.e. the contents will get wiped when you stop your container? – Ciprian Tomoiagă Feb 14 '19 at 16:17
  • @CiprianTomoiagă Perhaps when you [*start*](https://serverfault.com/questions/377348/when-does-tmp-get-cleared) the container. – MrR Jun 16 '19 at 22:36
  • 6
    This won't preserve processes running in the original container. – gbajson Feb 03 '21 at 15:11
  • 4
    Commiting container won't keep volume bindings, any solution for that? – mecaf Aug 14 '21 at 12:49
  • I run docker on windows server 2019 that does not support commit of a running container , what is the equivalent command to use in windows? – Feiga Lubow Oct 19 '21 at 11:31
175

We don't have any way to add volume in running container, but to achieve this objective you may use the below commands:

Copy files/folders between a container and the local filesystem:

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH

For reference see:

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

Yam Mesicka
  • 6,243
  • 7
  • 45
  • 64
user128364
  • 4,533
  • 3
  • 20
  • 12
  • 104
    There's a huge difference between mounting a volume and copying files to and from a container... – Jules May 30 '17 at 12:01
  • 68
    Anyway it helped me. I didn't know 'docker cp' command, and was trying to achieve exactly this - copy files from running container to the host. – Ivan Jul 18 '17 at 08:07
  • 7
    it's not a mount, but it's handy to bring files back and froth between container and local host. – linehrr Apr 26 '19 at 15:32
  • 1
    While this does solve the problem of replicating container contents locally, this is not close to being equivalent to mounting a volume and shouldn't be thought of as an alternative. Namely, replication has to be managed by the user, and the data exists now in two places. – Bash Jul 26 '19 at 16:47
  • 9
    I don't understand why so many up votes, this is a very wrong answer for the question asked. – João Matos Nov 20 '19 at 10:32
  • 21
    This indeed not exactly the OP's case but I came here looking for a way to attach volume to a *running* container. My goal was to get some content in/out of a container on the fly while it's running; assuming I do not control container creation and there is no option of stopping it. This answer actually points out the only way of achieving this. So, +1 and Thanks! – AlexanderF Apr 25 '20 at 04:16
  • 2
    As mentioned there is no support to add volume in running container, I think that's closest answer. In our case we don't want to replicate apache htdocs and mysql database setup process again, Steps: 1) Create a new duplicate container with desired volumes 2) Copy related folders to new container 3) Remove old container -f – Azghanvi Jan 26 '21 at 17:05
  • The thing we're trying to mount may be a socket or other device so this answer falls a little short being of a full solution because it only applies to things that can be copied with a docker cp command. – Wyck Dec 21 '21 at 17:31
  • 1
    I think this is a practical answer. If you're trying to add a volume to a container, you can copy the data out of the container into the folder that will be used for the volume, and then you can simply remove and re-create the container and it'll pull in the data from that volume folder. Worked great, thanks! – Vance Palacio May 15 '23 at 22:58
110

I've successfully mount /home/<user-name> folder of my host to the /mnt folder of the existing (not running) container. You can do it in the following way:

  1. Open configuration file corresponding to the stopped container, which can be found at /var/lib/docker/containers/99d...1fb/config.v2.json (may be config.json for older versions of docker).

  2. Find MountPoints section, which was empty in my case: "MountPoints":{}. Next replace the contents with something like this (you can copy proper contents from another container with proper settings):

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

or the same (formatted):

  "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. Restart the docker service: service docker restart

This works for me with Ubuntu 18.04.1 and Docker 18.09.0

calbertts
  • 1,513
  • 2
  • 15
  • 34
Igor Bendrup
  • 2,637
  • 2
  • 16
  • 15
  • 8
    Thanks for the answer. Step 3 is crucial. I would also add that it's better to stop the docker container first before doing the write. – buzypi Mar 27 '19 at 13:02
  • 15
    This is the best answer as it totally preserves the existing container. This is what I did: 1. Stop the docker engine: `systemctl stop docker.service` 2. Edit `config.v2.json`: `vim <(jq . /var/lib/docker/containers//config.v2.json)` 3. Save updates to a file: `:w config.v2.json` 4. Exit vim: `:q!` 5. Update existing file: `jq -c . config.v2.json > /var/lib/docker/containers//config.v2.json` 6. Start the docker engine: `systemctl start docker.service` 7. Start the container if necessary: `docker start ` 8. Enjoy :-) – Android Control May 10 '19 at 18:30
  • 12
    **A key step** is `service docker restart`. I tried to `docker restart ` then the new config is not picked up, and it's getting overwritten by the old config. – KFL Apr 19 '20 at 01:38
  • 1
    Also `jq` will help pretty print the JSON so it's mroe human editable: `cat config.v2.json | jq . > config.json` – KFL Apr 19 '20 at 01:39
  • Amazing! Easy to follow and don't need to worry about losing files. Works like a charm. Thank you so much! – WhaSukGO May 03 '21 at 08:16
  • 2
    It seems I cannot find the `config.v2.json` by the container id in Docker version 20.10.7 – yode Jul 10 '21 at 21:56
  • 1
    It seems it doesn't work (2023/01), after restarting `config.v2.json` is restored back to the original state (without new mount point). – jnemecz Jan 03 '23 at 11:38
  • @jnemecz Did you **restart** the **docker** service itself, not the Container? – Dmytro Ovdiienko Jun 07 '23 at 14:46
26

Jérôme Petazzoni has a pretty interesting blog post on how to Attach a volume to a container while it is running. This isn't something that's built into Docker out of the box, but possible to accomplish.

As he also points out

This will not work on filesystems which are not based on block devices.

It will only work if /proc/mounts correctly lists the block device node (which, as we saw above, is not necessarily true).

Also, I only tested this on my local environment; I didn’t even try on a cloud instance or anything like that

YMMV

Community
  • 1
  • 1
Roman
  • 19,581
  • 6
  • 68
  • 84
14

Unfortunately the switch option to mount a volume is only found in the run command.

docker run --help

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

There is a way you can work around this though so you won't have to reinstall the applications you've already set up on your container.

  1. Export your container docker container export -o ./myimage.docker mycontainer
  2. Import as an image docker import ./myimage.docker myimage
  3. Then docker run -i -t -v /somedir --name mycontainer myimage /bin/bash
Adel Helal
  • 642
  • 1
  • 9
  • 20
  • 1
    FYI - `docker container` isn't a valid command on 1.11.2 (which is the latest version that is supported by Synology as of this writing). I can't find any docs saying when it was added, though. In this case the first command is `docker export -o ./myimage.docker mycontainer`. – Chris R. Donnelly Sep 23 '17 at 21:36
  • 1
    Using `docker commit` is much easier, see answer above https://stackoverflow.com/a/33956387/1260896 – Franklin Piat Dec 09 '20 at 10:49
  • 1
    This one doesn't preserve history though, so it's still a good solution for the space conscious. – Spartan Apr 23 '21 at 00:30
8

A note for using Docker Windows containers after I had to look for this problem for a long time!

Condiditions:

  • Windows 10
  • Docker Desktop (latest version)
  • using Docker Windows Container for image microsoft/mssql-server-windows-developer

Problem:

  • I wanted to mount a host dictionary into my windows container.

Solution as partially discripted here:

  • create docker container

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

  • go to command shell in container

docker exec -it <CONTAINERID> cmd.exe

  • create DIR

mkdir DirForMount

  • stop container

docker container stop <CONTAINERID>

  • commit container

docker commit <CONTAINERID> <NEWIMAGENAME>

  • delete old container

docker container rm <CONTAINERID>

  • create new container with new image and volume mounting

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

After this i solved this problem on docker windows containers.

droebi
  • 872
  • 1
  • 14
  • 27
0

My answer will be little different. You can stop your container, add the volume and restart it. How to do it, follow the steps.

docker volume create ubuntu-volume
docker stop <container-name>
sudo docker run -i -t --mount source=ubuntu-volume,target=<target-path-in-container> ubuntu /bin/bash 
Aditya Bhuyan
  • 328
  • 6
  • 10
  • 5
    docker run creates a _new_ container from an image (https://docs.docker.com/engine/reference/commandline/run/). OP is asking about adding a volume to an _existing_ container. – wxgeorge Mar 02 '22 at 13:36
0

You can stop and remove the container, append the existing volume in a startup script, and restart from the image. If the already existing existing partitions do keep the data, you shouldn't experience any loss of information. This should also work the same way with Dockerfile and Docker composer.

eg (solr image). (initial script)

#!/bin/sh
docker pull solr:8.5
docker stop my_solr
docker rm solr:8.5

docker create \
  --name my_solr \
  -v "/XXXX/docker/solr/solrdata":/var/solr \
  -p 8983:8983 \
  --restart unless-stopped \
  --user 1000:1000 \
  -e SOLR_HEAP=1g \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  solr:8.5
docker cp /home/XXXX/docker/solr/XXXXXXXX.jar my_solr:/opt/solr/contrib/dataimporthandler-extras/lib
docker start my_solr

file with the second volume

#!/bin/sh
docker pull solr:8.5
docker stop my_solr
docker rm solr:8.5

docker create \
  --name my_solr \
  -v "/XXXX/docker/solr/solrdata":/var/solr \
  -v "/XXXX/backups/solr_snapshot_folder":/var/solr_snapshots \
  -p 8983:8983 \
  --restart unless-stopped \
  --user 1000:1000 \
  -e SOLR_HEAP=1g \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  solr:8.5
docker cp /home/XXXX/docker/solr/XXXXXXXX.jar my_solr:/opt/solr/contrib/dataimporthandler-extras/lib
docker start my_solr
-1

Use symlink to the already mounted drive:

ln -s Source_path targer_path_which_is_already_mounted_on_the_running_docker

F. Müller
  • 3,969
  • 8
  • 38
  • 49
-6

The best way is to copy all the files and folders inside a directory on your local file system by: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

SRC_PATH is on container DEST_PATH is on localhost

Then do docker-compose down attach a volume to the same DEST_PATH and run Docker containers by using docker-compose up -d

Add volume by following in docker-compose.yml

volumes:
 - DEST_PATH:SRC_PATH
Nordle
  • 2,915
  • 3
  • 16
  • 34
  • There are other, better options above. – MrR Jun 16 '19 at 22:38
  • Indeed, there are better options above, and copying files around is not mounting them. In addition, the "volumes" definition given for the docker-compose option is the other way around: volumes: - HOST_PATH:CONTAINER_PATH – Guillaume S. Feb 19 '20 at 14:22