Docker Container Data Volumes: Persistence and Sharing
Understanding Docker Container Data Volumes
Docker Architecture Fundamentals
Docker encapsulates applications and their dependencies into images. However, this raises an important question: what happens to data when containers are removed? If all data resides within containers, deleting them would result in permanent data loss. This creates two critical requirements:
- Data persistence across container restarts and deletions
- Local storage capability for datbaases like MySQL
Docker provides a solution through data volumes, enabling both persistent storage and data sharing between containers.
In essence: Data volumes allow for persistent storage and synchronization capabilities, with the added benefit of data sharing between containers!
Implementing Data Volumes
Method 1: Command Line Volume Mounting
docker run -it -v host_directory:container_directory
# Testing volume mounting
admin@ubuntu:/home# docker run -it -v /home/test_volume:/home ubuntu /bin/bash
# After starting the container, verify the mount with:
# docker inspect container_id
Testing SynchronizationWhen a file is created on the host system, it should also appear in the container's mounted directory. To test this:
- Stop the container
- Modify a file on the host system
- Restart the container
- Verify that the changes are synchronized within the container
This approach allows local modifications to automatically propagate to the container, simplifying development workflows.
Practical Implementation: MySQL Containerization
Considerations for MySQL data persistence:
# Pull the MySQL image
admin@ubuntu:~# docker pull mysql:8.0
# Run the container with volume mounting
# MySQL requires password configuration during setup
# Official example: docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
# Our implementation:
-d background execution
-p port mapping
-V volume mounting
-e environment configuration
--name container name
admin@ubuntu:~# docker run -d -p 3307:3306 -v /home/mysql/config:/etc/mysql/conf.d -v /home/mysql/database:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=securepass --name mysql_server mysql:8.0
# Test connection using a database client like DBeaver or DataGrip
# Connect to port 3307 (mapped to container's 3306)
# Create a test database and verify the mapped directory
If the container is removed, the locally mounted volumes persist, ensuring data durability.
Named and Anonymous Volume Mounting
# Anonymous mounting
-v container_path!
-P (uppercase) # randomly assign ports
docker run -d -P --name web_server -v /etc/nginx nginx
# List all volumes
admin@ubuntu:~# docker volume ls
DRIVER VOLUME NAME
local 7a8b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z
# This demonstrates anonymous mounting - only the container path is specified
# Named mounting
admin@ubuntu:~# docker run -d -P --name nginx_app -v nginx_config:/etc/nginx nginx
f1e2d3c4b5a6c7d8e9f0a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z
admin@ubuntu:~# docker volume ls
DRIVER VOLUME NAME
local nginx_config
# Using -v volume_name:container_path
# Inspect the volume details
All Docker container volumes without specified host paths are stored in /var/lib/docker/volumes/xxxx/_data. Named volumes are preferred as they're easier to manage.
# Differentiating mounting types
-V container_path # Anonymous mounting
-V volume_name:container_path # Named mounting
-V /host_path:container_path # Specific path mounting!
# Extended options:
# -v container_path:ro/rw to set read-only or read-write permissions
ro readonly # Read-only
rw readwrite # Read-write
# Setting permissions restricts container access to mounted content
docker run -d -P --name nginx_web -v nginx_config:/etc/nginx:ro nginx
docker run -d -P --name nginx_web -v nginx_config:/etc/nginx:rw nginx
# With 'ro', only the host can modify the content; the container cannot!
Introduction to Dockerfile for Volume Management
A Dockerfile is a script file used to build Docker images. Each command in the script represents a layer in the image.
# Create a Dockerfile
admin@ubuntu:/home# mkdir custom-docker-image
admin@ubuntu:/home/custom-docker-image# mkdir dockerfile_volume
admin@ubuntu:/home/custom-docker-image# ls
dockerfile_volume
# File contents: INSTRUCTION(parameters)
admin@ubuntu:/home/custom-docker-image# vim dockerfile_volume
FROM ubuntu
VOLUME ["data_volume1","data_volume2"]
CMD echo "----build complete----"
CMD /bin/bash
# Each command represents a layer in the image
# Build and run the custom image
When a volume is defined in a Dockerfile, Docker automatically creates a synchronization directory with the host system.
# Check running containers
admin@ubuntu:/home/test# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7f8a9b0c7d6e custom_image "/bin/bash" 45 seconds ago Up 44 seconds custom_container
a1b2c3d4e5f6 nginx:1.24.0 "/docker-entrypoint.…" 25 minutes ago Up 25 minutes 0.0.0.0:32770->80/tcp, :::32770->80/tcp nginx_web
b3c4d5e6f7g8 nginx:1.24.0 "/docker-entrypoint.…" 27 minutes ago Up 27 minutes 0.0.0.0:32771->80/tcp, :::32771->80/tcp nginx_app
c5d6e7f8g9h0 mysql:8.0 "docker-entrypoint.s…" 40 minutes ago Up 40 minutes 33060/tcp, 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp mysql_server
admin@ubuntu:/home/test# docker inspect 7f8a9b0c7d6e
# Verify file synchronization
admin@ubuntu:~# cd /var/lib/docker/volumes/abc123def456ghi789jkl012mno345pqr678stu901vwx234yza567bcd890efg/_data
admin@ubuntu:/var/lib/docker/volumes/abc123def456ghi789jkl012mno345pqr678stu901vwx234yza567bcd890efg/_data# ls
synced_file.txt
This approach is commonly used when building custom images. If volumes aren't defined during image building, they can be manually mounted during container creation with -v volume_name:container_path.
Data Volume Containers for Shared Storage
Multiple database instances with synchronized data:
# Start multiple containers from a custom image
# Create a file in container01 and verify it appears in container02 and container03
# due to the shared volume mechanism
# Test: Remove container01 and check if container02 and container03 can still access the file
# The file remains accessible
Multiple MySQL instances with shared data:
admin@ubuntu:~# docker run -d -p 3307:3306 -v /home/mysql/config:/etc/mysql/conf.d -v /home/mysql/database:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=securepass --name mysql_primary mysql:8.0
admin@ubuntu:~# docker run -d -p 3308:3306 -v /home/mysql/config:/etc/mysql/conf.d -v /home/mysql/database:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=securepass --name mysql_secondary --volumes-from mysql_primary mysql:8.0
# This configuration enables data synchronization between containers
Key Takeaways:
The lifecycle of a data volume container continues as long as at least one container is using it. However, when data is persisted to the local filesystem, it remains even after all containers are removed.