✦ For everyone, free.

Practical knowledge for real and everyday life

Home

20.2.1 Compose Learning Step

A focused guide to Compose Learning Step, connecting core concepts with practical Docker and container operations.

Docker Compose is the tool that brings multiple containers together as a single, coordinated application. The Compose learning step teaches you to define multi-service applications in a declarative file, start and stop them with single commands, and understand how Compose manages the networking, volumes, and dependencies between services.

What Docker Compose Does

Running multiple containers manually means executing separate docker run commands for each service, creating networks by hand, passing connection parameters as environment variables, and remembering the exact flags for each container. Docker Compose replaces all of that with a single compose.yml file that describes every service, its configuration, its connections to other services, and its volumes — and then starts everything with one command.

Compose is included with Docker Desktop on Mac and Windows. On Linux, it is installed as the docker compose plugin.

The compose.yml File

Compose reads a file named compose.yml (or docker-compose.yml for the legacy version) in the current directory. This file uses YAML to define services:

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

This file defines two services: a web server and a PostgreSQL database. The volumes section at the top level declares the named volume db_data that Docker manages.

Starting the Application

docker compose up -d

Compose reads compose.yml, creates the services' containers, connects them to a shared network, and starts them. The -d flag runs them in the background (detached mode).

On first run, Compose pulls any images not already present locally. Subsequent runs use cached images unless the image tags have changed.

Verifying Services Are Running

docker compose ps
NAME          IMAGE           STATUS     PORTS
project-db-1  postgres:15     running    5432/tcp
project-web-1 nginx:alpine    running    0.0.0.0:8080->80/tcp

Each service is named with the project name prefix (defaulting to the directory name) and a numeric suffix.

Built-In DNS Between Services

Compose creates a private network for the application and configures DNS so that each service is reachable by its service name. A container in the web service can connect to the database at hostname db on port 5432 — Docker resolves db to the database container's IP address automatically.

No manual network creation, no hardcoded IP addresses.

Building Application Images

When a service uses a Dockerfile instead of a prebuilt image, use the build key:

services:
  web:
    build: .
    ports:
      - "3000:3000"
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

build: . tells Compose to run docker build in the current directory to create the web service image. The image is rebuilt only when you explicitly request it.

To rebuild images:

docker compose build

Or rebuild and restart in one step:

docker compose up -d --build

Service Dependencies

Services often have startup order requirements: the web server should not start until the database is ready. Use depends_on to declare ordering:

services:
  web:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

With condition: service_healthy, Compose waits until the db service's healthcheck passes before starting web. The healthcheck runs pg_isready to verify PostgreSQL is accepting connections.

Viewing Logs

docker compose logs

Shows aggregated logs from all services, prefixed with the service name.

docker compose logs -f web

Streams live logs from the web service only.

Stopping and Removing

Stop running containers without removing them:

docker compose stop

Stop and remove containers, networks, and anonymous volumes:

docker compose down

Remove containers, networks, and named volumes:

docker compose down -v

The -v flag removes named volumes, which deletes persisted data. Use it with care.

Environment Variables in Compose

Compose supports a .env file in the same directory as compose.yml for variable substitution:

.env file:

POSTGRES_PASSWORD=mysecret
APP_PORT=3000

compose.yml:

services:
  web:
    build: .
    ports:
      - "${APP_PORT}:3000"
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

Compose reads .env automatically and substitutes variables in the YAML. Sensitive values stay out of the committed compose.yml file.

Multiple Compose Files

Compose supports merging multiple files for environment-specific overrides:

docker compose -f compose.yml -f compose.override.yml up -d

compose.override.yml is automatically loaded alongside compose.yml if it exists in the same directory. This pattern keeps production and development configurations separate: the base compose.yml defines services, and compose.override.yml adds development-specific volume mounts and debug settings.

The Architecture Compose Establishes

Compose network (project_default) web :3000 db :5432 DNS Host :8080

All services share a private network. The web service reaches db by hostname. The web service publishes port 8080 to the host. The database port is not exposed to the host — it is only accessible from within the Compose network.

Running Commands Inside a Service

docker compose exec web sh

Opens a shell inside the running web service container. Useful for inspecting the filesystem, running database migrations, or debugging connection issues from inside the container.

docker compose exec db psql -U postgres

Opens a PostgreSQL prompt inside the db service container.

Compose in Development vs Production

For local development, Compose is the standard way to run the full application stack on a developer's machine with a single command. For production, Compose is suitable for single-host deployments. For multi-host deployments with high availability, Kubernetes or Docker Swarm take over the orchestration role.

Content in this section