目次
compose.yaml の構文を徹底解説
compose.yaml の最上位には、主に4つのセクションがあります。
name: myapp # プロジェクト名(任意、デフォルトはフォルダー名)
services: # 実行するコンテナ
...
volumes: # 名前付き Volume
...
networks: # カスタムネットワーク(任意、デフォルトで自動作成)
...
以下では、用途別に services の下でよく使う設定を説明し、最後に完全な例を実行します。
image と build
既存のイメージを使います。
services:
redis:
image: redis:8-alpine
Dockerfile からビルドします。
services:
app:
build: . # 現在のフォルダーにある Dockerfile を使う
さらに細かく設定する場合:
services:
app:
build:
context: ./backend
dockerfile: Dockerfile.prod
target: prod # マルチステージビルドの対象ステージ
args:
APP_VERSION: "1.4.2"
image: myorg/app:1.4.2 # ビルド後のイメージ名
build と image の両方を指定すると、Compose はビルド結果に image の値を名前として付けます。その後、docker compose push でプッシュできます。
ports:ポート
ports:
- "8080:80" # ホスト:コンテナ
- "127.0.0.1:5432:5432" # ローカルのみ公開
- "9000-9002:9000-9002" # 範囲
必ず引用符で囲んでください。YAML は一部の 数字:数字 形式を60進数として解釈するため、予期しないエラーの原因になります。
expose は用途を示すだけで、外部には公開しません。同じネットワーク内のサービスは、もともと相互に接続できます。
volumes:マウント
services:
db:
image: postgres:18
volumes:
- pgdata:/var/lib/postgresql # 名前付き Volume
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro # Bind mount(相対パス)
volumes:
pgdata:
-
./または../で始まるパスは、compose.yamlからの相対パスを使う Bind mount です。 -
名前だけを指定するものは名前付き Volume です。最上位の
volumes:で宣言する必要があり、実際の名前にはプロジェクト名のプレフィックスが付きます(例:shop_pgdata)。 -
Compose の外で作成した Volume を使う場合:
volumes: pgdata: external: true
environment と env_file
environment:
NODE_ENV: production
DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
env_file:
- .env.app
${...} の値は .env ファイルまたは現在の環境変数から取得されます。詳しくは環境変数と .env ファイルをご覧ください。
depends_on と healthcheck:データベースの準備が整うまで待つ
depends_on が制御するのは起動順序だけです。db コンテナが先に起動することは保証しますが、データベースに接続できる状態になっていることまでは保証しません。PostgreSQL の起動には数秒かかるため、アプリケーションが接続できずに失敗することがあります。healthcheck と condition: service_healthy を組み合わせると、Compose はヘルスチェックに合格してからアプリケーションを起動します。
実際の例(compose.yaml):
name: shop
services:
app:
image: postgres:18
command: ["psql", "-h", "db", "-U", "shop", "-c", "SELECT 'app connected' AS status;"]
environment:
PGPASSWORD: ${DB_PASSWORD}
depends_on:
db:
condition: service_healthy
db:
image: postgres:18
environment:
POSTGRES_USER: shop
POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required}
POSTGRES_DB: shop
volumes:
- pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U shop -d shop"]
interval: 2s
timeout: 3s
retries: 20
adminer:
image: adminer
ports:
- "8081:8080"
profiles: [tools]
volumes:
pgdata:
app は PostgreSQL クライアントを使って、「起動時にデータベースへ接続する」アプリケーションを模擬します。.env に DB_PASSWORD=change-me を設定してください。
まず db だけを起動し、ヘルス状態の変化を確認します。
$ docker compose up -d db
[+] up 3/3
✔ Network shop_default Created 0.0s
✔ Volume shop_pgdata Created 0.0s
✔ Container shop-db-1 Started 0.3s
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
shop-db-1 postgres:18 "docker-entrypoint.s…" db 1 second ago Up Less than a second (health: starting) 127.0.0.1:5432->5432/tcp
数秒後:
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
shop-db-1 postgres:18 "docker-entrypoint.s…" db 10 seconds ago Up 9 seconds (healthy) 127.0.0.1:5432->5432/tcp
状態が health: starting から healthy に変わりました。いったん停止し、最初から app を起動します。
$ docker compose up app
[+] up 3/3
✔ Network shop_default Created 0.0s
✔ Container shop-db-1 Created 0.0s
✔ Container shop-app-1 Created 0.1s
Attaching to app-1
Container shop-db-1 Waiting
Container shop-db-1 Healthy
app-1 | status
app-1 | ---------------
app-1 | app connected
app-1 | (1 row)
app-1 |
app-1 exited with code 0
w Enable Watch d Detach
Compose は先に db を起動し、Waiting と表示します。Healthy になるまで待ってから app を起動するため、app は最初の接続に成功します(app connected)。condition: service_healthy がなければ、データベースの準備が整う前に app が接続しようとします。
(最後の行 w Enable Watch d Detach は、Compose をフォアグラウンドで実行したときに表示されるショートカットの案内です。)
ヘルスチェックの
pg_isreadyには-h 127.0.0.1を指定しています。指定しない場合、初期化の途中でデータベースが healthy と判定され、アプリケーションの接続が失敗することがあります。実測例はPostgreSQLを参照してください。MySQL でも同じ問題が起こります。MySQLを参照してください。
condition に指定できる値:
| 値 | 意味 |
|---|---|
service_started | コンテナが起動済み(デフォルト) |
service_healthy | ヘルスチェックに合格 |
service_completed_successfully | サービスが実行を完了し、終了コードが 0。データベースのマイグレーションなど、一度だけ実行するタスクに適しています |
さらに depends_on の下に restart: true を追加すると、db の再起動時に app も再起動します。
restart
restart: unless-stopped
使用できる値:no、always、on-failure、unless-stopped(動作についてはコンテナのライフサイクルを参照してください)。
command と entrypoint
イメージの CMD / ENTRYPOINT を上書きします。
command: ["npm", "run", "dev"]
entrypoint: ["/app/docker-entrypoint.sh"]
networks
デフォルトでは、すべてのサービスが同じ 專案名稱_default ネットワークに属します。分離する必要がある場合は、独自のネットワークを定義できます。
services:
web:
image: nginx:1.30-alpine
networks: [frontend]
app:
build: .
networks: [frontend, backend]
db:
image: postgres:18
networks: [backend]
networks:
frontend:
backend:
web は app に接続できますが、db には接続できません。
profiles:サービスを選択して起動する
上の例では、adminer に profiles: [tools] を設定しています。
$ docker compose config --services
db
app
$ docker compose --profile tools config --services
db
app
adminer
profile を指定しない場合、adminer は起動しません。--profile tools を追加すると起動します。管理ツールやテスト用メールサーバーなど、必要なときだけ起動するサービスに適しています。
リソース制限とその他のよく使う設定
services:
app:
image: myorg/app:1.4.2
container_name: app # コンテナ名を固定(あとから scale できません)
user: "1000:1000"
working_dir: /app
mem_limit: 512m
cpus: 1.5
init: true # docker run --init と同じ
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
extra_hosts:
- "host.docker.internal:host-gateway"
compose.override.yaml:設定のマージ
Compose は compose.yaml と compose.override.yaml を自動的にマージします。サンプルのディレクトリには、このファイルもあります。
# compose.override.yaml
services:
db:
ports:
- "127.0.0.1:5432:5432"
docker compose config でマージ後の最終的な設定を確認します(最後の ports に注目してください)。
$ docker compose config db
name: shop
services:
db:
environment:
POSTGRES_DB: shop
POSTGRES_PASSWORD: change-me
POSTGRES_USER: shop
image: postgres:18
networks:
default: null
volumes:
- type: volume
source: pgdata
target: /var/lib/postgresql
volume: {}
healthcheck:
test:
- CMD-SHELL
- pg_isready -h 127.0.0.1 -U shop -d shop
timeout: 3s
interval: 2s
retries: 20
ports:
- mode: ingress
host_ip: 127.0.0.1
target: 5432
published: "5432"
protocol: tcp
networks:
default:
name: shop_default
volumes:
pgdata:
name: shop_pgdata
-f compose.yaml でファイルを明示的に 1 つだけ指定すると、override はマージされず、ports もなくなります。
$ docker compose -f compose.yaml config db
name: shop
services:
db:
environment:
POSTGRES_DB: shop
POSTGRES_PASSWORD: change-me
POSTGRES_USER: shop
image: postgres:18
networks:
default: null
volumes:
- type: volume
source: pgdata
target: /var/lib/postgresql
volume: {}
healthcheck:
test:
- CMD-SHELL
- pg_isready -h 127.0.0.1 -U shop -d shop
timeout: 3s
interval: 2s
retries: 20
networks:
default:
name: shop_default
volumes:
pgdata:
name: shop_pgdata
docker compose config は省略形式も完全な形式に展開します(たとえば、pgdata:/var/lib/postgresql は type: volume、source、target に変換されます)。さらに、${DB_PASSWORD} も置き換えます。設定が反映されていないように見えるときは、まずこれを使って Compose が実際に読み込んだ内容を確認してください。
よくある使い分けは次のとおりです。
compose.yaml:すべての環境で共通の設定です。compose.override.yaml:開発専用の設定(ソースコードのマウント、デバッグ用ポートの公開)です。ローカルでdocker compose upを実行すると自動的に適用されます。compose.prod.yaml:本番環境用です。docker compose -f compose.yaml -f compose.prod.yaml up -dで指定します。
まとめ
imageは既存のイメージを使い、buildは Dockerfile からビルドします。depends_onとcondition: service_healthyを組み合わせると、サービスが実際に準備できるまで待機します。profilesを使うと、管理ツールなどのサービスを必要なときだけ起動できます。compose.override.yamlは自動的にマージされます。docker compose configで最終的な設定を確認しましょう。
練習問題
練習 1:この章の db サービスに restart: unless-stopped を追加し、メモリを 512 MB に制限してください。
解答
db:
image: postgres:18
restart: unless-stopped
mem_limit: 512m
変更を適用するには、docker compose up -d を実行します。
練習 2:adminer には profiles: [tools] が設定されています。一緒に起動するにはどうしますか?
解答
docker compose --profile tools up -d
よくある質問
depends_on を指定してもデータベースの準備完了を待たないのはなぜですか?
depends_on: [db] だけでは起動順序が保証されるだけです。データベースに接続できるまで待つには、healthcheck と condition: service_healthy を設定します。ヘルスチェックの書き方はこの章と [PostgreSQL](/ja/docker/postgresql/) をご覧ください。
YAML のインデントを間違えるとどうなりますか?
docker compose config が did not find expected key などのエラーを表示します。[よくあるエラーメッセージ](/ja/docker/errors/) をご覧ください。空白だけを使い、Tab は使わないでください。
version: '3.8' はまだ必要ですか?
必要ありません。Compose Specification では version フィールドは使われなくなっており、現在のバージョンでは無視され、警告が表示されます。
更新日 2026年10月14日