Skip to content

Volumes

What are Docker Volumes?

Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. Unlike bind mounts, volumes are completely managed by Docker.

Why Use Volumes?

  • Data persistence - Data survives container removal
  • Sharing data - Multiple containers can share the same volume
  • Performance - Better performance than bind mounts on Mac/Windows
  • Backups - Easier to backup and migrate
  • Remote storage - Can be hosted on remote systems or cloud

Types of Mounts

Managed by Docker, stored in Docker's storage directory.

# Create volume
docker volume create my-data

# Use volume
docker run -v my-data:/app/data nginx

Bind Mounts

Mount a file or directory from host into container.

# Mount current directory
docker run -v $(pwd):/app nginx

# Mount specific file
docker run -v /path/on/host:/path/in/container nginx

tmpfs Mounts

Stored in host memory only, not persisted.

# Use tmpfs
docker run --tmpfs /app/cache nginx

Comparison

Feature Volumes Bind Mounts tmpfs
Managed by Docker Yes No No
Location Docker directory Anywhere on host RAM
Performance Good Varies Excellent
Persist after container removed Yes Yes No
Can share between containers Yes Yes No
Backup/restore Easy Manual Not possible

Working with Volumes

Create Volume

# Create volume
docker volume create my-volume

# Create with driver options
docker volume create --driver local \
  --opt type=nfs \
  --opt o=addr=192.168.1.1,rw \
  --opt device=:/path/to/dir \
  my-nfs-volume

List Volumes

# List all volumes
docker volume ls

# Filter by name
docker volume ls --filter name=my-volume

# Filter dangling volumes
docker volume ls --filter dangling=true

Inspect Volume

# View volume details
docker volume inspect my-volume

# View mount point
docker volume inspect -f '{{.Mountpoint}}' my-volume

Remove Volume

# Remove specific volume
docker volume rm my-volume

# Remove all unused volumes
docker volume prune

# Remove with force
docker volume rm -f my-volume

Using Volumes with Containers

Named Volume

# Create and use in one command
docker run -v my-data:/app/data nginx

# Using --mount (more explicit)
docker run --mount source=my-data,target=/app/data nginx

Anonymous Volume

Created automatically, harder to reference:

# Docker creates random volume name
docker run -v /app/data nginx

Read-Only Volume

# Mount as read-only
docker run -v my-data:/app/data:ro nginx

# Using --mount
docker run --mount source=my-data,target=/app/data,readonly nginx

Bind Mount

# Mount host directory
docker run -v $(pwd)/data:/app/data nginx

# Using --mount
docker run --mount type=bind,source=$(pwd)/data,target=/app/data nginx

Volume Examples

Persist Database Data

# Create volume
docker volume create postgres-data

# Run PostgreSQL with volume
docker run -d \
  --name postgres \
  -v postgres-data:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret \
  postgres:13

# Data persists even after container removal
docker rm -f postgres
docker run -d --name postgres -v postgres-data:/var/lib/postgresql/data postgres:13

Share Data Between Containers

# Create shared volume
docker volume create shared-data

# Writer container
docker run -d --name writer \
  -v shared-data:/data \
  alpine sh -c "while true; do date >> /data/log.txt; sleep 1; done"

# Reader container
docker run -d --name reader \
  -v shared-data:/data:ro \
  alpine tail -f /data/log.txt

Development with Bind Mounts

# Mount source code for live reloading
docker run -d \
  --name dev-app \
  -v $(pwd)/src:/app/src \
  -p 3000:3000 \
  node:16 \
  npm run dev

Backup Volume

# Backup volume to tar file
docker run --rm \
  -v my-data:/data \
  -v $(pwd):/backup \
  alpine \
  tar czf /backup/data-backup.tar.gz /data

# Restore from backup
docker run --rm \
  -v my-data:/data \
  -v $(pwd):/backup \
  alpine \
  tar xzf /backup/data-backup.tar.gz -C /

