- docker-composeって何?一言でいうと「複数コンテナを“1つのアプリ”としてまとめて起動・停止するリモコン」
- まずはイメージ:FastAPI + PostgreSQL を docker-compose で立ち上げる
- 重要ポイント1:services で「アプリを構成するコンテナ」を全部定義する
- 重要ポイント2:ネットワークは「サービス名でつながる」ことを理解する
- 重要ポイント3:環境変数とボリュームで「状態」と「設定」を外に出す
- 重要ポイント4:開発体験を良くするための docker-compose の使い方
- 重要ポイント5:docker-compose は「ローカルのミニ本番環境」を作る道具
- 初心者が docker-compose に慣れるためのステップ
- まとめ(docker-compose は「複数コンテナでできたアプリを、1つの YAML でまとめて扱うためのリモコン」)
docker-composeって何?一言でいうと「複数コンテナを“1つのアプリ”としてまとめて起動・停止するリモコン」
Docker は「1コンテナ=1プロセス」をきれいに動かすのが得意です。
でも、現実のアプリはだいたいこうなります。
Web アプリ(FastAPI / Django)
データベース(PostgreSQL / MySQL)
キャッシュ(Redis)
フロントエンド(別コンテナ)
これを毎回、個別に docker run で起動して、ネットワークをつないで…は正直しんどい。
そこで登場するのが docker-compose です。
docker-compose は、
「複数のコンテナ(サービス)を、1つの設定ファイル(YAML)で定義して、docker compose up 一発でまとめて起動・停止できる仕組み」
だと思ってください。
まずはイメージ:FastAPI + PostgreSQL を docker-compose で立ち上げる
例として動かすアプリのイメージ
シンプルな構成を想像します。
FastAPI アプリ(app/main.py)
PostgreSQL(DB)
ローカル開発で、これを docker-compose で動かしたいとします。
docker-compose.yml の最小例
こんな docker-compose.yml を考えます。
version: "3.9"
services:
web:
build: .
container_name: myapp-web
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://myuser:mypass@db:5432/mydb
depends_on:
- db
db:
image: postgres:16
container_name: myapp-db
environment:
- POSTGRES_USER=myuser
- POSTGRES_PASSWORD=mypass
- POSTGRES_DB=mydb
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
YAMLこれを置いておいて、プロジェクトルートで
docker compose up
とすると、
web コンテナ(FastAPI)
db コンテナ(PostgreSQL)
がまとめて立ち上がり、http://localhost:8000 にアクセスできるようになります。
重要ポイント1:services で「アプリを構成するコンテナ」を全部定義する
services は「このアプリに必要な部品の一覧」
services: の下に書くのは、「このアプリを動かすのに必要なコンテナたち」です。
先ほどの例だと、
web が FastAPI アプリdb が PostgreSQL
という役割です。
web には build: . と書いてあります。
これは「このディレクトリの Dockerfile を使ってイメージをビルドしてね」という意味です。
db には image: postgres:16 と書いてあります。
これは「公式の postgres:16 イメージをそのまま使う」という意味です。
docker-compose は、「自前のアプリ」と「既製品のミドルウェア」を一緒に定義して、
まとめて起動できるのが強みです。
depends_on で「起動順序の依存関係」を表現する
web の中に depends_on: - db と書いてあります。
これは、「web は db に依存している(db を先に起動してほしい)」という宣言です。
厳密には「db コンテナを先に起動する」だけで、「DB が完全に ready になるまで待つ」わけではありませんが、
少なくとも「DB がない状態で web だけ起動する」事故は防げます。
本格的に「DB が ready になるまで待つ」なら、アプリ側でリトライしたり、ヘルスチェックを使ったりしますが、
最初の一歩としては depends_on で十分です。
重要ポイント2:ネットワークは「サービス名でつながる」ことを理解する
db という名前がそのままホスト名になる
web の DATABASE_URL をもう一度見てみます。
environment:
- DATABASE_URL=postgresql://myuser:mypass@db:5432/mydb
YAMLここで @db:5432 と書いている db は、services.db の db と一致しています。
docker-compose では、同じ compose ファイル内のサービス同士は、
自動で同じネットワークに入り、サービス名で名前解決できるようになります。
つまり、
db というホスト名で PostgreSQL に接続できる
ポートはコンテナ内の 5432 をそのまま使う
という状態になります。
これが分かると、
「ローカルでは localhost:5432、本番では別ホスト…」みたいな切り替えを、
環境変数だけでうまく扱えるようになります。
重要ポイント3:環境変数とボリュームで「状態」と「設定」を外に出す
DB のデータはボリュームに逃がす
db の定義の中に、こうありました。
volumes:
- db-data:/var/lib/postgresql/data
YAMLこれは、「コンテナ内の /var/lib/postgresql/data を、db-data という名前のボリュームにマウントする」という意味です。
コンテナは基本「使い捨て」です。
コンテナを消すと、中のファイルも消えます。
でも、DB のデータは消えたら困ります。
そこで、「データだけはボリュームに逃がす」というパターンを使います。
volumes: の一番下で、
volumes:
db-data:
YAMLと定義しているのは、「名前付きボリューム db-data を作る」という宣言です。
これで、
コンテナを作り直しても
DB のデータはボリュームに残る
という状態になります。
環境変数で設定を渡す
db の中には、こういう環境変数があります。
environment:
- POSTGRES_USER=myuser
- POSTGRES_PASSWORD=mypass
- POSTGRES_DB=mydb
YAMLこれは、PostgreSQL の公式イメージが理解してくれる「初期設定用の環境変数」です。
docker-compose では、こうやって「設定値」を環境変数として渡すのが基本です。
パスワードなどの秘密情報は、本番では .env や Secrets で上書きするのがベストです。
重要ポイント4:開発体験を良くするための docker-compose の使い方
コードをコンテナにマウントしてホットリロードする
開発中は、コードを変えたらすぐ反映されてほしいですよね。
そのために、web にボリュームマウントを追加します。
services:
web:
build: .
ports:
- "8000:8000"
volumes:
- .:/app
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
depends_on:
- db
YAMLここでやっていることは、
.:/app で、ホストのカレントディレクトリをコンテナの /app にマウント--reload 付きで Uvicorn を起動(コード変更で自動リロード)
という開発用の設定です。
これで、
ホスト側で Python ファイルを編集
コンテナ内のアプリが自動リロード
ブラウザをリロードすると変更が反映
という快適な開発ループが作れます。
本番用 compose と開発用 compose を分ける
本番では、
--reload は使わない
コードはイメージに焼き込む(マウントしない)
dev 依存は入れない
など、開発とは違う要件になります。
そのために、
docker-compose.dev.yml(開発用)docker-compose.yml(本番用 or 共通)
のようにファイルを分けて、
開発時:
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
のように重ねて使う、というパターンもよくあります。
重要ポイント5:docker-compose は「ローカルのミニ本番環境」を作る道具
本番に近い構成をローカルで再現できる
docker-compose の一番おいしいところは、
「本番と似た構成を、ローカルで簡単に再現できる」
という点です。
本番:
Web(FastAPI)
DB(PostgreSQL)
Redis
Nginx(リバースプロキシ)
ローカル:
同じ4つを docker-compose で立ち上げる
こうしておくと、
「本番では動くのにローカルでは動かない」
「ローカルでは動くのに本番では動かない」
というギャップが減ります。
DevOps 的には、「ローカル・CI・本番の差を減らす」ことがめちゃくちゃ重要です。
docker-compose は、そのための強力な武器になります。
初心者が docker-compose に慣れるためのステップ
ステップ1:FastAPI + PostgreSQL の2コンテナ構成を compose で動かしてみる
まずは、さっきのようなシンプルな web + db 構成を実際に動かしてみる。docker compose up で立ち上げて、docker compose down で止める感覚を掴む。
ステップ2:コードマウント+--reload で「開発用 compose」を作る
volumes と command を使って、
「コードを変えたら即反映される」開発環境を compose で作ってみる。
ステップ3:本番を意識して「マウントなし・--reload なし」の構成も書いてみる
開発用と本番用で、
何を変えるべきか(マウント・コマンド・環境変数)を意識して書き分けてみる。
まとめ(docker-compose は「複数コンテナでできたアプリを、1つの YAML でまとめて扱うためのリモコン」)
初心者目線で整理すると、Python の docker-compose はこういうものです。
services: の下に Web アプリや DB などのコンテナを全部定義し、ネットワークや環境変数、ボリュームをまとめて設定して、docker compose up 一発で「ミニ本番環境」を立ち上げるための仕組み。
サービス名でお互いを参照できるネットワーク、ボリュームによるデータ永続化、環境変数による設定注入を組み合わせることで、「ローカル・CI・本番の構成差」を小さくしつつ、開発用(マウント+--reload)と本番用(イメージ固定・--reload なし)をうまく切り替えられるようになる。
