Chapter 5: Volumes and Network Configuration
9/1/25About 7 min
Chapter 5: Volumes and Network Configuration
Learning Objectives
- Master the creation and use of Docker volumes
- Understand the difference between bind mounts and named volumes
- Learn to create and configure Docker networks
- Become proficient in inter-container network communication
Knowledge Points
The Need for Data Persistence
Containers are ephemeral by nature. When a container is deleted, the data inside it is also lost. To achieve data persistence, Docker provides several storage mechanisms:
Storage Type | Features | Use Case |
---|---|---|
Volumes | Docker-managed, good performance, shareable | Database files, application data |
Bind Mounts | Directly maps host directories, flexible | Configuration files, development environment |
tmpfs Mounts | Stored in memory, high performance | Temporary files, cache |
Docker Network Model
Docker uses the Container Network Model (CNM) architecture, which includes three core components:
- Sandbox: The container's network stack
- Endpoint: The container's network interface
- Network: A collection of endpoints that can communicate
Volume Management
Creating and Managing Volumes
# Create a volume
docker volume create my-volume
docker volume create --driver local web-data
docker volume create --name db-data
# View the list of volumes
docker volume ls
# View detailed volume information
docker volume inspect my-volume
# Example output:
[
{
"CreatedAt": "2023-01-15T10:30:45Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-volume/_data",
"Name": "my-volume",
"Options": {},
"Scope": "local"
}
]
# Remove a volume
docker volume rm my-volume
# Clean up unused volumes
docker volume prune
# Force remove all volumes (dangerous operation)
docker volume rm $(docker volume ls -q)
Using Volumes
# Use a named volume
docker run -d --name mysql-server \
-v db-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=password \
mysql:8.0
# Use an anonymous volume
docker run -d --name web-server \
-v /usr/share/nginx/html \
nginx:latest
# Mount multiple volumes
docker run -d --name app-server \
-v app-data:/opt/app/data \
-v log-data:/opt/app/logs \
-v config-data:/opt/app/config \
myapp:latest
# Read-only volume
docker run -d --name readonly-app \
-v config-data:/opt/app/config:ro \
myapp:latest
Advanced Volume Features
# Pre-populate a volume from a container
docker run -d --name data-container \
-v shared-data:/data \
busybox sh -c "echo 'Hello World' > /data/hello.txt"
# Use the same volume in other containers
docker run --rm -v shared-data:/data ubuntu cat /data/hello.txt
# Volume labels
docker volume create \
--label environment=production \
--label project=webapp \
prod-data
# View volumes with labels
docker volume ls --filter label=environment=production
# Create a volume with driver options
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/share \
nfs-volume
Volume Backup and Restore
# Backup a volume
docker run --rm \
-v db-data:/source:ro \
-v $(pwd):/backup \
ubuntu tar czf /backup/db-backup-$(date +%Y%m%d).tar.gz -C /source .
# Restore a volume
docker volume create db-data-restored
docker run --rm \
-v db-data-restored:/target \
-v $(pwd):/backup \
ubuntu tar xzf /backup/db-backup-20230115.tar.gz -C /target
# Volume migration
# Create a backup container
docker create --name backup-container \
-v source-volume:/source:ro \
ubuntu
# Copy data to the host
docker cp backup-container:/source/. ./backup/
# Restore to a new volume
docker run --rm \
-v target-volume:/target \
-v $(pwd)/backup:/backup \
ubuntu cp -r /backup/. /target/
Bind Mounts
Basic Bind Mounts
# Bind mount a host directory
docker run -d --name web-dev \
-p 8080:80 \
-v /home/user/html:/usr/share/nginx/html \
nginx:latest
# Use an absolute path
docker run -d --name app-dev \
-v /opt/myapp:/app \
-w /app \
python:3.9 python app.py
# Use a relative path (current directory)
docker run -d --name node-dev \
-p 3000:3000 \
-v $(pwd):/usr/src/app \
-w /usr/src/app \
node:16 npm start
# Read-only bind mount
docker run -d --name config-app \
-v /etc/myapp/config:/opt/app/config:ro \
myapp:latest
Advanced Bind Mount Options
# Use the mount syntax (recommended)
docker run -d --name advanced-app \
--mount type=bind,source=/host/path,target=/container/path,readonly \
myapp:latest
# Mount with permission control
docker run -d --name perm-app \
--mount type=bind,source=/host/data,target=/app/data,bind-propagation=shared \
myapp:latest
# Set SELinux labels (on systems with SELinux enabled)
docker run -d --name selinux-app \
-v /host/data:/app/data:Z \
myapp:latest
# Mount a single file
docker run -d --name single-file \
-v /host/config.json:/app/config.json:ro \
myapp:latest
Development Environment Practice
# Frontend development environment
mkdir -p ~/projects/frontend-app
cd ~/projects/frontend-app
# Create package.json
cat > package.json << 'EOF'
{
"name": "frontend-app",
"scripts": {
"dev": "webpack serve --mode development",
"build": "webpack --mode production"
}
}
EOF
# Run the development container
docker run -it --rm \
--name frontend-dev \
-p 3000:3000 \
-v $(pwd):/app \
-v /app/node_modules \
-w /app \
node:16 bash
# Install dependencies and start the development server inside the container
npm install
npm run dev
Docker Networking
Network Driver Types
Network Driver | Features | Use Case |
---|---|---|
bridge | Default network, single-host communication | Single-host multi-container applications |
host | Uses the host's network stack | High-performance network applications |
none | No network connection | Secure isolation scenarios |
overlay | Cross-host communication | Cluster environments |
macvlan | MAC address independent containers | Physical network integration |
Viewing Default Networks
# View all networks
docker network ls
# Example output:
NETWORK ID NAME DRIVER SCOPE
d8b6a3c7f4e2 bridge bridge local
f7a8b9c6d5e4 host host local
a1b2c3d4e5f6 none null local
# View detailed network information
docker network inspect bridge
# View container network information
docker inspect container-name | jq '.[0].NetworkSettings'
Creating Custom Networks
# Create a bridge network
docker network create my-network
docker network create --driver bridge app-network
# Create a network with a subnet
docker network create \
--driver bridge \
--subnet=172.20.0.0/16 \
--ip-range=172.20.240.0/20 \
--gateway=172.20.0.1 \
custom-network
# Create an overlay network (Swarm mode)
docker network create \
--driver overlay \
--subnet=10.1.0.0/24 \
--gateway=10.1.0.1 \
swarm-network
# View network details
docker network inspect my-network
Container Network Connections
# Specify a network at runtime
docker run -d --name web-server \
--network my-network \
nginx:latest
# Connect an existing container to a network
docker network connect my-network existing-container
# Disconnect from a network
docker network disconnect my-network container-name
# Assign an IP address to a container
docker run -d --name static-ip \
--network custom-network \
--ip 172.20.0.10 \
nginx:latest
# Set hostname and alias
docker run -d --name web-server \
--network my-network \
--hostname webserver \
--network-alias www \
nginx:latest
Inter-container Communication
Communication Between Containers on the Same Network
# Create an application network
docker network create app-net
# Start the database container
docker run -d --name mysql-db \
--network app-net \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=appdb \
mysql:8.0
# Start the application container
docker run -d --name web-app \
--network app-net \
-p 8080:80 \
-e DATABASE_HOST=mysql-db \
-e DATABASE_USER=root \
-e DATABASE_PASSWORD=password \
my-web-app:latest
# Test inter-container communication
docker exec web-app ping mysql-db
docker exec web-app nslookup mysql-db
Multi-network Containers
# Create frontend and backend networks
docker network create frontend-net
docker network create backend-net
# Start the database (only on the backend network)
docker network create backend-net
docker run -d --name database \
--network backend-net \
postgres:13
# Start the application server (connected to both networks)
docker run -d --name app-server \
--network backend-net \
my-app:latest
docker network connect frontend-net app-server
# Start the web server (only on the frontend network)
docker run -d --name web-server \
--network frontend-net \
-p 80:80 \
nginx:latest
Network Troubleshooting
# View container network configuration
docker exec container-name ip addr show
docker exec container-name ip route show
# Test network connectivity
docker exec container1 ping container2
docker exec container1 telnet container2 80
# View network connections
docker exec container-name netstat -tuln
docker exec container-name ss -tuln
# Packet capture analysis
docker exec container-name tcpdump -i eth0 -w /tmp/capture.pcap
Practical Cases
Complete LAMP Stack
# 1. Create a project network
docker network create lamp-network
# 2. Create volumes
docker volume create mysql-data
docker volume create web-data
# 3. Start MySQL database
docker run -d --name mysql \
--network lamp-network \
--restart unless-stopped \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=rootpassword \
-e MYSQL_DATABASE=webapp \
-e MYSQL_USER=webuser \
-e MYSQL_PASSWORD=webpassword \
mysql:8.0
# 4. Start Apache+PHP container
docker run -d --name apache-php \
--network lamp-network \
--restart unless-stopped \
-p 8080:80 \
-v web-data:/var/www/html \
php:8.1-apache
# 5. Install PHP MySQL extension
docker exec apache-php docker-php-ext-install mysqli pdo pdo_mysql
# 6. Commit the modified image
docker commit apache-php php:8.1-apache-mysql
# 7. Restart the Apache container
docker stop apache-php
docker rm apache-php
docker run -d --name apache-php \
--network lamp-network \
--restart unless-stopped \
-p 8080:80 \
-v web-data:/var/www/html \
php:8.1-apache-mysql
# 8. Create a test PHP file
docker exec apache-php bash -c 'cat > /var/www/html/test.php << "EOF"
<?php
$servername = "mysql";
$username = "webuser";
$password = "webpassword";
$dbname = "webapp";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully to MySQL database!<br>";
phpinfo();
?>
EOF'
# 9. Test the application
curl http://localhost:8080/test.php
Microservices Architecture Example
# Create a microservices network
docker network create microservices-net
# Service discovery and configuration center
docker run -d --name consul \
--network microservices-net \
-p 8500:8500 \
consul:latest
# API Gateway
docker run -d --name api-gateway \
--network microservices-net \
-p 80:8080 \
-e CONSUL_URL=http://consul:8500 \
my-api-gateway:latest
# User service
docker run -d --name user-service \
--network microservices-net \
-e CONSUL_URL=http://consul:8500 \
-e DB_HOST=postgres \
my-user-service:latest
# Order service
docker run -d --name order-service \
--network microservices-net \
-e CONSUL_URL=http://consul:8500 \
-e DB_HOST=postgres \
my-order-service:latest
# PostgreSQL database
docker run -d --name postgres \
--network microservices-net \
-v postgres-data:/var/lib/postgresql/data \
-e POSTGRES_DB=microservices \
-e POSTGRES_USER=admin \
-e POSTGRES_PASSWORD=password \
postgres:13
# Redis cache
docker run -d --name redis \
--network microservices-net \
redis:alpine
Development Environment Setup
# Create a development project
mkdir ~/dev-environment
cd ~/dev-environment
# Create development network and volumes
docker network create dev-network
docker volume create postgres-dev-data
docker volume create redis-dev-data
# Start the development database
docker run -d --name dev-postgres \
--network dev-network \
-p 5432:5432 \
-v postgres-dev-data:/var/lib/postgresql/data \
-e POSTGRES_DB=devdb \
-e POSTGRES_USER=developer \
-e POSTGRES_PASSWORD=devpass \
postgres:13
# Start Redis
docker run -d --name dev-redis \
--network dev-network \
-p 6379:6379 \
-v redis-dev-data:/data \
redis:alpine
# Start the development container (Node.js environment)
docker run -it --rm \
--name dev-environment \
--network dev-network \
-p 3000:3000 \
-v $(pwd):/workspace \
-w /workspace \
-e DATABASE_URL=postgresql://developer:devpass@dev-postgres:5432/devdb \
-e REDIS_URL=redis://dev-redis:6379 \
node:16 bash
# Initialize the project inside the development container
npm init -y
npm install express pg redis
# Create a simple application
cat > app.js << 'EOF'
const express = require('express');
const { Pool } = require('pg');
const redis = require('redis');
const app = express();
const port = 3000;
// Database connection
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
// Redis connection
const redisClient = redis.createClient({
url: process.env.REDIS_URL
});
app.get('/', async (req, res) => {
try {
const dbResult = await pool.query('SELECT NOW()');
await redisClient.set('last_visit', new Date().toISOString());
const lastVisit = await redisClient.get('last_visit');
res.json({
message: 'Development environment is working!',
database_time: dbResult.rows[0].now,
last_visit: lastVisit
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.listen(port, '0.0.0.0', () => {
console.log(`Dev server running on port ${port}`);
});
EOF
# Start the development server
node app.js
Network Security and Best Practices
Network Isolation Strategy
# Create networks for different environments
docker network create production-net
docker network create staging-net
docker network create development-net
# Database only on the backend network
docker network create backend-net
docker network create frontend-net
# Use a dedicated network for sensitive services
docker network create secure-net \
--internal # Disable external access
Firewall Rules
# Restrict container access to the external network
iptables -I DOCKER-USER -s 172.17.0.0/16 -d 8.8.8.8 -j DROP
# Allow a specific container to access an external API
iptables -I DOCKER-USER -s 172.20.0.10 -d api.example.com -p tcp --dport 443 -j ACCEPT
# Log network connections
iptables -I DOCKER-USER -j LOG --log-prefix "DOCKER-USER: "
Data and Network Best Practices
- Data Persistence: Use named volumes for important data instead of bind mounts.
- Network Isolation: Use different networks for different environments and services.
- Backup Strategy: Regularly back up important volumes.
- Security Configuration: Use internal networks for sensitive services and restrict external access.
- Monitoring and Alerting: Monitor network and storage usage.
Important Notes
- Volumes are not automatically deleted when a container is removed; they need to be cleaned up manually.
- File permission issues with bind mounts can cause applications to fail.
- Incorrect network configuration can prevent containers from communicating.
- Use the host network mode with caution in production environments.
Summary
By completing this chapter, you should have mastered:
- Data Persistence: Mastered storage mechanisms like volumes and bind mounts.
- Network Communication: Understood the Docker network model and inter-container communication methods.
- Practical Applications: Able to build complex multi-container application architectures.
- Security Configuration: Learned about network isolation and security best practices.
In the next chapter, we will learn about Docker Compose to achieve declarative orchestration and management of multi-container applications.