backend / docker / 09_volume_types.md

Volume Types in Dockerfile

3 interview angles 9 min read source

Volume Types in Dockerfile

Overview

Volumes in Docker provide persistent storage for containers. There are different ways to define and use volumes in Dockerfiles and Docker Compose, each serving different purposes for data persistence, sharing, and management.

Types of Volumes

1. Named Volumes

Definition: Docker-managed volumes with specific names, stored in Docker’s storage directory.

Characteristics:

  • Managed by Docker
  • Persistent across container restarts
  • Can be shared between containers
  • Backed up and managed easily

Dockerfile:

FROM postgres:13
VOLUME ["/var/lib/postgresql/data"]

docker-compose.yml:

version: '3.8'

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

volumes:
  postgres_data:  # Named volume

Command Line:

# Create named volume
docker volume create postgres_data

# Use in container
docker run -v postgres_data:/var/lib/postgresql/data postgres:13

# List volumes
docker volume ls

# Inspect volume
docker volume inspect postgres_data

# Remove volume
docker volume rm postgres_data

2. Bind Mounts

Definition: Mount a directory or file from the host into the container.

Characteristics:

  • Direct access to host filesystem
  • Changes reflect immediately
  • Good for development
  • Host path must exist

Dockerfile:

# Note: Bind mounts are typically not in Dockerfile
# They're specified at runtime
FROM nginx:alpine
# Bind mounts specified with -v flag

docker-compose.yml:

version: '3.8'

services:
  web:
    image: nginx:alpine
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro  # Bind mount
      - ./html:/usr/share/nginx/html:ro

Command Line:

# Bind mount
docker run -v /host/path:/container/path nginx:alpine

# Read-only bind mount
docker run -v /host/path:/container/path:ro nginx:alpine

# Absolute path
docker run -v /home/user/data:/app/data myapp

# Relative path (from current directory)
docker run -v ./data:/app/data myapp

3. Anonymous Volumes

Definition: Volumes created automatically without a name, managed by Docker.

Characteristics:

  • Created automatically
  • No explicit name
  • Removed when container is removed (unless –rm is not used)
  • Good for temporary data

Dockerfile:

FROM postgres:13
VOLUME ["/var/lib/postgresql/data"]  # Creates anonymous volume

docker-compose.yml:

version: '3.8'

services:
  db:
    image: postgres:13
    volumes:
      - /var/lib/postgresql/data  # Anonymous volume

Command Line:

# Anonymous volume
docker run -v /container/path postgres:13

# List anonymous volumes
docker volume ls
# Shows volumes with random names

4. tmpfs Mounts

Definition: In-memory storage that doesn’t persist after container stops.

Characteristics:

  • Stored in RAM
  • Very fast
  • Not persistent
  • Limited by available RAM
  • Good for temporary files

Dockerfile:

# tmpfs mounts are specified at runtime, not in Dockerfile
FROM nginx:alpine

docker-compose.yml:

version: '3.8'

services:
  web:
    image: nginx:alpine
    tmpfs:
      - /tmp
      - /var/cache/nginx

Command Line:

# tmpfs mount
docker run --tmpfs /tmp nginx:alpine

# tmpfs with options
docker run --tmpfs /tmp:rw,noexec,nosuid,size=100m nginx:alpine

VOLUME Instruction in Dockerfile

Basic Syntax

# Single volume
VOLUME ["/data"]

# Multiple volumes
VOLUME ["/data", "/logs", "/cache"]

# Volume with default data
VOLUME ["/var/lib/postgresql/data"]

How VOLUME Works

FROM postgres:13

# Creates anonymous volume
VOLUME ["/var/lib/postgresql/data"]

# Any writes to this path go to the volume
# Data persists even if container is removed

Important Notes:

  • VOLUME creates anonymous volumes
  • Data in volume persists after container removal
  • Can be overridden at runtime
  • Changes after VOLUME instruction don’t persist

VOLUME Best Practices

# Good: Define volumes for persistent data
FROM postgres:13
VOLUME ["/var/lib/postgresql/data"]

# Good: Multiple volumes
FROM myapp
VOLUME ["/data", "/logs", "/cache"]

# Avoid: Volume in wrong location
FROM myapp
COPY . /app
VOLUME ["/app"]  # Bad: Loses copied files

Volume Mounting Strategies

1. Development: Bind Mounts

version: '3.8'

services:
  web:
    build: .
    volumes:
      # Bind mount for live code reload
      - .:/app
      - /app/node_modules  # Anonymous volume to preserve node_modules
    environment:
      - NODE_ENV=development

Why:

  • Code changes reflect immediately
  • No rebuild needed
  • Fast development cycle

2. Production: Named Volumes

version: '3.8'

services:
  db:
    image: postgres:13
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=mydb

volumes:
  postgres_data:
    driver: local

Why:

  • Managed by Docker
  • Persistent and reliable
  • Easy backup/restore
  • Isolated from host

3. Configuration: Bind Mounts (Read-Only)

version: '3.8'

services:
  nginx:
    image: nginx:alpine
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro

Why:

  • Configuration managed on host
  • Read-only prevents accidental changes
  • Easy to update

4. Temporary Data: tmpfs

version: '3.8'

services:
  app:
    image: myapp
    tmpfs:
      - /tmp
      - /var/cache

Why:

  • Fast access (RAM)
  • Automatic cleanup
  • No disk usage

Volume Drivers

Local Driver (Default)

volumes:
  my_volume:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /path/on/host

NFS Driver

volumes:
  nfs_volume:
    driver: local
    driver_opts:
      type: nfs
      o: addr=nfs-server.example.com,rw
      device: ":/path/on/nfs"

Volume Plugin

volumes:
  cloud_volume:
    driver: cloudstor:aws
    driver_opts:
      backingstore: s3://bucket-name

Common Patterns

1. Preserve node_modules

services:
  web:
    build: .
    volumes:
      - .:/app
      - /app/node_modules  # Anonymous volume preserves node_modules

Why: Prevents host node_modules from overwriting container’s

2. Database Data Persistence

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

  mysql:
    image: mysql:8
    volumes:
      - mysql_data:/var/lib/mysql

volumes:
  postgres_data:
  mysql_data:

3. Log Aggregation

services:
  app:
    image: myapp
    volumes:
      - app_logs:/var/log/app

  log_aggregator:
    image: fluentd
    volumes:
      - app_logs:/var/log/app:ro  # Read-only

volumes:
  app_logs:

4. Shared Data Between Containers

services:
  worker1:
    image: myapp
    volumes:
      - shared_data:/data

  worker2:
    image: myapp
    volumes:
      - shared_data:/data

volumes:
  shared_data:

Common Interview Questions and Answers

Q1: What are the different types of volumes in Docker?

Volume types:

  1. Named Volumes:

    • Docker-managed with names
    • Persistent and shareable
    • Best for production data
  2. Bind Mounts:

    • Direct host filesystem access
    • Good for development
    • Changes reflect immediately
  3. Anonymous Volumes:

    • Auto-created without names
    • Temporary storage
    • Removed with container (usually)
  4. tmpfs Mounts:

    • In-memory storage
    • Fast but not persistent
    • Good for temporary files

Q2: What’s the difference between VOLUME in Dockerfile and volumes in docker-compose?

VOLUME in Dockerfile:

VOLUME ["/data"]  # Creates anonymous volume
  • Creates volume at image build time
  • Anonymous volume by default
  • Can be overridden at runtime

volumes in docker-compose:

volumes:
  - my_volume:/data  # Named volume
  • Defines volume at runtime
  • Can be named or bind mount
  • More flexible

Best Practice: Use docker-compose for volume management, VOLUME in Dockerfile for documentation.

Q3: When should you use bind mounts vs named volumes?

Use Bind Mounts when:

  • Development (live code reload)
  • Configuration files
  • Need direct host access
  • Sharing files with host

Use Named Volumes when:

  • Production data
  • Database storage
  • Need Docker management
  • Portability important

Example:

# Development: Bind mount
volumes:
  - .:/app

# Production: Named volume
volumes:
  - app_data:/app/data

Q4: What happens to data in a volume when a container is removed?

Depends on volume type:

  1. Named Volume: Data persists
docker run -v my_volume:/data myapp
docker rm container  # Volume and data remain
  1. Bind Mount: Data on host persists
docker run -v /host/data:/data myapp
docker rm container  # Host data remains
  1. Anonymous Volume: Usually removed
docker run -v /data myapp
docker rm container  # Volume removed (unless --rm not used)
  1. tmpfs: Data lost (in-memory)
docker run --tmpfs /tmp myapp
docker rm container  # Data lost

Q5: How do you backup and restore Docker volumes?

Backup and restore:

Backup:

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

