Introduction
When working with Docker containers, understanding how to properly manage data persistence is crucial. Docker provides three main approaches for mounting data into containers: Volumes, Bind Mounts, and tmpfs mounts. Each has distinct characteristics, use cases, and trade-offs.
This comprehensive guide explores all Docker mount types, their differences, practical examples, and best practices to help you choose the right approach for your specific needs.
What is Mounting in Docker?
Mounting in Docker refers to the process of making host filesystem directories or Docker-managed storage available inside containers. This allows containers to:
- Access host files and directories
- Persist data beyond container lifecycle
- Share data between multiple containers
- Exchange configuration files, logs, and application code
graph TD
A[Docker Mount Types] --> B[Volumes]
A --> C[Bind Mounts]
A --> D[tmpfs Mounts]
B --> B1[Docker-managed storage]
B --> B2[/var/lib/docker/volumes]
B --> B3[Production data persistence]
C --> C1[Direct host path mapping]
C --> C2[Development & code sync]
C --> C3[Configuration files]
D --> D1[In-memory storage]
D --> D2[Temporary data]
D --> D3[Sensitive information]
style B fill:#4ecdc4
style C fill:#feca57
style D fill:#ff6b6b
Three Types of Docker Mounts
Quick Comparison Table
Feature | Docker Volume | Bind Mount | tmpfs Mount |
---|---|---|---|
Management | Docker-managed | User-managed | Docker-managed |
Storage Location | /var/lib/docker/volumes | Anywhere on host | Memory (RAM) |
Portability | High | Low | N/A |
Performance | Good | Good | Excellent |
Persistence | Yes | Yes | No (volatile) |
Best For | Production data | Development | Temporary data |
Can Share Between Containers | Yes | Yes | No |
Backup/Migration | Easy | Manual | N/A |
Host Path Dependency | No | Yes | No |
1. Docker Volumes (Recommended for Production)
What Are Docker Volumes?
Docker Volumes are the preferred mechanism for persisting data. They are completely managed by Docker and stored in a dedicated location on the host.
graph LR
subgraph "Host System"
V[/var/lib/docker/volumes]
V1[my-vol/]
V2[db-data/]
V --> V1
V --> V2
end
subgraph "Container 1"
C1[/app/data]
end
subgraph "Container 2"
C2[/var/lib/mysql]
end
V1 --> C1
V2 --> C2
style V fill:#4ecdc4
style V1 fill:#a8e6cf
style V2 fill:#a8e6cf
Characteristics
- Managed by Docker: Docker handles all lifecycle operations
- Named or Anonymous: Can be explicitly named or auto-generated
- Shared Access: Multiple containers can mount the same volume
- Volume Drivers: Support for cloud storage, network storage, etc.
- Isolated from Host: No direct dependency on host directory structure
Basic Volume Commands
1# Create a named volume
2docker volume create my-volume
3
4# List all volumes
5docker volume ls
6
7# Inspect volume details
8docker volume inspect my-volume
9
10# Remove a volume
11docker volume rm my-volume
12
13# Remove all unused volumes
14docker volume prune
Using Volumes in Containers
1. Short Syntax (-v flag)
1# Named volume
2docker run -v my-volume:/app/data nginx:latest
3
4# Anonymous volume (auto-generated name)
5docker run -v /app/data nginx:latest
6
7# Multiple volumes
8docker run \
9 -v db-data:/var/lib/mysql \
10 -v config-data:/etc/mysql/conf.d \
11 mysql:8.0
2. Long Syntax (–mount flag) - Recommended
1docker run \
2 --mount type=volume,source=my-volume,target=/app/data \
3 nginx:latest
4
5# With additional options
6docker run \
7 --mount type=volume,source=my-volume,target=/app/data,readonly \
8 nginx:latest
Docker Compose Example
1version: '3.8'
2
3services:
4 app:
5 image: node:18
6 volumes:
7 # Named volume
8 - app-data:/app/data
9 - app-logs:/app/logs
10 environment:
11 - NODE_ENV=production
12
13 database:
14 image: postgres:15
15 volumes:
16 # Named volume for database persistence
17 - postgres-data:/var/lib/postgresql/data
18 # Named volume for initialization scripts
19 - postgres-init:/docker-entrypoint-initdb.d
20 environment:
21 - POSTGRES_PASSWORD=secret
22
23# Volume definitions
24volumes:
25 app-data:
26 driver: local
27 app-logs:
28 driver: local
29 postgres-data:
30 driver: local
31 postgres-init:
32 driver: local
Advanced Volume Features
1. Volume Drivers
1# Use NFS volume driver
2docker volume create \
3 --driver local \
4 --opt type=nfs \
5 --opt o=addr=192.168.1.100,rw \
6 --opt device=:/path/to/dir \
7 nfs-volume
8
9# Use AWS EFS driver (requires plugin)
10docker volume create \
11 --driver rexray/efs \
12 --name efs-volume
13
14# Azure File Storage
15docker volume create \
16 --driver azure_file \
17 --name azure-volume \
18 -o share=myshare
2. Volume with Specific Permissions
1# Create volume with specific user/group
2docker volume create \
3 --opt type=tmpfs \
4 --opt device=tmpfs \
5 --opt o=uid=1000,gid=1000 \
6 my-volume
3. Read-Only Volumes
1# Mount volume as read-only
2docker run \
3 -v my-volume:/app/data:ro \
4 nginx:latest
5
6# Or with --mount
7docker run \
8 --mount type=volume,source=my-volume,target=/app/data,readonly \
9 nginx:latest
Pros and Cons
Pros
- Easy to backup and migrate: Can be backed up using
docker cp
or volume plugins - Cross-platform: Works on Linux, Windows, and macOS
- Managed lifecycle: Docker handles creation and cleanup
- Better performance on Docker Desktop: Optimized for macOS and Windows
- Volume drivers: Can store volumes on remote hosts or cloud providers
- Safe sharing: Multiple containers can safely share volumes
- Pre-populated content: New volumes can be pre-filled from container content
Cons
- Less direct access: Cannot directly edit files from host without container
- Abstracted location: Files stored in Docker-managed directory
- Requires Docker commands: Need Docker CLI to manage volumes
Use Cases
Database Storage
- PostgreSQL, MySQL, MongoDB data directories
- Ensures data survives container recreation
Application State
- User uploads
- Application-generated files
- Cache directories
Shared Configuration
- Shared config between microservices
- Centralized logging
Backup and Restore Scenarios
1# Backup volume 2docker run --rm \ 3 -v my-volume:/data \ 4 -v $(pwd):/backup \ 5 busybox tar czf /backup/backup.tar.gz /data 6 7# Restore volume 8docker run --rm \ 9 -v my-volume:/data \ 10 -v $(pwd):/backup \ 11 busybox tar xzf /backup/backup.tar.gz -C /
2. Bind Mounts (Best for Development)
What Are Bind Mounts?
Bind Mounts directly map a host directory or file to a container path. The host path must exist before creating the container.
graph LR
subgraph "Host System"
H1[/home/user/project]
H2[/home/user/logs]
H3[/etc/config]
end
subgraph "Container"
C1[/app]
C2[/app/logs]
C3[/etc/app/config]
end
H1 -->|Bind Mount| C1
H2 -->|Bind Mount| C2
H3 -->|Bind Mount| C3
style H1 fill:#feca57
style H2 fill:#feca57
style H3 fill:#feca57
Characteristics
- Direct Host Mapping: Container accesses files directly from host
- Path Dependency: Requires specific host directory structure
- Two-Way Sync: Changes reflect immediately in both directions
- No Docker Management: Docker doesn’t manage the host directory
- Full Host Access: Container has same permissions as mounted directory
Using Bind Mounts
1. Short Syntax (-v flag)
1# Basic bind mount
2docker run -v /host/path:/container/path nginx:latest
3
4# With read-only flag
5docker run -v /host/path:/container/path:ro nginx:latest
6
7# Current directory
8docker run -v $(pwd):/app node:18
9
10# Multiple bind mounts
11docker run \
12 -v $(pwd)/src:/app/src \
13 -v $(pwd)/logs:/app/logs \
14 -v $(pwd)/config.json:/app/config.json \
15 node:18
2. Long Syntax (–mount flag) - More Explicit
1# Basic bind mount
2docker run \
3 --mount type=bind,source=/host/path,target=/container/path \
4 nginx:latest
5
6# Read-only bind mount
7docker run \
8 --mount type=bind,source=/host/path,target=/container/path,readonly \
9 nginx:latest
10
11# With consistency options (macOS/Windows)
12docker run \
13 --mount type=bind,source=$(pwd),target=/app,consistency=cached \
14 node:18
Docker Compose Example
1version: '3.8'
2
3services:
4 web:
5 image: nginx:latest
6 ports:
7 - "8080:80"
8 volumes:
9 # Bind mount for development - hot reload
10 - ./src:/usr/share/nginx/html
11 - ./nginx.conf:/etc/nginx/nginx.conf:ro
12 - ./logs:/var/log/nginx
13 environment:
14 - ENVIRONMENT=development
15
16 app:
17 image: node:18
18 working_dir: /app
19 volumes:
20 # Sync entire project directory
21 - ./app:/app
22 # But exclude node_modules (use anonymous volume)
23 - /app/node_modules
24 # Mount specific config file
25 - ./app/config/development.json:/app/config/config.json
26 command: npm run dev
27 ports:
28 - "3000:3000"
Development Workflow Example
1# Complete development setup with hot reload
2
3# 1. Project structure
4# project/
5# ├── src/
6# │ ├── index.js
7# │ └── utils/
8# ├── tests/
9# ├── config/
10# └── docker-compose.yml
11
12# 2. Docker Compose configuration
13version: '3.8'
14
15services:
16 dev:
17 image: node:18
18 working_dir: /app
19 volumes:
20 # Mount source code for hot reload
21 - ./src:/app/src
22 - ./tests:/app/tests
23 - ./package.json:/app/package.json
24 # Use anonymous volume for node_modules
25 - /app/node_modules
26 command: npm run dev
27 ports:
28 - "3000:3000"
29 environment:
30 - NODE_ENV=development
31 - CHOKIDAR_USEPOLLING=true # For file watching
32
33# 3. Start development
34docker-compose up
35
36# Now changes to ./src/* are immediately reflected in container!
Advanced Bind Mount Features
1. Consistency Modes (macOS/Windows)
1# Cached: prioritize container performance
2docker run \
3 --mount type=bind,source=$(pwd),target=/app,consistency=cached \
4 node:18
5
6# Delegated: prioritize host performance
7docker run \
8 --mount type=bind,source=$(pwd),target=/app,consistency=delegated \
9 node:18
10
11# Consistent: perfect sync (default, slowest)
12docker run \
13 --mount type=bind,source=$(pwd),target=/app,consistency=consistent \
14 node:18
2. Bind Propagation
1# Shared propagation (default)
2docker run \
3 --mount type=bind,source=/host/path,target=/container/path,bind-propagation=shared \
4 ubuntu
5
6# Private propagation
7docker run \
8 --mount type=bind,source=/host/path,target=/container/path,bind-propagation=private \
9 ubuntu
10
11# Slave propagation
12docker run \
13 --mount type=bind,source=/host/path,target=/container/path,bind-propagation=slave \
14 ubuntu
3. SELinux Labels (Linux)
1# With SELinux label
2docker run -v /host/path:/container/path:z nginx:latest # Private label
3docker run -v /host/path:/container/path:Z nginx:latest # Shared label
Pros and Cons
Pros
- Direct file editing: Edit files on host with any editor
- Real-time sync: Changes immediately reflected in container
- No Docker commands needed: Use normal file operations
- Perfect for development: Hot reload, live debugging
- Share configuration: Easy to share config files
- Specific file mounting: Can mount individual files
Cons
- Host path dependency: Requires specific directory structure
- Less portable: Paths differ across environments
- Security concerns: Container can modify host files
- Permission issues: User ID mismatches can cause problems
- Performance on macOS/Windows: Slower than volumes
- Backup complexity: Must backup host directory separately
Use Cases
Development Environment
1# Hot reload for web development 2docker run \ 3 -v $(pwd)/src:/app/src \ 4 -v $(pwd)/public:/app/public \ 5 -p 3000:3000 \ 6 node:18 npm run dev
Configuration Files
1# Mount specific config files 2docker run \ 3 -v /etc/myapp/config.yml:/app/config.yml:ro \ 4 myapp:latest
Log Collection
1# Collect logs to host directory 2docker run \ 3 -v $(pwd)/logs:/var/log/app \ 4 myapp:latest
Testing and CI/CD
1# Run tests on current codebase 2docker run \ 3 -v $(pwd):/app \ 4 -w /app \ 5 node:18 npm test
Database Configuration
1# Custom PostgreSQL config 2docker run \ 3 -v $(pwd)/postgresql.conf:/etc/postgresql/postgresql.conf:ro \ 4 -v postgres-data:/var/lib/postgresql/data \ 5 postgres:15
3. tmpfs Mounts (For Temporary Data)
What Are tmpfs Mounts?
tmpfs mounts store data in the host’s memory (RAM). Data exists only while the container runs and is never written to disk.
graph TD
subgraph "Host System"
RAM[System RAM]
RAM --> TM1[tmpfs Mount 1]
RAM --> TM2[tmpfs Mount 2]
end
subgraph "Container"
C1[/tmp]
C2[/run]
end
TM1 -->|In-Memory| C1
TM2 -->|In-Memory| C2
N[Container Stops] -->|Data Lost| X[❌ Data Deleted]
style RAM fill:#ff6b6b
style TM1 fill:#ffb3ba
style TM2 fill:#ffb3ba
style X fill:#ff6b6b
Characteristics
- Memory Storage: Data stored in RAM, not disk
- Volatile: Data lost when container stops
- Fast Performance: No disk I/O overhead
- Secure: No data leakage to disk
- Linux Only: Not available on Windows containers
- Size Limited: Limited by available memory
Using tmpfs Mounts
1. Short Syntax (–tmpfs flag)
1# Basic tmpfs mount
2docker run --tmpfs /app/tmp nginx:latest
3
4# With size limit (100MB)
5docker run --tmpfs /app/tmp:size=100m nginx:latest
6
7# Multiple tmpfs mounts
8docker run \
9 --tmpfs /tmp \
10 --tmpfs /run:size=64m \
11 ubuntu:latest
2. Long Syntax (–mount flag)
1# Basic tmpfs
2docker run \
3 --mount type=tmpfs,target=/app/tmp \
4 nginx:latest
5
6# With options
7docker run \
8 --mount type=tmpfs,target=/app/tmp,tmpfs-size=100m,tmpfs-mode=1770 \
9 nginx:latest
Docker Compose Example
1version: '3.8'
2
3services:
4 app:
5 image: myapp:latest
6 tmpfs:
7 # Simple tmpfs mount
8 - /tmp
9 - /run
10
11 web:
12 image: nginx:latest
13 volumes:
14 # Using long syntax for more control
15 - type: tmpfs
16 target: /app/cache
17 tmpfs:
18 size: 100m
19 mode: 1770
20 - type: tmpfs
21 target: /tmp
22 tmpfs:
23 size: 50m
24
25 database:
26 image: postgres:15
27 volumes:
28 # Persistent data on volume
29 - db-data:/var/lib/postgresql/data
30 tmpfs:
31 # Temporary files in memory
32 - /tmp
33 - /run/postgresql:size=100m
34
35volumes:
36 db-data:
Advanced tmpfs Options
1# With all options
2docker run \
3 --mount type=tmpfs,target=/app/tmp,\
4tmpfs-size=100m,\
5tmpfs-mode=1777,\
6tmpfs-uid=1000,\
7tmpfs-gid=1000 \
8 myapp:latest
9
10# Options explained:
11# - tmpfs-size: Maximum size (100MB)
12# - tmpfs-mode: Unix permissions (1777 = sticky bit + rwx)
13# - tmpfs-uid: Owner user ID
14# - tmpfs-gid: Owner group ID
Pros and Cons
Pros
- Excellent performance: In-memory operations are extremely fast
- Secure: Sensitive data never written to disk
- No disk wear: Reduces SSD/HDD wear for temporary files
- Automatic cleanup: Data automatically removed when container stops
- No persistence overhead: No need to manage cleanup
Cons
- Volatile storage: All data lost when container stops
- Linux only: Not supported on Windows containers
- Memory limited: Uses system RAM (limited resource)
- Cannot share: Cannot share tmpfs between containers
- No backup possible: Data cannot be backed up
- Memory pressure: Can affect system performance if overused
Use Cases
Temporary Processing
1# Image processing with temporary files 2docker run \ 3 --tmpfs /tmp:size=1g \ 4 -v $(pwd)/input:/input:ro \ 5 -v $(pwd)/output:/output \ 6 image-processor
Sensitive Data
1# Handle sensitive credentials in memory 2docker run \ 3 --tmpfs /secrets:size=10m,mode=0700 \ 4 -e SECRET_FILE=/secrets/token \ 5 myapp:latest
Build Cache
1# Fast build with in-memory cache 2docker run \ 3 --tmpfs /tmp:size=2g \ 4 -v $(pwd):/app \ 5 -w /app \ 6 node:18 npm run build
Session Storage
1# Web server with in-memory sessions 2docker run \ 3 --tmpfs /var/lib/nginx/sessions:size=200m \ 4 nginx:latest
Testing Environment
1# Fast test execution with tmpfs 2docker run \ 3 --tmpfs /tmp:size=500m \ 4 --tmpfs /var/tmp:size=500m \ 5 -v $(pwd):/app \ 6 test-runner npm test
Complete Comparison Matrix
Feature Comparison
Feature | Volume | Bind Mount | tmpfs |
---|---|---|---|
Storage Location | /var/lib/docker/volumes | Custom host path | Memory (RAM) |
Managed By | Docker | Host/User | Docker |
Persistence | Yes (survives container) | Yes (survives container) | No (volatile) |
Portability | High | Low | Medium |
Performance (Linux) | Good | Good | Excellent |
Performance (macOS/Win) | Excellent | Moderate | Excellent |
Host Access | Indirect | Direct | None |
Sharing Between Containers | Yes | Yes | No |
Backup/Restore | Easy | Manual | Not applicable |
Size Limit | Host disk | Host disk | RAM |
Platform Support | All | All | Linux only |
SELinux/AppArmor | Handled by Docker | Manual configuration | Handled by Docker |
Initial Content | Can inherit | Uses existing | Empty |
Performance Comparison
graph LR
A[Performance by Platform] --> B[Linux Host]
A --> C[macOS/Windows]
B --> B1[Volume: ★★★★☆]
B --> B2[Bind Mount: ★★★★☆]
B --> B3[tmpfs: ★★★★★]
C --> C1[Volume: ★★★★★]
C --> C2[Bind Mount: ★★☆☆☆]
C --> C3[tmpfs: ★★★★★]
style B3 fill:#4ecdc4
style C1 fill:#4ecdc4
style C3 fill:#4ecdc4
Use Case Decision Tree
graph TD
A[Choose Mount Type] --> B{Need Persistence?}
B -->|No| C[tmpfs Mount]
B -->|Yes| D{Production or Development?}
D -->|Production| E[Docker Volume]
D -->|Development| F{Need Direct File Access?}
F -->|Yes| G[Bind Mount]
F -->|No| H[Docker Volume]
C --> I[Fast, Secure, Volatile]
E --> J[Managed, Portable, Backupable]
G --> K[Direct Access, Hot Reload]
H --> L[Isolated, Performance]
style E fill:#4ecdc4
style G fill:#feca57
style C fill:#ff6b6b
Best Practices
1. Volume Best Practices
1# Good: Named volumes with clear purpose
2services:
3 db:
4 image: postgres:15
5 volumes:
6 - postgres-data:/var/lib/postgresql/data
7 - postgres-backup:/backup
8
9volumes:
10 postgres-data:
11 name: myapp_postgres_data
12 postgres-backup:
13 name: myapp_postgres_backup
Best Practices:
- Use named volumes instead of anonymous volumes
- Add meaningful volume names
- Regular backup strategy
- Use volume drivers for production
- Document volume contents and purpose
2. Bind Mount Best Practices
1# Good: Clear separation of concerns
2services:
3 dev:
4 image: node:18
5 volumes:
6 # Source code - read/write
7 - ./src:/app/src
8 # Configuration - read-only
9 - ./config/development.json:/app/config/config.json:ro
10 # Logs - write only
11 - ./logs:/app/logs
12 # Exclude node_modules
13 - /app/node_modules
Best Practices:
- Use read-only (
:ro
) when possible - Exclude unnecessary directories
- Use absolute paths or
$(pwd)
- Document required host directory structure
- Be careful with permissions
- Avoid bind mounts in production
3. tmpfs Best Practices
1# Good: Size limits and appropriate use
2services:
3 app:
4 image: myapp:latest
5 tmpfs:
6 # Limit size to prevent memory exhaustion
7 - /tmp:size=100m,mode=1777
8 - /run:size=50m
9 deploy:
10 resources:
11 limits:
12 memory: 512M # Account for tmpfs in memory limit
Best Practices:
- Always set size limits
- Include tmpfs size in container memory limits
- Use for truly temporary data only
- Monitor memory usage
- Not suitable for large datasets
4. Security Best Practices
1# Read-only root filesystem with writable tmpfs
2docker run \
3 --read-only \
4 --tmpfs /tmp:size=100m \
5 --tmpfs /run:size=50m \
6 myapp:latest
7
8# User namespaces to avoid root access
9docker run \
10 --userns-remap=default \
11 -v my-volume:/app/data \
12 myapp:latest
13
14# Specific user/group
15docker run \
16 --user 1000:1000 \
17 -v my-volume:/app/data \
18 myapp:latest
5. Production Recommendations
1# Production setup example
2version: '3.8'
3
4services:
5 app:
6 image: myapp:1.2.3
7 volumes:
8 # Named volumes for persistent data
9 - app-data:/var/lib/app
10 - app-logs:/var/log/app
11 # Read-only bind mounts for config
12 - ./config/production.yml:/etc/app/config.yml:ro
13 tmpfs:
14 # In-memory temporary files
15 - /tmp:size=100m
16 deploy:
17 replicas: 3
18 resources:
19 limits:
20 memory: 512M
21
22 db:
23 image: postgres:15
24 volumes:
25 # Volume with backup strategy
26 - postgres-data:/var/lib/postgresql/data
27 environment:
28 - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
29 secrets:
30 - db_password
31 tmpfs:
32 - /tmp:size=50m
33
34volumes:
35 app-data:
36 driver: local
37 driver_opts:
38 type: none
39 o: bind
40 device: /mnt/app-data
41 app-logs:
42 driver: local
43 postgres-data:
44 driver: local
45 driver_opts:
46 type: none
47 o: bind
48 device: /mnt/postgres-data
49
50secrets:
51 db_password:
52 external: true
Real-World Examples
Example 1: Full-Stack Application
1version: '3.8'
2
3services:
4 # Frontend (Development)
5 frontend:
6 image: node:18
7 working_dir: /app
8 command: npm run dev
9 ports:
10 - "3000:3000"
11 volumes:
12 # Bind mounts for hot reload
13 - ./frontend/src:/app/src
14 - ./frontend/public:/app/public
15 - ./frontend/package.json:/app/package.json
16 # Anonymous volume for node_modules
17 - /app/node_modules
18 tmpfs:
19 # Fast build cache
20 - /app/.cache:size=500m
21 environment:
22 - NODE_ENV=development
23 - CHOKIDAR_USEPOLLING=true
24
25 # Backend (Production-like)
26 backend:
27 image: mybackend:latest
28 ports:
29 - "8080:8080"
30 volumes:
31 # Volume for uploaded files
32 - backend-uploads:/app/uploads
33 # Volume for generated reports
34 - backend-reports:/app/reports
35 # Read-only config
36 - ./backend/config.yml:/app/config.yml:ro
37 tmpfs:
38 # Session storage in memory
39 - /tmp/sessions:size=200m
40 environment:
41 - NODE_ENV=production
42 - LOG_LEVEL=info
43
44 # Database (Production)
45 database:
46 image: postgres:15
47 volumes:
48 # Persistent data storage
49 - postgres-data:/var/lib/postgresql/data
50 # Initialization scripts
51 - ./database/init:/docker-entrypoint-initdb.d:ro
52 tmpfs:
53 # PostgreSQL runtime files
54 - /run/postgresql:size=100m
55 environment:
56 - POSTGRES_PASSWORD=secret
57 - POSTGRES_DB=myapp
58
59 # Cache (Production)
60 redis:
61 image: redis:7-alpine
62 volumes:
63 # Persistent cache data
64 - redis-data:/data
65 # Custom configuration
66 - ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
67 command: redis-server /usr/local/etc/redis/redis.conf
68
69 # Nginx (Production)
70 nginx:
71 image: nginx:latest
72 ports:
73 - "80:80"
74 - "443:443"
75 volumes:
76 # Configuration
77 - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
78 - ./nginx/conf.d:/etc/nginx/conf.d:ro
79 # SSL certificates
80 - ./nginx/ssl:/etc/nginx/ssl:ro
81 # Static files
82 - frontend-build:/usr/share/nginx/html:ro
83 # Logs
84 - nginx-logs:/var/log/nginx
85 tmpfs:
86 # Client body temp files
87 - /var/cache/nginx:size=500m
88 depends_on:
89 - frontend
90 - backend
91
92volumes:
93 backend-uploads:
94 backend-reports:
95 postgres-data:
96 redis-data:
97 frontend-build:
98 nginx-logs:
Example 2: Microservices with Shared Volumes
1version: '3.8'
2
3services:
4 # Service 1: File Processor
5 processor:
6 image: file-processor:latest
7 volumes:
8 # Shared volume for file exchange
9 - shared-files:/app/files
10 # Processed files output
11 - processed-files:/app/output
12 tmpfs:
13 # Fast processing workspace
14 - /tmp/workspace:size=1g
15
16 # Service 2: File Analyzer
17 analyzer:
18 image: file-analyzer:latest
19 volumes:
20 # Read from processed files
21 - processed-files:/app/input:ro
22 # Write analysis results
23 - analysis-results:/app/results
24 tmpfs:
25 # Analysis cache
26 - /tmp/cache:size=500m
27
28 # Service 3: API Server
29 api:
30 image: api-server:latest
31 ports:
32 - "8080:8080"
33 volumes:
34 # Read analysis results
35 - analysis-results:/app/data:ro
36 # API logs
37 - api-logs:/var/log/api
38
39volumes:
40 shared-files:
41 processed-files:
42 analysis-results:
43 api-logs:
Example 3: Development Environment
1version: '3.8'
2
3services:
4 app:
5 build:
6 context: .
7 dockerfile: Dockerfile.dev
8 command: npm run dev
9 ports:
10 - "3000:3000"
11 volumes:
12 # Full source code mount
13 - .:/app
14 # Exclude specific directories
15 - /app/node_modules
16 - /app/.git
17 - /app/dist
18 tmpfs:
19 # Fast test cache
20 - /app/.cache:size=500m
21 # Jest cache
22 - /tmp/jest:size=200m
23 environment:
24 - NODE_ENV=development
25 - DEBUG=app:*
26
27 db:
28 image: postgres:15
29 ports:
30 - "5432:5432"
31 volumes:
32 # Development database
33 - dev-db-data:/var/lib/postgresql/data
34 # Seed data
35 - ./database/seed.sql:/docker-entrypoint-initdb.d/seed.sql:ro
36 environment:
37 - POSTGRES_PASSWORD=devpassword
38 - POSTGRES_DB=devdb
39
40volumes:
41 dev-db-data:
Troubleshooting
Common Issues and Solutions
1. Permission Denied Errors
1# Problem: Permission denied when writing to volume
2# Solution 1: Match user IDs
3docker run \
4 --user $(id -u):$(id -g) \
5 -v $(pwd):/app \
6 myapp:latest
7
8# Solution 2: Change ownership in Dockerfile
9FROM node:18
10RUN useradd -u 1000 -m appuser
11USER appuser
12
13# Solution 3: Use init container to fix permissions
14docker run \
15 --rm \
16 -v my-volume:/data \
17 alpine:latest \
18 chown -R 1000:1000 /data
2. Data Not Persisting
1# Problem: Data disappears after container restart
2# Wrong: Using container path only
3docker run myapp:latest # No volume specified!
4
5# Correct: Use named volume
6docker run -v my-data:/app/data myapp:latest
3. Bind Mount Not Syncing (macOS/Windows)
1# Problem: File changes not reflected
2# Solution: Use consistency options
3docker run \
4 --mount type=bind,source=$(pwd),target=/app,consistency=cached \
5 node:18
6
7# Or add polling for file watchers
8docker run \
9 -v $(pwd):/app \
10 -e CHOKIDAR_USEPOLLING=true \
11 node:18 npm run dev
4. Volume Taking Too Much Space
1# Check volume sizes
2docker system df -v
3
4# Remove unused volumes
5docker volume prune
6
7# Remove specific volume
8docker volume rm volume-name
9
10# Clean everything (careful!)
11docker system prune -a --volumes
5. Cannot Remove Volume
1# Problem: "volume is in use"
2# Solution 1: Find and stop containers using it
3docker ps -a --filter volume=my-volume
4
5# Solution 2: Force remove container and volume
6docker rm -f container-name
7docker volume rm my-volume
8
9# Solution 3: Remove all stopped containers first
10docker container prune
11docker volume rm my-volume
Migration Strategies
Migrating from Bind Mounts to Volumes
1# Step 1: Create volume
2docker volume create my-app-data
3
4# Step 2: Copy data from bind mount to volume
5docker run --rm \
6 -v /host/path:/source:ro \
7 -v my-app-data:/dest \
8 alpine:latest \
9 sh -c "cp -av /source/. /dest/"
10
11# Step 3: Update docker-compose.yml
12# Before:
13volumes:
14 - /host/path:/app/data
15
16# After:
17volumes:
18 - my-app-data:/app/data
Backing Up and Restoring Volumes
1# Backup volume to tar file
2docker run --rm \
3 -v my-volume:/source:ro \
4 -v $(pwd):/backup \
5 alpine:latest \
6 tar czf /backup/my-volume-backup-$(date +%Y%m%d).tar.gz -C /source .
7
8# Restore volume from tar file
9docker run --rm \
10 -v my-volume:/dest \
11 -v $(pwd):/backup:ro \
12 alpine:latest \
13 tar xzf /backup/my-volume-backup-20250101.tar.gz -C /dest
14
15# Or use dedicated backup tool
16docker run --rm \
17 -v my-volume:/volume \
18 -v $(pwd):/backup \
19 loomchild/volume-backup backup my-volume
Performance Optimization
1. Volume Performance Tips
1# Use local driver with optimal options
2volumes:
3 fast-volume:
4 driver: local
5 driver_opts:
6 type: none
7 o: bind
8 device: /mnt/fast-ssd/data # Use SSD storage
9
10# For databases, use direct mount
11volumes:
12 postgres-data:
13 driver: local
14 driver_opts:
15 type: none
16 o: bind
17 device: /mnt/database-ssd
2. Bind Mount Performance (macOS/Windows)
1# Use delegated consistency for better performance
2services:
3 app:
4 volumes:
5 - ./src:/app/src:delegated
6 - ./node_modules:/app/node_modules:cached
3. tmpfs for Performance-Critical Operations
1# Use tmpfs for build artifacts
2services:
3 builder:
4 volumes:
5 - ./src:/app/src:ro
6 tmpfs:
7 - /app/dist:size=2g
8 - /tmp:size=1g
Conclusion
Choosing the right Docker mount type is crucial for application performance, development workflow, and data management:
Quick Selection Guide
Use Docker Volumes when:
- Building production applications
- Need data persistence across container lifecycles
- Want Docker-managed storage
- Require easy backup and migration
- Need to share data between multiple containers
Use Bind Mounts when:
- Developing applications locally
- Need real-time file synchronization
- Want to edit files directly on host
- Mounting configuration files
- CI/CD pipelines needing access to build artifacts
Use tmpfs Mounts when:
- Handling sensitive temporary data
- Need maximum performance
- Working with temporary build artifacts
- Storing session data
- Processing files that don’t need persistence
Key Takeaways
- Volumes are preferred for production - Docker-managed, portable, and easy to backup
- Bind mounts excel in development - Direct access, hot reload, familiar workflow
- tmpfs provides security and speed - Perfect for temporary, sensitive data
- Mix approaches when appropriate - Different needs require different solutions
- Consider platform differences - Performance varies between Linux, macOS, and Windows
Understanding these mount types and their trade-offs enables you to build more efficient, maintainable, and production-ready containerized applications.