====== Docker - Containers - Share data between docker containers ======
Docker Volumes can be created and attached in the same command that creates a container, or they can be created independent of any containers and then attached later.
There are a number of different ways to share data between containers.
----
===== Creating an Independent Volume =====
Docker's 1.9 onwards allows a volume to be created without it relating to any particular container:
docker volume create --name DataVolume1
The name is displayed, indicating that the command was successful.
Output
DataVolume1
To make use of the volume, we'll create a new container from the Ubuntu image, using the **--rm** flag to automatically delete it when we exit. We'll use **-v** to mount the new volume. -v requires the name of the volume, a colon, then the absolute path to where the volume should appear inside the container. If the directories in the path don't exist as part of the image, they'll be created when the command runs. If they do exist, the mounted volume will hide the existing content.
docker run -ti --rm -v DataVolume1:/datavolume1 ubuntu
Write some data to the volume:
echo "Example1" > /datavolume1/Example1.txt
Because we used the **--rm** flag, the container will be automatically deleted when we exit. The volume, however, will still be accessible.
exit
Verify the volume is present on the system with docker volume inspect:
docker volume inspect DataVolume1
result:
Output
[
{
"Name": "DataVolume1",
"Driver": "local",
"Mountpoint": "/var/lib/docker/volumes/datavolume1/_data",
"Labels": null,
"Scope": "local"
}
]
**WARNING**: The data on the host can also be accessed at the path listed as the Mountpoint.
Avoid altering this as it can cause data corruption if applications or containers are unaware of changes.
----
Start a new container and attach DataVolume1:
docker run --rm -ti -v DataVolume1:/datavolume1 ubuntu
cat /datavolume1/Example1.txt
displays:
Output
Example1
----
Exit the container.
exit
In this example, we created a volume, attached it to a container, and verified its persistence.
----
===== Creating a Volume that Persists when the Container is Removed =====
Create a volume at the same time as the container, delete the container, then attach the volume to a new container.
docker run -ti --name=Container2 -v DataVolume2:/datavolume2 ubuntu
Write some data to the volume:
echo "Example2" > /datavolume2/Example2.txt
cat /datavolume2/Example2.txt
Output:
Example2
----
Exit the container:
exit
----
Restart it - the volume will mount automatically.
docker start -ai Container2
----
Verify that the volume has indeed mounted and our data is still in place:
cat /datavolume2/Example2.txt
Output
Example2
Exit and clean up.
exit
----
Docker won't allow a volume to be removed if it's referenced by a container. Try anyway:
docker volume rm DataVolume2
The message tells us that the volume is still in use and supplies the long version of the container ID:
Output:
Error response from daemon: Unable to remove volume,
volume still in use: remove DataVolume2: volume is in use -
[719f98391ecf1d6f0f053ffea1bbd84cd2dc9cf6d31d5a4f348c60d98392804c]
----
Use the ID to remove the container:
docker rm 719f98391ecf1d6f0f053ffea1bbd84cd2dc9cf6d31d5a4f348c60d98392804c
Output:
719f98391ecf1d6f0f053ffea1bbd84cd2dc9cf6d31d5a4f348c60d98392804c
Removing the container won't affect the volume. Check it's still present on the system:
docker volume ls
Output:
DRIVER VOLUME NAME
local DataVolume2
----
Remove the volume:
docker volume rm DataVolume2
In this example, we created an empty data volume at the same time that we created a container.
----
===== Creating a Volume from an Existing Directory with Data =====
If a volume is created at the same time a container is created and the path to a directory is provided that contains data in the base image, that data will be copied into the volume.
Create a container and add the data volume at /var, a directory which contains data in the base image:
docker run -ti --rm -v DataVolume3:/var ubuntu
All the content from the base image's /var directory is copied into the volume, and we can mount that volume in a new container. This time, rather than relying on the base image's default bash command, we'll issue our own ls command, which will show the contents of the volume without entering the shell:
docker run --rm -v DataVolume3:/datavolume3 ubuntu ls DataVolume3
DataVolume3 has a copy of the contents of the base image's /var directory:
Output:
backups
cache
lib
local
lock
log
mail
opt
run
spool
tmp
It's unlikely that we would want to mount /var/ in this way, but this can be helpful if we've crafted our own image and want an easy way to preserve data.
----
===== Sharing Data between Multiple Docker Containers =====
To have multiple containers attached to the same data volume.
**WARNING**: Attaching multiple containers to the same data volume is relatively straightforward, but there's one critical caveat: at this time, Docker doesn't handle file locking.
If you need multiple containers writing to the volume, the applications running in those containers must be designed to write to shared data stores in order to prevent data corruption.
----
==== Create Container4 and DataVolume4 ====
Use **docker run** to create a new container named Container4 with a data volume attached:
docker run -ti --name=Container4 -v DataVolume4:/datavolume4 ubuntu
Create a file and add some text:
echo "This file is shared between containers" > /datavolume4/Example4.txt
Exit the container.
exit
This returns us to the host command prompt, where we'll make a new container that mounts the data volume from Container4.
----
==== Create Container5 and Mount Volumes from Container4 ====
docker run -ti --name=Container5 --volumes-from Container4 ubuntu
cat /datavolume4/Example4.txt
Output:
This file is shared between containers.
Append some text from the second container:
echo "Both containers can write to DataVolume4" >> /datavolume4/Example4.txt
Exit the container:
exit
Check that the data is still present to Container4.
----
==== View Changes Made in Container5 ====
Check for the changes that were written to the data volume by Container5 by restarting Container4:
docker start -ai Container4
cat /datavolume4/Example4.txt
cat /DataVolume4/Example4.txt
Output:
This file is shared between containers.
Both containers can write to DataVolume4
Now that we've verified that both containers were able to read and write from the data volume, we'll exit the container:
exit
Remember that Docker doesn't handle any file locking, so applications must account for the file locking themselves.
It is possible to mount a Docker volume as read-only to ensure that data corruption won't happen by accident when a container requires read-only access by adding **:ro**.
----
==== Start Container 6 and Mount the Volume Read-Only ====
Once a volume has been mounted in a container, rather than unmounting it like we would with a typical Linux file system, we instead create a new container mounted the way we want it and, if needed, remove the previous container.
To make the volume read-only, we append **:ro** to the end of the container name:
docker run -ti --name=Container6 --volumes-from Container4:ro ubuntu
Check the read-only status by trying to remove our example file:
rm /datavolume4/Example4.txt
Output:
rm: cannot remove '/datavolume4/Example4.txt': Read-only file system
Exit the container and clean up our test containers and volumes:
exit
Clean up our containers and volume:
docker rm Container4 Container5 Container6
docker volume rm DataVolume4
In this example, we've shown how to share data between two containers using a data volume and how to mount a data volume as read-only.