Docker Compose with Volumes

Named Volumes

version: '3.8'

services:
  db:
    image: postgres
    volumes:
      - postgres-data:/var/lib/postgresql/data

  app:
    build: .
    volumes:
      - app-data:/app/data

volumes:
  postgres-data:
  app-data:

Bind Mounts

version: '3.8'

services:
  app:
    build: .
    volumes:
      - ./src:/app/src        # Bind mount
      - ./config:/app/config  # Bind mount
      - node_modules:/app/node_modules  # Named volume

volumes:
  node_modules:

Volume Configuration

volumes:
  postgres-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /path/on/host

  nfs-data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=192.168.1.1,rw
      device: ":/path/to/dir"

External Volumes

volumes:
  existing-volume:
    external: true  # Use existing volume

Volume Use Cases

Development

services:
  app:
    volumes:
      # Live reload - changes reflect immediately
      - ./src:/app/src

      # Preserve node_modules from image
      - /app/node_modules

      # Share config
      - ./config:/app/config:ro

Production Database

services:
  postgres:
    image: postgres:13
    volumes:
      # Persist data
      - postgres-data:/var/lib/postgresql/data

      # Custom config
      - ./postgres.conf:/etc/postgresql/postgresql.conf:ro

      # Init scripts
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro

volumes:
  postgres-data:
    driver: local

Logs and Monitoring

services:
  app:
    volumes:
      # Application logs
      - ./logs:/app/logs

  nginx:
    volumes:
      # Web server logs
      - ./logs/nginx:/var/log/nginx

Volume Drivers

Docker supports various volume drivers:

Local

Default driver, stores data on host:

docker volume create --driver local my-volume

NFS

Network File System:

docker volume create --driver local \
  --opt type=nfs \
  --opt o=addr=192.168.1.1,rw \
  --opt device=:/path/to/dir \
  nfs-volume

Cloud Storage

Various plugins for AWS EBS, Azure File Storage, Google Cloud Storage, etc.

Volume Best Practices

For Development

  • Use bind mounts for source code (live reload)
  • Use named volumes for dependencies (node_modules)
  • Use bind mounts for config files
  • Mount as read-only when possible
services:
  app:
    volumes:
      - ./src:/app/src              # Source code
      - node_modules:/app/node_modules  # Dependencies
      - ./config.yml:/app/config.yml:ro # Config (read-only)

For Production

  • Use named volumes for databases
  • Use named volumes for uploaded files
  • Use read-only mounts for config
  • Regular backups of volumes
  • Use volume labels for organization
services:
  db:
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./postgres.conf:/etc/postgresql/postgresql.conf:ro

volumes:
  postgres-data:
    labels:
      app: myapp
      environment: production

General Best Practices

  • Name your volumes - Easier to manage than anonymous volumes
  • Document volume contents - What data is stored where
  • Regular backups - Automate volume backups
  • Clean up - Remove unused volumes regularly
  • Don't store secrets - Use Docker secrets or environment variables
  • Consider performance - Volumes perform better than bind mounts
  • Use specific paths - Avoid mounting entire root directories

Troubleshooting Volumes

View Volume Contents

# Run temporary container to inspect volume
docker run --rm -v my-data:/data alpine ls -la /data

Check Volume Size

# Get mountpoint
docker volume inspect -f '{{.Mountpoint}}' my-volume

# Check size (Linux)
sudo du -sh /var/lib/docker/volumes/my-volume/_data

Permission Issues

# Check ownership
docker run --rm -v my-data:/data alpine ls -ln /data

# Fix ownership (if needed)
docker run --rm -v my-data:/data alpine chown -R 1000:1000 /data

Find Containers Using Volume

# List containers using volume
docker ps -a --filter volume=my-volume

Skill++

Docker volumes can be stored on remote hosts or cloud providers, allowing containers to access shared data across multiple machines!


Prev -- Up -- Next