目次

compose.yaml の構文を徹底解説

compose.yaml の最上位には、主に4つのセクションがあります。

name: myapp          # プロジェクト名(任意、デフォルトはフォルダー名)

services:            # 実行するコンテナ
  ...

volumes:             # 名前付き Volume
  ...

networks:            # カスタムネットワーク(任意、デフォルトで自動作成)
  ...

以下では、用途別に services の下でよく使う設定を説明し、最後に完全な例を実行します。

Compose プロジェクト内のサービス、プロジェクトネットワーク、名前付き Volume、ホストに割り当てられたポート
Compose プロジェクトの例:サービス名がホスト名になり、ports を設定したサービスだけがホストから接続できます

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日