Docker Composeで3層アーキテクチャを構築しよう
このハンズオンでは、前の講座で個別に起動していたノートアプリケーションを、Docker Composeを使って一括管理する方法について実際にハンズオン形式で手を動かしながら体験します。
- Docker Composeによる複数コンテナの一括管理
- compose.yamlでの3層構造の定義
- depends_onによる起動順序の制御
- ボリュームによるデータ永続化
- 初期化SQLの自動実行
1. 事前準備
Gitの基礎知識を習得していることを前提とします。自信のない方は先に以下の講座を実施してください。
この講座のハンズオンでは、以下のツールやアカウントが必要です。まだ準備できていない場合は、リンク先の手順に沿って準備をお願いします。
2. 前の講座との違い
前の講座「Dockerで3層アーキテクチャを構築しよう」では、3つのコンテナを個別のコマンドで起動しました。MySQLコンテナを起動し、テーブルを手動で作成し、APIコンテナをビルドして起動し、ネットワークに接続し、フロントコンテナをビルドして起動する...という多くの手順が必要でした。
Docker Composeを使うと、これらの手順をcompose.yamlファイルに記述し、docker compose upコマンド1つで全てのコンテナを起動できます。
3. ハンズオンの概要
このハンズオンでは、前の講座で作成したノートアプリケーションと同じ構成を、Docker Composeで構築します。
3.1 構成図
このハンズオンで構築する3層アーキテクチャの全体像を以下に示します。
flowchart LR
User[ユーザ<br>ブラウザ] --> Front
subgraph DockerCompose[Docker Compose]
Front[front<br>Nginx<br>:3000] --> API[api<br>FastAPI<br>:8000]
API --> DB[(db<br>MySQL<br>:3306)]
DB --- Volume[(db-data<br>ボリューム)]
end
| 💡 ポイント |
|---|
| このハンズオンでは、PythonやNginxをローカルにインストールする必要はありません。すべての処理はDockerコンテナ内で行われます。Docker Composeは、Docker Desktopに含まれているため、別途インストールする必要もありません。 |
4. プロジェクトの準備
4.1 サンプルリポジトリのクローン
このハンズオンで使用するノートアプリケーションのソースコードは、GitHubのサンプルリポジトリに用意しています。コマンドプロンプト(Windows)またはターミナル(Mac)を開き、任意の場所で以下のコマンドを実行します。
git clone https://github.com/gevanni-academy/sample-note-api.git
クローンが完了したら、Visual Studio Codeを起動し、「ファイル」→「フォルダーを開く」から、クローンしたsample-note-apiフォルダを開いてください。以降の操作は、Visual Studio Codeのターミナルから行います。
4.2 フォルダ構成の確認
クローンしたリポジトリのフォルダ構成は以下のようになっています。
sample-note-api
├── compose.yaml
├── api/
│ ├── Dockerfile
│ ├── main.py
│ ├── models.py
│ ├── database.py
│ ├── requirements.txt
│ └── routers/
│ └── notes.py
├── front/
│ ├── Dockerfile
│ ├── index.html
│ ├── style.css
│ └── script.js
└── db/
└── init.sql
各フォルダは3層アーキテクチャの各層に対応しています。
| フォルダ | 層 | 内容 |
|---|---|---|
| db/ | データベース層 | init.sql(テーブル作成・テストデータ投入用の初期化SQL) |
| api/ | アプリケーション層 | FastAPIのソースコード、Dockerfile、requirements.txt |
| front/ | プレゼンテーション層 | HTML/CSS/JavaScriptのフロントエンド、Nginx用のDockerfile |
そして、プロジェクトのルートにcompose.yamlがあります。このファイルがDocker Composeの設定ファイルで、3つのサービスの構成をまとめて定義しています。
| 💡 ポイント |
|---|
| PythonやFastAPIの詳しい説明は省略します。コードの詳細については「PythonでREST APIを作ろう」講座に記載があります。この講座では、Docker Composeの設定と使い方に集中します。 |
5. compose.yamlの解説
compose.yamlを開いてみましょう。以下の内容が記述されています。
services:
# データベース層
db:
image: mysql:8.0
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: notedb
MYSQL_USER: noteuser
MYSQL_PASSWORD: notepass
volumes:
- db-data:/var/lib/mysql
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-prootpass"]
interval: 10s
timeout: 5s
retries: 5
# アプリケーション層
api:
build: ./api
ports:
- "8000:8000"
environment:
DB_HOST: db
DB_USER: noteuser
DB_PASSWORD: notepass
DB_NAME: notedb
depends_on:
db:
condition: service_healthy
# プレゼンテーション層
front:
build: ./front
ports:
- "3000:80"
depends_on:
- api
volumes:
db-data:
各設定について解説します。
5.1 servicesセクション
servicesセクションには、起動する3つのコンテナを定義しています。
| サービス名 | 役割 | 説明 |
|---|---|---|
| db | データベース層 | MySQLコンテナ。ノートデータを永続化する |
| api | アプリケーション層 | FastAPIコンテナ。REST APIを提供する |
| front | プレゼンテーション層 | Nginxコンテナ。ノート管理画面を表示する |
5.2 dbサービスの設定
db:
image: mysql:8.0
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: notedb
MYSQL_USER: noteuser
MYSQL_PASSWORD: notepass
volumes:
- db-data:/var/lib/mysql
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-prootpass"]
interval: 10s
timeout: 5s
retries: 5
各設定を解説します。
image: mysql:8.0
imageで使用するDockerイメージを指定しています。ここではMySQLの公式イメージのバージョン8.0を使用します。
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: notedb
MYSQL_USER: noteuser
MYSQL_PASSWORD: notepass
environmentで、MySQLコンテナの初期設定に必要な環境変数を指定しています。MYSQL_DATABASEを指定すると、コンテナ初回起動時にそのデータベースが自動的に作成されます。MYSQL_USERとMYSQL_PASSWORDで、アプリケーションがデータベースに接続するためのユーザを作成しています。
volumes:
- db-data:/var/lib/mysql
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
volumesで、コンテナ内のデータをホスト側に保存する設定をしています。1行目のdb-data:/var/lib/mysqlは、MySQLのデータを名前付きボリュームに保存することで、コンテナを削除してもデータが失われないようにしています。2行目は、db/init.sqlをMySQLの初期化ディレクトリにマウントしています。これにより、コンテナ初回起動時にテーブル作成とテストデータ投入が自動で実行されます。
| 📝 MySQLの初期化スクリプトについて |
|---|
MySQLの公式イメージは、コンテナ初回起動時に/docker-entrypoint-initdb.d/ディレクトリ内のSQLファイルを自動的に実行します。この仕組みを利用することで、テーブル作成やデータ投入を自動化できます。 |
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-prootpass"]
interval: 10s
timeout: 5s
retries: 5
healthcheckは、コンテナの状態を定期的に確認するための設定です。mysqladmin pingコマンドを使って、MySQLが正常に応答するかをチェックしています。MySQLは起動に時間がかかるため、この設定がないと後述するAPIサーバがデータベース接続に失敗することがあります。
5.3 apiサービスの設定
api:
build: ./api
ports:
- "8000:8000"
environment:
DB_HOST: db
DB_USER: noteuser
DB_PASSWORD: notepass
DB_NAME: notedb
depends_on:
db:
condition: service_healthy
各設定を解説します。
build: ./api
buildで、Dockerイメージをビルドするディレクトリを指定しています。./apiディレクトリ内のDockerfileをもとにイメージが作成されます。
ports:
- "8000:8000"
portsで、ホストの8000番ポートをコンテナの8000番ポートに転送しています。これにより、ブラウザからhttp://localhost:8000でAPIにアクセスできるようになります。
environment:
DB_HOST: db
DB_USER: noteuser
DB_PASSWORD: notepass
DB_NAME: notedb
environmentで、APIがデータベースに接続するための情報を環境変数として渡しています。DB_HOSTにはdbというサービス名を指定しています。Docker Composeでは、同じネットワーク内のサービス同士はサービス名で通信できるため、IPアドレスではなくサービス名を使います。
depends_on:
db:
condition: service_healthy
depends_onで、サービスの起動順序を制御しています。condition: service_healthyを指定することで、dbサービスのhealthcheckが成功するまでAPIの起動を待機させています。これにより、MySQLが完全に起動してからAPIが接続を試みるようになります。
5.4 frontサービスの設定
front:
build: ./front
ports:
- "3000:80"
depends_on:
- api
各設定を解説します。
build: ./front
buildで、./frontディレクトリのDockerfileからフロントエンド用のイメージをビルドします。
ports:
- "3000:80"
portsで、ホストの3000番ポートをコンテナの80番ポートに転送しています。Nginxはコンテナ内で80番ポートで動作するため、ブラウザからはhttp://localhost:3000でアクセスできるようになります。
depends_on:
- api
depends_onで、apiサービスが起動してからフロントエンドを起動するように順序を指定しています。
5.5 volumesセクション
volumes:
db-data:
db-dataという名前付きボリュームを定義しています。このボリュームにMySQLのデータが保存されるため、コンテナを削除してもデータは保持されます。
6. アプリケーションの起動
6.1 サービスの一括起動
Visual Studio Codeのターミナルを開き、Docker Composeでサービスを起動します。
docker compose up -d --build
| オプション | 説明 |
|---|---|
| -d | バックグラウンドでコンテナを起動するため |
| --build | イメージを(再)ビルドするため。初回起動時やソースコードを変更した場合に使用 |
初回起動時は、イメージのビルドに時間がかかります。
| 💡 ポイント |
|---|
docker compose up -d --buildの1コマンドで、3つのコンテナすべてが起動します。前の講座では、各コンテナを個別に起動し、ネットワークを作成して接続する必要がありましたが、Docker Composeではこれらの操作が自動的に行われます。 |
6.2 起動状況の確認
サービスの状態を確認します。
docker compose ps
すべてのサービスがrunningまたはhealthy状態になっていれば成功です。
NAME IMAGE STATUS
sample-note-api-api-1 sample-note-api-api Up
sample-note-api-db-1 mysql:8.0 Up (healthy)
sample-note-api-front-1 sample-note-api-front Up
| ⚠️ サービスが起動しない場合 |
|---|
docker compose logs サービス名でエラーログを確認してください。よくある問題として、以下のものがあります。・ dbサービスがhealthyにならない → MySQLの起動に時間がかかっています。1分程度待ってから再度docker compose psを実行してください。・ apiサービスがすぐに終了する → docker compose logs apiでエラーを確認してください。・ frontサービスがビルドに失敗する → docker compose logs frontでエラーを確認してください。 |
6.3 ログの確認
全サービスのログをリアルタイムで確認できます。
docker compose logs -f
以下のようなログが表示されていれば、各サービスが正常に起動しています。
db:ready for connectionsと表示され、MySQLが接続を受け付ける状態になっているapi:Uvicorn running on http://0.0.0.0:8000と表示され、APIサーバが起動しているfront:start worker processと表示され、Nginxが起動している
Ctrl+Cでログの表示を終了します。
特定のサービスのログだけを確認したい場合は、サービス名を指定します。例えば、APIサーバのログだけを確認するには以下を実行します。
docker compose logs api
以下のようにUvicorn running on http://0.0.0.0:8000と表示されていれば、APIサーバが正常に起動しています。
sample-note-api-api-1 | INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
7. 動作確認
7.1 ブラウザでアクセス
Webブラウザを開き、以下のURLにアクセスします。
http://localhost:3000
「ノートアプリ」というページが表示され、init.sqlで登録した初期データのノートが一覧表示されれば成功です。