# Backup with container
docker run --rm \
  -v postgres_data:/var/lib/postgresql/data \
  -v $(pwd):/backup \
  postgres:13 \
  pg_dumpall -U postgres > /backup/backup.sql

Restore:

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

Q6: What is the VOLUME instruction in Dockerfile?

VOLUME instruction:

VOLUME ["/data"]

Purpose:

  • Declares mount point for volume
  • Creates anonymous volume
  • Documents persistent data location
  • Can be overridden at runtime

Important:

  • Changes after VOLUME are lost
  • Creates anonymous volume by default
  • Best used for documentation

Example:

FROM postgres:13
VOLUME ["/var/lib/postgresql/data"]  # Documents data location

Q7: How do you share volumes between containers?

Sharing methods:

  1. Named Volume (Recommended):
services:
  app1:
    volumes:
      - shared_data:/data
  
  app2:
    volumes:
      - shared_data:/data

volumes:
  shared_data:
  1. Bind Mount:
services:
  app1:
    volumes:
      - ./shared:/data
  
  app2:
    volumes:
      - ./shared:/data
  1. Volume From:
services:
  app1:
    volumes:
      - data:/data
  
  app2:
    volumes_from:
      - app1

Q8: What’s the difference between -v and –mount?

-v (–volume):

docker run -v my_volume:/data myapp
docker run -v /host:/container:ro myapp
  • Simpler syntax
  • Legacy format
  • Less options

–mount:

docker run --mount type=volume,source=my_volume,target=/data myapp
docker run --mount type=bind,source=/host,target=/container,readonly myapp
  • More explicit
  • More options
  • Recommended for new code

Prefer –mount for clarity and options.

Q9: How do you handle node_modules in Docker volumes?

Common issue: Host node_modules overwrites container’s

Solution 1: Anonymous Volume:

services:
  web:
    volumes:
      - .:/app
      - /app/node_modules  # Preserves container's node_modules

Solution 2: .dockerignore:

node_modules

Solution 3: Separate Volume:

services:
  web:
    volumes:
      - .:/app
      - node_modules:/app/node_modules

volumes:
  node_modules:

Q10: What are tmpfs mounts and when to use them?

tmpfs mounts:

Definition: In-memory filesystem, not persistent

Use Cases:

  • Temporary files
  • Cache that can be lost
  • Sensitive data (cleared on stop)
  • High-performance temporary storage

Example:

services:
  app:
    tmpfs:
      - /tmp
      - /var/cache

Options:

tmpfs:
  - /tmp:rw,noexec,nosuid,size=100m

When to Use:

  • Temporary files
  • Performance-critical caches
  • Sensitive temporary data
  • Reduce disk I/O

Best Practices

  1. Use Named Volumes for Production: Managed and persistent
  2. Use Bind Mounts for Development: Live code reload
  3. Document VOLUME in Dockerfile: Shows persistent data locations
  4. Use Read-Only for Configs: Prevent accidental changes
  5. Backup Regularly: Important data needs backups
  6. Avoid VOLUME After COPY: Changes will be lost
  7. Use .dockerignore: Exclude unnecessary files from bind mounts
  8. Monitor Volume Usage: Check disk space
  9. Use tmpfs for Temporary Data: Fast and auto-cleaned
  10. Name Volumes Explicitly: Easier to manage

Summary

Volume types:

  • Named Volumes: Docker-managed, persistent, production-ready
  • Bind Mounts: Host filesystem, development-friendly
  • Anonymous Volumes: Auto-created, temporary
  • tmpfs: In-memory, fast, not persistent

VOLUME instruction:

  • Declares mount points
  • Creates anonymous volumes
  • Documents persistent data
  • Can be overridden

Best practices:

  • Named volumes for production
  • Bind mounts for development
  • Read-only for configs
  • Regular backups
  • Proper documentation

Volumes are essential for:

  • Data persistence
  • Container communication
  • Development workflows
  • Production deployments

Interview angle

  • “Volume, bind mount, or tmpfs?” - named volumes are Docker-managed and the right default for persistent data; bind mounts map a host path and suit local development with live reload; tmpfs is memory-only for secrets or scratch that must not touch disk.
  • “Why prefer a named volume over a bind mount in production?” - it’s portable, managed by the runtime, avoids host path and permission coupling, and works with volume drivers for networked storage.
  • “What happens to a volume when the container is removed?” - it survives. That’s the point, and also why unused volumes accumulate; prune them deliberately, since a stray docker volume prune can delete data you wanted.