Docker Compose YAMLチュートリアル:マルチサービス環境を構築するための完全ガイド

現代のソフトウェア開発において、単一のアプリケーションが単一のコンテナで完結することは稀です。Webサーバー、データベース、キャッシュレイヤー、メッセージキュー、そしてフロントエンド。これら複数のコンテナが連携して初めて、一つのシステムとして機能します。これらの複雑なコンテナ群を、まるで一つのアプリケーションであるかのように一括で定義・管理するための強力なツールが「Docker Compose」です。

本記事では、Docker Compose YAMLチュートレアルとして、YAMLファイルの構造から、マルチサービス環境の構築、さらには実践的な運用テクニックまで、エンジニアが現場で即座に使える知識を深く掘り下げて解説します。


1. Docker Composeの基本概念とYAMLの役割

Docker Composeを理解するためには、まず「なぜ単一のdocker runコマンドでは不十分なのか」を理解する必要があります。

Docker Composeとは何か?

Docker Composeは、マルチコンテナのDockerアプリケーションを定義および実行するためのツールです。開発環境において、データベースのセットアップ、ネットワークの設定、ボリュームのマウントといった複雑な手順を、たった一つのコマンド(docker compose up)に集約できます。

なぜYAML形式が使われるのか?

Docker Composeの設定にはYAML(YAML Ain't Markup Language)が採用されています。YAMLは、人間にとっての読みやすさと、機械にとっての解析のしやすさを両立させたデータ形式です。階層構造(インデント)によって、サービスの依存関係やネットワーク構成を直感的に記述できるため、インフラの構成管理(IaC: Infrastructure as Code)において非常に優れた特性を持っています。

単一コンテナとマルチコンテナの違い

単一コンテナの運用では、コンテナが起動した後に手動でネットワークや環境変数を設定する必要があります。一方、マルチコンテナ環境では、コンテナ間の通信(Service Discovery)や、データの永続化、起動順序の制御が不可避です。Docker Composeは、これらの「コンテナ間の関係性」を宣言的に記述することに特化しています。

もし、コンテナの構成管理をさらに効率化したい場合は、Docker Composeの高度な活用術も併せて参照してください。


2. Docker Compose YAMLの基本構造と主要なプロパティ

YAMLファイル(通常はdocker-compose.yml)は、特定のスキーマに従って記述されます。主要なセクションとその役割をマスターしましょう。

services:サービス定義の核心

servicesセクションは、Composeファイルの中で最も重要な部分です。ここで、起動したい各コンテナ(サービス)を定義します。各サービスには、使用するイメージやビルド手順、ポートマッピングなどの設定を記述します。

networks:ネットワーク構成の定義

複数のコンテナが互いに通信するためには、共通のネットワークが必要です。networksセクションを使用することで、特定のサービス間のみが通信可能な隔離されたネットワークを作成できます。これにより、セキュリティの向上と名前解決の簡略化が実現します。

volumes:データの永続化

コンテナは「使い捨て」が基本ですが、データベースのデータなどは消えては困ります。volumesセクションでは、ホストマシン上のディレクトリや、Dockerが管理する名前付きボリュームをコンテナ内にマウントする設定を行います。

主要なプロパティ一覧

プロパティ名 役割 説明
image イメージの指定 Docker Hubなどから取得するベースイメージを指定。
build ビルドコンテキスト Dockerfileを使用して独自のイメージを作成する際のパスを指定。
ports ポートマウント ホストポート:コンテナポートの形式で通信経路を公開。
environment 環境変数 コンテナ内部で使用する環境変数を設定。
depends_on 起動順序の制御 どのサービスが先に起動すべきかを定義。
volumes ボリューム設定 データの永続化やソースコードの同期に使用。

3. 実践チュートリアル:Webアプリ、DB、Redisの3層構造を構築する

それでは、実際に「Python (Flask) + PostgreSQL + Redis」という、モダンなWebアプリケーションの構成を構築する手順を見ていきましょう。

プロジェクトのディレクトリ構成

まず、以下のようなディレクトリ構造を想定します。

my-project/
├── docker-compose.yml
├── .env
├── app/
│   ├── Dockerfile
│   ├── main.py
│   └── requirements.txt
└── data/ (PostgreSQLのデータ保存用)

docker-compose.yml の詳細解説

以下に、本チュートリアルの核となるYAMLファイルの内容を示します。

version: '3.8'  # Docker Composeのファイル形式バージョン

services:
  # 1. Webアプリケーション・サービス
  web:
    build: ./app          # ./appディレクトリのDockerfileを使用
    ports:
      - "5000:5000"        # ホストの5000番をコンテナの5000番に接続
    environment:
      - FLASK_ENV=development
      - DATABASE_URL=postgresql://user:password@db:5432/myapp
      - REDIS_HOST=redis
    depends_on:
      - db                 # dbサービスが起動した後に起動
      - redis               # redisサービスが起動した後に起動
    volumes:
      - ./app:/app         # ソースコードを同期(ホットリロード用)

  # 2. データベース・サービス (PostgreSQL)
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTANC_PASSWORD: password
      POSTGRES_DB: myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data  # データの永続化
    networks:
      - backend-network

  # 3. キャッシュ・サービス (Redis)
  redis:
    image: redis:7-alpine
    networks:
      - backend-network

# ネットワークの定義
networks:
  backend-network:
    driver: bridge

# ボリュームの定義
volumes:
  postgres_data:

コードのポイント解説

  1. build: ./app: imageを指定する代わりに、ローカルのDockerfileからイメージを生成します。これにより、独自の依存関係を持つアプリを簡単にコンテナ化できます。
  2. depends_on: webサービスが、dbとredisが立ち上がった後に起動するように制御しています。ただし、注意点として「コンテナが起動したこと」は保証しますが、「DBの準備(初期化)が完了したこと」までは保証しません。
  3. volumes (Named Volume): postgres_dataという名前付きボリュームを使用しています。これにより、docker compose downでコンテナを削除しても、データベースの内容は保持されます。
  4. networks: webサービスはデフォルトのネットワークに参加していますが、dbとredisはbackend-networkに所属させています。これにより、外部(ホスト)からDBに直接アクセスされるリスクを減らし、サービス間通信をセキュアに保ちます。

4. 高度な設定:環境変数、ボリューム、ネットワークの最適化

基本をマスターしたら、次はプロフェッショナルな運用に不可欠な「管理の自動化」について学びましょう。

.env ファイルによる環境変数の管理

YAMLファイル内にパスワードやAPIキーを直接記述することは、セキュリティ上極めて危険です。Docker Composeは、同じディレクトリにある.envファイルを自動的に読み込む機能を持っています。

.env ファイルの例:

POSTGSAGRES_PASSWORD=super_secret_password
APP_PORT=5000

docker-compose.yml での利用:

services:
  web:
    ports:
      - "${APP_PORT}:5000"

このように記述することで、環境ごとに設定を切り替えることが容易になります。

ボリュームマウントによる開発効率の向上

開発フェーズでは、ホストマシンのソースコードをコンテナ内のディレクトリにマウント(Bind Mount)することが重要です。これにより、エディタでコードを書き換えた瞬間に、コンテナ内のアプリケーションに反映(ホットリロード)され、再ビルドの手間を大幅に削減できます。

ネットワーク分離によるセキュリティ強化

大規模な構成では、frontend-network(Webサーバーとロードバランサー用)とbackend-network(WebサーバーとDB用)のように、ネットワークを分離することを検討してください。これにより、万が一Webサーバーが侵害された際、攻撃者がデータベースネットワークへ直接アクセスすることを防ぐ「防御層」を構築できます。

さらに、より高度なインフラ構築の知識が必要な場合は、Super Toolsのデベロッパー向けツール集を活用して、効率的な開発環境を構築しましょう。


5. Docker Composeの運用とデバッグのテクニック

コンテナが動かない、あるいは意図した通りに動かない。そんな時に役立つ運用スキルを身につけましょう。

よく使うコマンド集

コマンド 説明
docker compose up -d バックグラウンド(デタッチモード)で全サービスを起動。
docker compose ps 現在稼働中のサービス一覧とステータスを表示。
cam docker compose logs -f [service] 特定のサービスのログをリアルタイムで監視。
docker compose exec [service] bash 稼働中のコンテナ内に入って直接コマンドを実行。
docker compose down コンテナ、ネットワーク、イメージを停止・削除。
docker compose build --no-cache キャッシュを使わずにイメージを再ビルド。

コンテナのトラブルシューティング方法

  1. ログの確認: ほとんどのトラブルはdocker compose logsで解決します。特に、DBの接続エラー(Connection Refused)は、depends_onの依存関係や、環境変数のDATABASE_URLの間違いが原因であることが多いです。
  2. ネットワークの疎通確認: docker compose exec web ping db のように、コンテナ内から他のサービスに対してネットワーク疎通があるかを確認します。
  3. ボリュームの確認: データが消えた場合は、ボリュームが正しくマウントされているか、docker volume inspect で確認してください。

FAQ(よくある質問)

Q1: depends_on を設定していれば、DBの準備が完了した後にアプリが起動しますか?

A: いいえ、depends_on は「コンテナの起動順序」を制御するだけで、「アプリケーション(DBプロセス)の準備完了」までは保証しません。DBの初期化には時間がかかることがあるため、アプリ側でリトライロジック(Wait-for-itスクリプトなど)を実装するのがベストプラクティスです。

Q2: docker compose down をすると、作成したデータも消えてしまいますか?

A: volumes で定義した「名前付きボリューム(Named Volume)」を使用している場合、データは保持されます。しかし、ホストのディレクトリを直接マウントしている「バインドマウント」の場合、ホスト側のファイルが書き換わります。

Q3: docker-compose.yml のバージョン(version: '3.8')は何を指定すべきですか?

A: 使用しているDocker Engineのバージョンに依存します。最新のDocker Desktopを使用している場合は、最新のスキーマに従うのが一般的です。最近のDocker Compose V2では、バージョン指定自体が非推奨(省略可能)になりつつあります。

Q4: 複数のプロジェクトで同じポート(例: 80番)を使いたい場合はどうすればいいですか?

A: ホスト側のポートを変更してください。ports: ["8080:80"] のように記述すれば、ホストの8080番ポートでアクセス可能になります。

Q5: .env ファイルに機密情報を書いて、GitHubにプッシュしても大丈夫ですか?

A: 絶対に避けてください。 .env ファイルは .gitignore に追加し、公開リポジトリには含めないようにしましょう。代わりに .env.example というテンプレートファイルを用意して、構造だけを共有するのが一般的です。

Q6: 開発環境と本番環境で docker-compose.yml を分けるべきですか?

A: はい、推奨されます。docker-compose.yml(基本構成)に加え、docker-compose.override.yml(開発用の上書き設定)を使用することで、本番環境では不要なボリュームマウントやデバッグツールを除外した、クリーンな構成を実現できます。


まとめ

Docker Compose YAMLチュートリアルを通じて、マルチサービス環境を構築するための基礎から応用までを解説してきました。

YAMLファイルは単なる設定ファイルではなく、システムの設計図(Blueprint)です。サービス間の依存関係、ネットワークの分離、データの永続化、環境変数の管理を適切に記述することで、誰でも(そしてどのCI/CDツールでも)再現可能な、堅牢な開発・運用環境を構築できます。

まずは、今回紹介した3層構造のテンプレートを自分のプロジェクトに適用することから始めてみてください。コンテナのオーケストレーションをマスターすることは、モダンなインフラエンジニアリングへの第一歩となります。