Docker Compose — Networks and Volumes

Why Networks and Volumes Matter

Networks enable services to communicate with each other. Volumes persist data beyond the container lifecycle. Together they form the backbone of multi-service applications in Docker Compose. Without understanding networks and volumes, your containers cannot talk to each other and your data disappears when containers restart.

Why this matters for your career:

  • Networking misconfiguration is a top cause of Docker issues
  • Data persistence is essential for databases, caches, and user uploads
  • Understanding Docker networking is required for Kubernetes networking
  • Volume management is key for backups and data migration

Docker Compose Networks

By default, Docker Compose creates a single network for all services defined in the compose file. Services can reach each other by service name (which acts as a DNS hostname).

Default Network

version: "3.9"
services:
  web:
    image: nginx
    # Can reach: db, redis by hostname
  db:
    image: postgres
  redis:
    image: redis

# Docker Compose creates a network called: project_default

Inside the web container, you can connect to the database using the hostname db and the port 5432 (inside the container).

Custom Networks

version: "3.9"
services:
  frontend:
    image: nginx
    networks:
      - frontend_net
      - backend_net

  api:
    image: my-api
    networks:
      - backend_net
      - database_net

  db:
    image: postgres
    networks:
      - database_net

networks:
  frontend_net:
    driver: bridge
  backend_net:
    driver: bridge
  database_net:
    driver: bridge

This creates three isolated networks:

  • frontend_net: frontend + api (frontend can reach api)
  • backend_net: api + frontend (shared)
  • database_net: api + db (api can reach db, frontend cannot)

Network isolation improves security by limiting which services can communicate.

Network Drivers

| Driver | Isolation | Use Case | |--------|-----------|----------| | bridge | Per-network | Default, single-host | | host | None (uses host network) | Performance-critical, single service | | overlay | Multi-host | Docker Swarm, multi-node | | macvlan | MAC address per container | Legacy apps needing direct network access | | none | Complete isolation | Security testing, standalone services |

Docker Compose Volumes

Volumes persist data generated by containers. They survive container restarts, updates, and deletions.

Named Volumes

version: "3.9"
services:
  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
  redis:
    image: redis:7
    volumes:
      - redis_data:/data

volumes:
  pgdata:
  redis_data:

Named volumes are managed by Docker and stored in /var/lib/docker/volumes/. They are the preferred way to persist data.

Bind Mounts

Bind mounts map a host directory into the container:

services:
  web:
    image: nginx
    volumes:
      - ./html:/usr/share/nginx/html:ro  # Read-only mount
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
  app:
    build: .
    volumes:
      - .:/app  # Development hot-reload
      - /app/node_modules  # Exclude node_modules from mount

Bind mounts are ideal for development (hot-reload) and configuration files. They are not recommended for production database storage.

tmpfs Mounts

services:
  cache:
    image: redis:7
    tmpfs:
      - /data  # Temporary, in-memory storage

tmpfs mounts are stored in memory only. They are fast but data is lost when the container stops. Use for caches and temporary files.

Volume Operations

# List volumes
docker volume ls

# Inspect a volume
docker volume inspect pgdata

# Remove unused volumes
docker volume prune

# Backup a volume
docker run --rm -v pgdata:/source -v $(pwd):/backup alpine \
  tar czf /backup/pgdata-backup.tar.gz -C /source .

# Restore a volume
docker run --rm -v pgdata:/target -v $(pwd):/backup alpine \
  tar xzf /backup/pgdata-backup.tar.gz -C /target

Network + Volume Complete Example

version: "3.9"

services:
  app:
    build: .
    ports:
      - "3000:3000"
    networks:
      - app_net
      - db_net
    volumes:
      - .:/app  # dev hot-reload
      - uploads:/app/uploads
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    networks:
      - db_net
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    networks:
      - app_net
    volumes:
      - redis_data:/data
    tmpfs:
      - /tmp

networks:
  app_net:
  db_net:

volumes:
  pgdata:
  redis_data:
  uploads:

This setup provides:

  • app can reach redis (same app_net) and db (connected to both)
  • db is isolated on db_net (only app can reach it)
  • Database data persists via pgdata named volume
  • User uploads persist via uploads named volume
  • Redis data persists, but /tmp is temporary (tmpfs)
  • App waits for db to be healthy before starting

Volume Driver Options

| Driver | Description | Use Case | |--------|-------------|----------| | local | Default, stored on host | General purpose | | nfs | Network File System | Shared storage across hosts | | cloudstor | AWS EBS, Azure Disk | Cloud storage integration | | cifs | Samba/CIFS | Windows file shares | | tmpfs | In-memory | Caches, temporary data |

Best Practices

| Practice | Reason | |----------|--------| | Use named volumes for databases | Data survives container restart | | Use bind mounts for development | Live code reload | | Use bind mounts for config files | Easy configuration changes | | Isolate networks by function | Security — limit which services can talk | | Always set healthcheck on databases | Other services wait for db readiness | | Never store secrets in bind mounts | Secrets in files may be committed to git | | Backup named volumes regularly | Data loss prevention | | Use tmpfs for caches | Speed, no disk wear |

Summary

Networks and volumes are essential for multi-service Docker Compose applications. Networks control which services can communicate, and volumes persist data beyond container lifetimes. Proper network isolation improves security, while proper volume configuration ensures data durability.

Key takeaways:

  • Default network: all services can communicate by hostname
  • Custom networks provide isolation between service groups
  • Named volumes persist data (managed by Docker)
  • Bind mounts share host directories with containers
  • tmpfs mounts are in-memory (fast, ephemeral)
  • Network drivers: bridge (default), host, overlay, macvlan
  • Use healthchecks to manage startup order
  • Back up named volumes regularly

What's Next: Deploy to VPS

The next chapter covers deploying Docker Compose applications to a VPS — using docker-compose in production, reverse proxy with Nginx, SSL certificates, and monitoring.

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!