Docker Compose and Orchestration
Overview
- What you’ll learn: How to define and manage multi-container applications using Docker Compose, including the docker-compose.yml file structure, service definitions, networking between services, scaling containers, environment management, resource limits, and health checks.
- Prerequisites: Docker Fundamentals (Lesson 58), basic YAML syntax
- Estimated reading time: 22 minutes
Introduction
Real-world applications rarely run as a single container. A typical web application might consist of an application server, a database, a cache layer, a reverse proxy, and a background worker — each running in its own container. Managing these containers individually with docker run commands quickly becomes tedious and error-prone. Docker Compose solves this by allowing you to define your entire application stack in a single YAML file.
Docker Compose reads a docker-compose.yml file that declares all services, their images, environment variables, volumes, networks, and dependencies. A single docker compose up command creates and starts the entire stack, while docker compose down tears it all down cleanly. This declarative approach makes application stacks reproducible, portable, and easy to version control.
In this lesson, you will learn the docker-compose.yml file structure, define multi-service applications with dependencies, configure networking and volumes, manage environment variables, scale services, set resource limits and health checks, and understand when to move beyond Compose to container orchestration platforms.
The docker-compose.yml File
The Compose file is the heart of Docker Compose. It uses YAML syntax to describe services (containers), networks, and volumes that make up your application. The current specification uses the Compose Specification format, which no longer requires a version: field.
# docker-compose.yml for a web application stack
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://appuser:secret@db:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
volumes:
- ./uploads:/app/uploads
restart: unless-stopped
db:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: appuser
POSTGRES_PASSWORD: secret
volumes:
- db-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]
interval: 10s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- cache-data:/data
nginx:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- app
volumes:
db-data:
cache-data:
# Compose automatically creates a default network for the stack
Each entry under services: defines a container. The build: directive tells Compose to build an image from a Dockerfile, while image: uses a pre-built image. The depends_on: section controls startup order and can wait for health check conditions. Named volumes declared at the top level persist data across container restarts. All services in a Compose file are automatically connected to a shared network where they can reach each other by service name.
Service Configuration and Dependencies
Docker Compose provides extensive options for configuring each service. Understanding dependency management is critical for ensuring services start in the correct order and can communicate reliably.
# Start the entire stack
$ docker compose up -d
[+] Running 4/4
✔ Network myapp_default Created
✔ Container myapp-db-1 Healthy
✔ Container myapp-cache-1 Started
✔ Container myapp-app-1 Started
✔ Container myapp-nginx-1 Started
# View running services
$ docker compose ps
NAME IMAGE STATUS PORTS
myapp-app-1 myapp:latest Up 2 minutes 0.0.0.0:3000->3000/tcp
myapp-db-1 postgres:15 Up 2 minutes (healthy) 5432/tcp
myapp-cache-1 redis:7 Up 2 minutes 6379/tcp
myapp-nginx-1 nginx:latest Up 2 minutes 0.0.0.0:80->80/tcp
# View logs across services
$ docker compose logs
$ docker compose logs -f app # follow one service
$ docker compose logs --tail 50 db # last 50 lines from db
# Execute commands in a service container
$ docker compose exec db psql -U appuser myapp
$ docker compose exec app sh
# Restart a single service
$ docker compose restart app
# Rebuild and restart services
$ docker compose up -d --build app
# Stop all services (preserves volumes)
$ docker compose down
# Stop and remove volumes
$ docker compose down -v
The docker compose up -d command starts all services in detached mode, respecting the dependency order. Compose names containers using the pattern {project}_{service}_{instance}. The project name defaults to the directory name but can be overridden with the -p flag or COMPOSE_PROJECT_NAME environment variable. The docker compose down -v command removes not only containers and networks but also named volumes, which is useful for clean resets during development.
Networking in Compose
Docker Compose automatically creates a bridge network for each project. All services in the Compose file are attached to this network and can reach each other using their service names as hostnames. You can also define custom networks for more complex topologies.
# docker-compose.yml with custom networks
services:
app:
build: .
networks:
- frontend
- backend
db:
image: postgres:15
networks:
- backend
nginx:
image: nginx:latest
ports:
- "80:80"
networks:
- frontend
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # no external access
# Inspect Compose networks
$ docker network ls | grep myapp
a1b2c3d4 myapp_frontend bridge local
b2c3d4e5 myapp_backend bridge local
# Verify service DNS resolution
$ docker compose exec app ping -c 2 db
PING db (172.20.0.3): 56 data bytes
64 bytes from 172.20.0.3: seq=0 ttl=64 time=0.1 ms
# The nginx service can reach app but NOT db (different networks)
$ docker compose exec nginx ping -c 1 app # succeeds
$ docker compose exec nginx ping -c 1 db # fails: Name not found
Custom networks allow you to isolate services. In the example above, the backend network with internal: true prevents the database from being accessible from outside the Docker environment. The app service is connected to both networks, acting as a bridge between the frontend (nginx) and backend (database) tiers. This mirrors traditional three-tier network architectures.
Scaling Services
Docker Compose supports running multiple instances of a service for simple horizontal scaling. This is useful for stateless application servers that can share load across instances.
# docker-compose.yml configured for scaling
services:
app:
build: .
expose:
- "3000"
deploy:
replicas: 3
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
environment:
- DATABASE_URL=postgres://appuser:secret@db:5432/myapp
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx-lb.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
db:
image: postgres:15
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
# Start with specified replicas
$ docker compose up -d
[+] Running 5/5
✔ Container myapp-db-1 Started
✔ Container myapp-app-1 Started
✔ Container myapp-app-2 Started
✔ Container myapp-app-3 Started
✔ Container myapp-nginx-1 Started
# Scale a service dynamically
$ docker compose up -d --scale app=5
# Verify scaled instances
$ docker compose ps
NAME STATUS PORTS
myapp-app-1 Up 5 min 3000/tcp
myapp-app-2 Up 5 min 3000/tcp
myapp-app-3 Up 5 min 3000/tcp
myapp-app-4 Up 1 min 3000/tcp
myapp-app-5 Up 1 min 3000/tcp
myapp-db-1 Up 5 min 5432/tcp
myapp-nginx-1 Up 5 min 0.0.0.0:80->80/tcp
When scaling services, use expose instead of ports to avoid port conflicts on the host. Nginx (or another load balancer) can distribute traffic across the instances using Docker’s built-in DNS round-robin resolution or an upstream configuration. Note that when using ports mappings, only one instance can bind to a given host port.
Environment Management and Resource Limits
Production deployments require careful management of environment variables (especially secrets) and resource constraints. Docker Compose supports multiple strategies for both.
# Using an .env file (loaded automatically)
# .env
POSTGRES_PASSWORD=supersecretpassword
APP_VERSION=2.1.0
# docker-compose.yml referencing .env variables
services:
app:
image: myapp:${APP_VERSION}
environment:
- DATABASE_PASSWORD=${POSTGRES_PASSWORD}
db:
image: postgres:15
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
# Using env_file for service-specific variables
services:
app:
build: .
env_file:
- ./common.env
- ./app.env
deploy:
resources:
limits:
cpus: '2.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 256M
# Override for different environments
# docker-compose.override.yml (automatically merged)
services:
app:
build:
context: .
target: development
volumes:
- .:/app
environment:
- NODE_ENV=development
- DEBUG=true
# Production override
# docker-compose.prod.yml
services:
app:
image: registry.example.com/myapp:${APP_VERSION}
deploy:
replicas: 3
resources:
limits:
cpus: '4.0'
memory: 2G
# Use override files for different environments
$ docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Validate the merged configuration
$ docker compose -f docker-compose.yml -f docker-compose.prod.yml config
# View resource usage of running services
$ docker compose top
$ docker stats
The .env file is loaded automatically and its variables can be referenced with ${VARIABLE} syntax. Override files allow you to customize the base configuration for different environments without duplicating the entire Compose file. The deploy.resources section sets CPU and memory limits that prevent a single service from consuming all host resources. Use docker compose config to verify the final merged configuration before deployment.
Key Takeaways
- Docker Compose defines multi-container applications in a single docker-compose.yml file, enabling reproducible, version-controlled application stacks that start with one command.
- Service dependencies with health checks ensure containers start in the correct order and are truly ready before dependent services attempt connections.
- Compose automatically creates isolated networks where services discover each other by name, and custom networks enable multi-tier isolation patterns.
- Services can be scaled horizontally with replicas and the –scale flag, paired with resource limits to prevent any single service from monopolizing host resources.
- Environment management through .env files, env_file directives, and override files supports clean separation between development, staging, and production configurations.
What’s Next
In Lesson 60, you will learn about cloud-init and Cloud Images, which automates the initialization of virtual machine and container instances at boot time using datasources, user-data scripts, and cloud-config modules for reproducible infrastructure provisioning.
繁體中文
概述
- 學習目標:了解如何使用 Docker Compose 定義和管理多容器應用程式,包括 docker-compose.yml 檔案結構、服務定義、服務間網路、容器擴展、環境管理、資源限制和健康檢查。
- 先決條件:Docker 基礎(第 58 課),基本的 YAML 語法
- 預計閱讀時間:22 分鐘
簡介
實際的應用程式很少以單一容器執行。一個典型的網頁應用程式可能包含應用程式伺服器、資料庫、快取層、反向代理和背景工作程式——每個都在自己的容器中執行。使用 docker run 命令單獨管理這些容器很快就會變得繁瑣且容易出錯。Docker Compose 透過允許您在單一 YAML 檔案中定義整個應用程式堆疊來解決這個問題。
Docker Compose 讀取 docker-compose.yml 檔案,宣告所有服務、映像、環境變數、磁碟區、網路和相依性。單一的 docker compose up 命令建立並啟動整個堆疊,而 docker compose down 則乾淨地拆除所有內容。這種宣告式方法使應用程式堆疊具有可重現性、可移植性,且易於版本控制。
在本課程中,您將學習 docker-compose.yml 檔案結構、定義具有相依性的多服務應用程式、設定網路和磁碟區、管理環境變數、擴展服務、設定資源限制和健康檢查,以及了解何時需要從 Compose 遷移到容器編排平台。
docker-compose.yml 檔案
Compose 檔案是 Docker Compose 的核心。它使用 YAML 語法描述組成應用程式的服務(容器)、網路和磁碟區。
# 網頁應用程式堆疊的 docker-compose.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://appuser:secret@db:5432/myapp
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
restart: unless-stopped
db:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: appuser
POSTGRES_PASSWORD: secret
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]
interval: 10s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
volumes:
- cache-data:/data
nginx:
image: nginx:latest
ports:
- "80:80"
depends_on:
- app
volumes:
db-data:
cache-data:
服務配置和相依性
Docker Compose 為配置每個服務提供了廣泛的選項。了解相依性管理對於確保服務按正確順序啟動並可靠通訊至關重要。
# 啟動整個堆疊
$ docker compose up -d
# 查看執行中的服務
$ docker compose ps
# 查看跨服務的日誌
$ docker compose logs
$ docker compose logs -f app
# 在服務容器中執行命令
$ docker compose exec db psql -U appuser myapp
# 重新啟動單一服務
$ docker compose restart app
# 重新建構並重新啟動服務
$ docker compose up -d --build app
# 停止所有服務
$ docker compose down
# 停止並移除磁碟區
$ docker compose down -v
Compose 中的網路
Docker Compose 自動為每個專案建立橋接網路。Compose 檔案中的所有服務都連接到此網路,可以使用服務名稱作為主機名稱彼此通訊。您也可以為更複雜的拓撲定義自訂網路。
# 具有自訂網路的 docker-compose.yml
services:
app:
build: .
networks:
- frontend
- backend
db:
image: postgres:15
networks:
- backend
nginx:
image: nginx:latest
ports:
- "80:80"
networks:
- frontend
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 無外部存取
自訂網路允許您隔離服務。具有 internal: true 的 backend 網路防止資料庫從 Docker 環境外部存取。app 服務連接到兩個網路,充當前端(nginx)和後端(資料庫)層之間的橋樑。
擴展服務
Docker Compose 支援執行服務的多個實例,實現簡單的水平擴展。這對於可以跨實例共享負載的無狀態應用程式伺服器很有用。
# 為擴展配置的 docker-compose.yml
services:
app:
build: .
expose:
- "3000"
deploy:
replicas: 3
resources:
limits:
cpus: '1.0'
memory: 512M
# 動態擴展服務
$ docker compose up -d --scale app=5
# 驗證擴展的實例
$ docker compose ps
環境管理和資源限制
生產部署需要仔細管理環境變數(尤其是密鑰)和資源約束。Docker Compose 支援多種策略。
# 使用 .env 檔案(自動載入)
# .env
POSTGRES_PASSWORD=supersecretpassword
APP_VERSION=2.1.0
# 使用覆蓋檔案適應不同環境
$ docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# 驗證合併後的配置
$ docker compose config
# 查看執行中服務的資源使用情況
$ docker compose top
$ docker stats
.env 檔案會自動載入,其變數可使用 ${VARIABLE} 語法引用。覆蓋檔案允許您自訂不同環境的基礎配置,無需複製整個 Compose 檔案。deploy.resources 部分設定 CPU 和記憶體限制,防止單一服務消耗所有主機資源。
重點摘要
- Docker Compose 在單一 docker-compose.yml 檔案中定義多容器應用程式,實現可重現、版本控制的應用程式堆疊,一個命令即可啟動。
- 具有健康檢查的服務相依性確保容器按正確順序啟動,且在相依服務嘗試連線之前確實準備就緒。
- Compose 自動建立隔離的網路,服務透過名稱發現彼此,自訂網路支援多層隔離模式。
- 服務可以透過副本和 –scale 旗標進行水平擴展,搭配資源限制防止任何單一服務獨佔主機資源。
- 透過 .env 檔案、env_file 指令和覆蓋檔案進行環境管理,支援開發、測試和生產配置之間的清晰分離。
下一步
在第 60 課中,您將學習 cloud-init 和雲端映像,它使用資料來源、使用者資料腳本和 cloud-config 模組,在啟動時自動化虛擬機器和容器實例的初始化,實現可重現的基礎架構佈建。
日本語
概要
- 学習内容:Docker Compose を使用したマルチコンテナアプリケーションの定義と管理方法。docker-compose.yml ファイル構造、サービス定義、サービス間ネットワーキング、コンテナのスケーリング、環境管理、リソース制限、ヘルスチェックを含みます。
- 前提条件:Docker の基礎(レッスン58)、基本的な YAML 構文
- 推定読了時間:22分
はじめに
実際のアプリケーションは単一のコンテナとして実行されることはほとんどありません。典型的な Web アプリケーションは、アプリケーションサーバー、データベース、キャッシュレイヤー、リバースプロキシ、バックグラウンドワーカーで構成され、それぞれが独自のコンテナで実行されます。docker run コマンドでこれらのコンテナを個別に管理することは、すぐに面倒でエラーが発生しやすくなります。Docker Compose は、アプリケーションスタック全体を単一の YAML ファイルで定義できるようにすることで、この問題を解決します。
Docker Compose は docker-compose.yml ファイルを読み取り、すべてのサービス、イメージ、環境変数、ボリューム、ネットワーク、依存関係を宣言します。単一の docker compose up コマンドでスタック全体を作成・起動し、docker compose down ですべてをクリーンに破棄します。この宣言的アプローチにより、アプリケーションスタックは再現可能で、ポータブルで、バージョン管理が容易になります。
このレッスンでは、docker-compose.yml ファイル構造、依存関係を持つマルチサービスアプリケーションの定義、ネットワーキングとボリュームの構成、環境変数の管理、サービスのスケーリング、リソース制限とヘルスチェックの設定、Compose を超えてコンテナオーケストレーションプラットフォームに移行するタイミングについて学びます。
docker-compose.yml ファイル
Compose ファイルは Docker Compose の中心です。YAML 構文を使用して、アプリケーションを構成するサービス(コンテナ)、ネットワーク、ボリュームを記述します。
# Web アプリケーションスタックの docker-compose.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://appuser:secret@db:5432/myapp
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
restart: unless-stopped
db:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: appuser
POSTGRES_PASSWORD: secret
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]
interval: 10s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
volumes:
- cache-data:/data
nginx:
image: nginx:latest
ports:
- "80:80"
depends_on:
- app
volumes:
db-data:
cache-data:
サービス構成と依存関係
Docker Compose は各サービスを構成するための広範なオプションを提供します。依存関係管理の理解は、サービスが正しい順序で起動し、確実に通信できるようにするために重要です。
# スタック全体を起動
$ docker compose up -d
# 実行中のサービスを表示
$ docker compose ps
# サービス間のログを表示
$ docker compose logs
$ docker compose logs -f app
# サービスコンテナ内でコマンドを実行
$ docker compose exec db psql -U appuser myapp
# 単一サービスを再起動
$ docker compose restart app
# サービスを再ビルドして再起動
$ docker compose up -d --build app
# すべてのサービスを停止
$ docker compose down
# 停止してボリュームも削除
$ docker compose down -v
Compose でのネットワーキング
Docker Compose はプロジェクトごとにブリッジネットワークを自動作成します。Compose ファイル内のすべてのサービスがこのネットワークに接続され、サービス名をホスト名として互いに通信できます。より複雑なトポロジーのためにカスタムネットワークも定義できます。
# カスタムネットワーク付きの docker-compose.yml
services:
app:
build: .
networks:
- frontend
- backend
db:
image: postgres:15
networks:
- backend
nginx:
image: nginx:latest
ports:
- "80:80"
networks:
- frontend
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 外部アクセスなし
カスタムネットワークによりサービスを分離できます。internal: true の backend ネットワークは、データベースが Docker 環境の外部からアクセスされることを防ぎます。app サービスは両方のネットワークに接続され、フロントエンド(nginx)とバックエンド(データベース)層のブリッジとして機能します。
サービスのスケーリング
Docker Compose はサービスの複数インスタンスの実行をサポートし、シンプルな水平スケーリングを実現します。
# スケーリング用に構成された docker-compose.yml
services:
app:
build: .
expose:
- "3000"
deploy:
replicas: 3
resources:
limits:
cpus: '1.0'
memory: 512M
# サービスを動的にスケーリング
$ docker compose up -d --scale app=5
# スケーリングされたインスタンスを確認
$ docker compose ps
環境管理とリソース制限
本番デプロイメントでは、環境変数(特にシークレット)とリソース制約の慎重な管理が必要です。Docker Compose は両方に対して複数の戦略をサポートします。
# .env ファイルを使用(自動的にロード)
# .env
POSTGRES_PASSWORD=supersecretpassword
APP_VERSION=2.1.0
# 異なる環境のオーバーライドファイルを使用
$ docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# マージされた構成を検証
$ docker compose config
# 実行中のサービスのリソース使用量を表示
$ docker compose top
$ docker stats
.env ファイルは自動的にロードされ、その変数は ${VARIABLE} 構文で参照できます。オーバーライドファイルにより、Compose ファイル全体を複製することなく、異なる環境の基本構成をカスタマイズできます。deploy.resources セクションは CPU とメモリの制限を設定し、単一のサービスがすべてのホストリソースを消費することを防ぎます。
重要ポイント
- Docker Compose は単一の docker-compose.yml ファイルでマルチコンテナアプリケーションを定義し、1つのコマンドで起動できる再現可能でバージョン管理されたアプリケーションスタックを実現します。
- ヘルスチェック付きのサービス依存関係により、コンテナが正しい順序で起動し、依存サービスが接続を試みる前に本当に準備ができていることを保証します。
- Compose はサービスが名前で互いを発見できる分離されたネットワークを自動作成し、カスタムネットワークはマルチティアの分離パターンを可能にします。
- サービスはレプリカと –scale フラグで水平スケーリングでき、リソース制限と組み合わせて単一サービスがホストリソースを独占することを防ぎます。
- .env ファイル、env_file ディレクティブ、オーバーライドファイルによる環境管理は、開発、ステージング、本番構成間のクリーンな分離をサポートします。
次のステップ
レッスン60では、cloud-init とクラウドイメージについて学びます。データソース、ユーザーデータスクリプト、cloud-config モジュールを使用して、ブート時に仮想マシンやコンテナインスタンスの初期化を自動化し、再現可能なインフラストラクチャプロビジョニングを実現します。