YAML with Docker and Docker Compose

Docker is the most widely used tool for containerizing applications. Docker Compose is the tool that manages multi-container applications using a single YAML file. Learning YAML for Docker means learning how to describe an entire application — its services, networks, volumes, and environment variables — in one readable file.

What Is a Docker Compose File?

A Docker Compose file is a YAML file named docker-compose.yml. It defines all the services that make up an application and how they connect to each other. One command — docker compose up — reads this file and starts all defined services.

Top-Level Keys in Docker Compose

KeyPurpose
versionSpecifies the Compose file format version
servicesDefines the individual containers (applications)
networksDefines custom networks for services to communicate
volumesDefines named storage volumes for persistent data
configsDefines configuration files to inject into services
secretsDefines sensitive data like passwords and certificates

Docker Compose File Structure Diagram

docker-compose.yml
│
├── version: "3.9"
│
├── services:
│     ├── web:
│     │     ├── image / build
│     │     ├── ports
│     │     ├── environment
│     │     ├── volumes
│     │     └── depends_on
│     │
│     └── db:
│           ├── image
│           ├── environment
│           └── volumes
│
├── networks:
│     └── app_network
│
└── volumes:
      └── db_data

Basic Single-Service Example

version: "3.9"

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"

This starts one Nginx web server container and exposes port 80 on the host machine.

Understanding the ports Key

ports:
  - "8080:80"    # HOST_PORT:CONTAINER_PORT
  - "443:443"

The format is HOST_PORT:CONTAINER_PORT. Traffic on the host machine's port 8080 forwards into the container's port 80.

Building from a Dockerfile

Instead of using an existing image, a service can build its container from a local Dockerfile.

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"

The context: . means Docker looks for the Dockerfile in the current directory.

Environment Variables

Configuration values like database credentials or API keys are passed to containers as environment variables.

services:
  app:
    image: myapp:latest
    environment:
      NODE_ENV: production
      DB_HOST: db
      DB_PORT: 5432
      DB_NAME: appdb

Alternatively, environment variables can be loaded from an external file using env_file.

services:
  app:
    image: myapp:latest
    env_file:
      - .env

Volumes for Persistent Data

Volumes keep data alive even when a container stops or is replaced.

services:
  db:
    image: postgres:15
    volumes:
      - db_data:/var/lib/postgresql/data    # Named volume
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql  # Bind mount

volumes:
  db_data:    # Named volume declaration

A named volume (db_data) is managed by Docker. A bind mount (./init.sql:...) maps a file from the host machine directly into the container.

Service Dependencies (depends_on)

services:
  web:
    image: myapp:latest
    depends_on:
      - db
      - redis

  db:
    image: postgres:15

  redis:
    image: redis:7

The depends_on key tells Docker to start the db and redis containers before starting web. Note that this waits for the container to start, not for the service inside to be ready.

Custom Networks

services:
  frontend:
    image: nginx:latest
    networks:
      - frontend_net

  backend:
    image: myapi:latest
    networks:
      - frontend_net
      - backend_net

  db:
    image: postgres:15
    networks:
      - backend_net

networks:
  frontend_net:
  backend_net:

Custom networks isolate services. The database is only on backend_net and cannot be reached directly from the frontend container.

Complete Full-Stack Example

version: "3.9"

services:
  # Frontend
  frontend:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./frontend/dist:/usr/share/nginx/html
    depends_on:
      - api
    networks:
      - app_net

  # Backend API
  api:
    build:
      context: ./api
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: production
      DB_HOST: db
      DB_PORT: 5432
      DB_USER: admin
      DB_PASS: secret
    depends_on:
      - db
    networks:
      - app_net

  # Database
  db:
    image: postgres:15
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: appdb
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - app_net

networks:
  app_net:

volumes:
  db_data:

Common Docker Compose YAML Properties

PropertyDescriptionExample
imageDocker image to usenginx:latest
buildBuild from Dockerfilecontext: .
portsPort mapping"8080:80"
environmentEnvironment variablesNODE_ENV: production
volumesMount files or directories./data:/app/data
depends_onService startup order- db
networksConnect to networks- app_net
restartRestart policyalways, on-failure
commandOverride container commandnpm start
healthcheckContainer health monitoringtest: ["CMD", "curl", "-f", "http://localhost"]

Summary

  • Docker Compose uses a YAML file to define multi-container applications
  • Top-level keys include services, networks, and volumes
  • Each service can use an existing image or build from a Dockerfile
  • Ports follow the format HOST:CONTAINER
  • Environment variables configure containers without hardcoding values
  • Named volumes persist data across container restarts
  • Custom networks isolate services and control communication

Leave a Comment