====== 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.