7.2 機能の確認
ノートアプリの各機能が正しく動作するか確認していきます。
まず、「新規ノート」欄にタイトルと内容を入力し、「追加」ボタンをクリックしてください。

一覧に新しいノートが追加されれば、フロントエンドからAPIを経由してデータベースへの書き込みが正常に行われています。

次に、ノートの「詳細」ボタンをクリックしてください。

ノートの全文と作成日・更新日が表示されれば、データベースからの読み取りが正常に動作しています。

続いて、「編集」ボタンをクリックしします。

タイトルや内容を変更して保存してください。

変更内容が反映されれば、更新処理が正常に動作しています。

最後に、「削除」ボタンをクリックしてください。

ノートが一覧から消えれば、削除処理も正常です。

これらの操作がすべて動作すれば、3層アーキテクチャ(フロントエンド → API → データベース)の連携が正しく構成されています。
7.3 APIの直接確認
Visual Studio Codeのターミナルから、APIサーバに直接リクエストを送信して確認することもできます。
curl http://localhost:8000/notes
以下のように、ノートの一覧がJSON形式で返ってくれば、APIサーバが正常に動作しています。
[{"title":"Meeting Notes","content":"Next meeting is on Monday. Need to prepare documents.","id":3,"created_at":"2025-01-01T00:00:00","updated_at":"2025-01-01T00:00:00"},{"title":"Shopping List","content":"Milk, Eggs, Bread, Coffee Beans","id":2,"created_at":"2025-01-01T00:00:00","updated_at":"2025-01-01T00:00:00"},{"title":"Docker Compose Notes","content":"Docker Compose manages multiple containers. Define services in compose.yaml.","id":1,"created_at":"2025-01-01T00:00:00","updated_at":"2025-01-01T00:00:00"}]
8. 前の講座との比較
前の講座(手動操作)と本講座(Docker Compose)の手順を比較してみましょう。
| 操作 | 手動操作 | Docker Compose |
|---|---|---|
| ネットワーク作成 | docker network create |
自動作成 |
| イメージビルド | コンテナごとにdocker image build |
自動ビルド |
| コンテナ起動 | コンテナごとにdocker container run |
docker compose up -d --build |
| ネットワーク接続 | コンテナごとにdocker network connect |
自動接続 |
| テーブル作成 | 手動でSQLを実行 | init.sqlで自動実行 |
| 停止・削除 | docker container stop + rm + network rm |
docker compose down |
このように、Docker Composeを使うことで、複雑な手順をcompose.yamlに定義し、1つのコマンドで実行できるようになります。
9. 不要リソースの削除
ハンズオンが終わったら、作成したリソースを削除します。
9.1 サービスの停止と削除
Visual Studio Codeのターミナルから、Docker Composeで起動したすべてのサービスを停止し、コンテナ、ネットワーク、ボリューム、イメージをまとめて削除します。
docker compose down -v --rmi all
| オプション | 説明 |
|---|---|
| -v | ボリュームも削除する |
| --rmi all | ビルドしたイメージも削除する |
以下のように、各リソースが削除されたことが表示されれば成功です。
[+] Running 4/4
✔ Container sample-note-api-front-1 Removed
✔ Container sample-note-api-api-1 Removed
✔ Container sample-note-api-db-1 Removed
✔ Network sample-note-api_default Removed
✔ Volume sample-note-api_db-data Removed
| 💡 ポイント |
|---|
-vオプションを付けないと、db-dataボリュームは残ります。これにより、次回docker compose upしたときに前回のデータが復元されます。完全にクリーンな状態に戻したい場合は、-vオプションを付けてください。 |
9.2 削除の確認
コンテナが削除されたことを確認します。
docker compose ps
以下のようにヘッダ行のみが表示され、コンテナが1つも表示されなければ削除完了です。
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
次に、ネットワークが削除されたことを確認します。
docker network ls
表示されたネットワーク一覧にsample-note-api_defaultが含まれていなければ、ネットワークも正常に削除されています。
最後に、イメージが削除されたことを確認します。
docker image ls
表示された一覧にsample-note-api-api、sample-note-api-front、mysqlが含まれていなければ、イメージも正常に削除されています。
9.3 プロジェクトフォルダの削除(任意)
クローンしたプロジェクトフォルダが不要な場合は、Visual Studio Codeでフォルダを閉じた後、エクスプローラー(Windows)やFinder(Mac)からsample-note-apiフォルダを削除してください。
10. まとめ
このハンズオンでは、Docker Composeを使って3層アーキテクチャのアプリケーションを構築する方法を体験しました。
- Docker Composeを使うと、複数のコンテナを
compose.yamlファイルで一括管理できる - compose.yamlには、services、volumes、networksなどの設定を記述する
- depends_onとhealthcheckを組み合わせることで、サービスの起動順序を適切に制御できる
- 初期化SQLを
/docker-entrypoint-initdb.d/にマウントすることで、データベースのセットアップを自動化できる docker compose up -d --buildで一括起動、docker compose downで一括停止ができる- 個別のコマンドを実行する方法と比べて、操作が大幅に簡略化される