「開発用と本番用でビルド設定やログ設定だけ違うのに、サービス定義を丸ごと2重管理している」
そんな悩みを抱えたままcompose.ymlを運用しているチームは少なくありません。
Docker Composeには、共通のサービス定義を別ファイルに切り出し、複数のサービス・複数のプロジェクトから再利用できる
extendsという仕組みがあります。公式ドキュメントでの扱いが小さく、「override(環境別の設定上書き)」との違いを理解しないまま使うと、意図しない設定崩れを招くことがあります。
この記事では、extendsの基本構文から共通base定義を切り出す実践例、override(docker-compose.override.yml)との使い分け、設定が反映されない時のトラブルシュートまで、実サーバーの確認例を交えて解説します。
動作確認環境: Rocky Linux 9.4 / Ubuntu 24.04 LTS(Docker Engine 26.x・Docker Compose Plugin v2.27)
この記事のポイント
・extendsは共通のサービス定義を別ファイルに切り出し、複数サービス・複数プロジェクトから再利用する仕組み
・override(docker-compose.override.yml)は同一プロジェクト内の環境差分、extendsは共通化そのものが目的で役割が違う
・Composeのマージ規則では、ports・volumesなどのリスト項目は結合ではなく丸ごと置き換えになる点が事故の原因になりやすい
・docker compose configで結合後の設定を出力し、意図した内容にマージされているかを毎回確認するのが鉄則
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
extendsとは何か|Compose Specにおける共通設定の継承の仕組み
複数のマイクロサービスを1つのcompose.ymlで管理していると、ロギング設定やヘルスチェック、リスタートポリシーなど「どのサービスにも共通して書きたい項目」が増えていきます。これをサービスの数だけコピペしていると、設定変更のたびに全サービスを1つずつ直す必要が出てきて、修正漏れの温床になります。
1. なぜcompose.ymlが肥大化するのか
現場でよくあるのは、開発チームが増えるにつれてサービス数が10・20と増え、logging:やhealthcheck:、restart:といった定型ブロックがサービスごとに重複していくパターンです。1箇所を直し忘れると、本番だけログ設定が古いままになるといった実務上の事故につながります。
2. extends構文の基本形
extendsは、file:で参照先ファイル、service:で参照先サービス名を指定し、そのサービス定義をベースに継承します。# extendsの最小構文 services: web: extends: file: common-services.yml service: app-base ports: - "8080:80"
webサービスはcommon-services.yml内のapp-baseサービスの定義(イメージ・環境変数・ヘルスチェック等)を継承したうえで、ports:だけを自分で上書き追加します。extendsで共通base設定を複数サービスに継承する実践例
3. common-services.ymlに共通設定を切り出す
まず、複数サービスで共有したい設定だけを独立したファイルにまとめます。# common-services.yml(共通設定の置き場) services: app-base: image: myapp:latest environment: - TZ=Asia/Tokyo - LOG_LEVEL=info logging: driver: json-file options: max-size: "10m" max-file: "3" healthcheck: test: ["CMD", "curl", "-f", "http://localhost/healthz"] interval: 30s timeout: 5s retries: 3 restart: unless-stopped
app-baseを継承します。# compose.yml(本体:web/workerがapp-baseを継承する) services: web: extends: file: common-services.yml service: app-base ports: - "8080:80" worker: extends: file: common-services.yml service: app-base command: ["python", "worker.py"]
webとworkerは、ロギング設定(json-file・10MB×3世代)やヘルスチェック、リスタートポリシーを個別に書かずに共有できます。共通部分を1箇所に集約したことで、ログ設定を変更したい場合は
common-services.ymlを1回直すだけで両方に反映されます。4. docker compose configで継承結果を確認する
extendsは「マージ後の見えない設定」が増える仕組みなので、実際にどうマージされたかを都度確認する習慣が重要です。# 結合後の実効設定をYAMLで出力して確認する $ docker compose config services: web: environment: LOG_LEVEL: info TZ: Asia/Tokyo healthcheck: interval: 30s retries: 3 test: - CMD - curl - -f - http://localhost/healthz timeout: 5s image: myapp:latest logging: driver: json-file options: max-file: "3" max-size: 10m ports: - mode: ingress target: 80 published: "8080" restart: unless-stopped
docker compose configは本番投入前の確認作業として必ず実行すべきコマンドです。継承ミスや意図しない上書きは、ほとんどがこの1コマンドで事前に発見できます。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Docker Composeの設計・共通化をはじめとするDockerの実践スキルを体系的に学べる講座を用意しています。
→ Dockerマスター講座の詳細はこちら >>
extendsとoverride(compose.override.yml)の違いと使い分け
5. overrideは「環境差分」、extendsは「共通化」が目的
似たような仕組みに見えて、extendsとoverrideは目的がまったく違います。・override(docker-compose.override.ymlや-f複数指定):同一プロジェクトの中で「開発環境だけvolumesをbind mountにしたい」「本番だけレプリカ数を増やしたい」といった環境差分を後から重ねる仕組み
・extends:プロジェクトやファイルをまたいで「共通のベース定義」そのものを1箇所に集約し、複数サービスから参照する仕組み
overrideは「同じプロジェクトの縦の差分」、extendsは「複数サービス・複数プロジェクトの横の共通化」と整理すると混同しにくくなります。
6. 両方を組み合わせた設計パターン
実務では両者を併用するのが一般的です。共通のapp-base定義はextendsで集約し、環境ごとの差分はoverrideで重ねます。# compose.override.yml(本番のみポート・レプリカ数を変更する差分) services: web: ports: - "443:80" deploy: replicas: 3
# 本番環境ではoverrideファイルを明示的に指定して起動する $ docker compose -f compose.yml -f compose.override.yml up -d
トラブルシュート|extendsで設定が反映されない時の調査手順
7. 手順1: リストのマージではなく置き換えになっていないか疑う
extendsやoverrideでは、Compose全体のマージ規則が適用されます。environment:のようなマッピング(連想配列)はキー単位でマージされますが、ports:やvolumes:のようなリストは結合ではなく丸ごと置き換えになります。これに気づかず「継承元のvolumesも残るはず」と思い込んでいると、共通base側で定義したマウントがごっそり消えるという事故が起きます。
# app-base側のvolumes(共有ライブラリのマウント) services: app-base: volumes: - shared_lib:/opt/shared # web側でvolumesを追加したつもりが、実際は置き換わってしまう例 services: web: extends: file: common-services.yml service: app-base volumes: - ./web-static:/var/www/static # ← ここに shared_lib のマウントを書き足さないと消える
8. 手順2: docker compose config --servicesとpsで実際の反映状況を確認する
# 認識されているサービス一覧を確認(extends先のservice名の誤字はここで発覚しやすい) $ docker compose config --services web worker db # 起動中コンテナの実際のマウント・ポート状況を確認 $ docker compose ps --format "table {{.Name}}\t{{.Ports}}" NAME PORTS myapp-web-1 0.0.0.0:8080->80/tcp myapp-worker-1
9. 手順3: 参照ファイルのパスミスを疑う
extends.file:のパスは、それを記述しているcompose.ymlからの相対パスで解決されます。サブディレクトリに移動した際にパス指定を直し忘れると、以下のようなエラーで起動そのものが失敗します。
$ docker compose up -d service "web" refers to undefined service "app-base": could not find common-services.yml # 対処: extends.fileのパスを実際のディレクトリ構成に合わせて修正する extends: file: ../shared/common-services.yml service: app-base
10. よくある原因チェックリスト
・リスト項目の消失:ports・volumesなど継承元にあった設定が、継承側の同項目で丸ごと置き換わっていないか・service名の誤字:extends.serviceに指定した名前が参照先ファイル内のサービス名と一致しているか
・相対パスのズレ:extends.fileのパスが、compose.ymlの実際の配置場所から見て正しいか
・循環参照:AがBを継承し、BがAを継承するような循環構成になっていないか(Composeはこれを検出してエラーにする)
・本番反映前の未確認:docker compose configで実効設定を確認せずに本番へ
upしていないか本記事のまとめ
| やりたいこと | 使う仕組み・確認コマンド |
|---|---|
| 共通のサービス定義を複数サービスで使い回したい | 共通ファイルを作りextends.file/serviceで継承する |
| 開発・本番で一部だけ設定を変えたい | docker-compose.override.ymlや-f複数指定で重ねる |
| 継承後の実際の設定を確認したい | docker compose configで実効設定を出力する |
| 継承元のvolumes・portsが消えてしまう | リストは置き換えのため、継承側にも明示的に書き足す |
| extends先のファイルが見つからないと言われる | extends.fileの相対パスを配置場所に合わせて修正する |
一方で「リストは結合ではなく置き換え」というマージ規則を知らずに使うと、静かに設定が欠落する事故につながります。
本番へ反映する前に必ず
docker compose configで実効設定を確認する運用を、チームのルールとして定着させておきましょう。現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、本記事で紹介したDocker Composeの共通化・環境分離設計をさらに深く学べる講座を用意しています。
→ Dockerマスター講座の詳細はこちら >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:docker compose watchで開発環境のホットリロードを実現する方法|sync・rebuild・sync+restartの使い分けと実践設計
- この記事の属するカテゴリ:Dockerへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます