Python | DevOps・運用:docker-compose

Python Python
スポンサーリンク
  1. docker-composeって何?一言でいうと「複数コンテナを“1つのアプリ”としてまとめて起動・停止するリモコン」
  2. まずはイメージ:FastAPI + PostgreSQL を docker-compose で立ち上げる
    1. 例として動かすアプリのイメージ
    2. docker-compose.yml の最小例
  3. 重要ポイント1:services で「アプリを構成するコンテナ」を全部定義する
    1. services は「このアプリに必要な部品の一覧」
    2. depends_on で「起動順序の依存関係」を表現する
  4. 重要ポイント2:ネットワークは「サービス名でつながる」ことを理解する
    1. db という名前がそのままホスト名になる
  5. 重要ポイント3:環境変数とボリュームで「状態」と「設定」を外に出す
    1. DB のデータはボリュームに逃がす
    2. 環境変数で設定を渡す
  6. 重要ポイント4:開発体験を良くするための docker-compose の使い方
    1. コードをコンテナにマウントしてホットリロードする
    2. 本番用 compose と開発用 compose を分ける
  7. 重要ポイント5:docker-compose は「ローカルのミニ本番環境」を作る道具
    1. 本番に近い構成をローカルで再現できる
  8. 初心者が docker-compose に慣れるためのステップ
    1. ステップ1:FastAPI + PostgreSQL の2コンテナ構成を compose で動かしてみる
    2. ステップ2:コードマウント+--reload で「開発用 compose」を作る
    3. ステップ3:本番を意識して「マウントなし・--reload なし」の構成も書いてみる
  9. まとめ(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 という名前がそのままホスト名になる

webDATABASE_URL をもう一度見てみます。

environment:
  - DATABASE_URL=postgresql://myuser:mypass@db:5432/mydb
YAML

ここで @db:5432 と書いている db は、
services.dbdb と一致しています。

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」を作る

volumescommand を使って、
「コードを変えたら即反映される」開発環境を compose で作ってみる。

ステップ3:本番を意識して「マウントなし・--reload なし」の構成も書いてみる

開発用と本番用で、
何を変えるべきか(マウント・コマンド・環境変数)を意識して書き分けてみる。


まとめ(docker-compose は「複数コンテナでできたアプリを、1つの YAML でまとめて扱うためのリモコン」)

初心者目線で整理すると、Python の docker-compose はこういうものです。

services: の下に Web アプリや DB などのコンテナを全部定義し、ネットワークや環境変数、ボリュームをまとめて設定して、docker compose up 一発で「ミニ本番環境」を立ち上げるための仕組み。
サービス名でお互いを参照できるネットワーク、ボリュームによるデータ永続化、環境変数による設定注入を組み合わせることで、「ローカル・CI・本番の構成差」を小さくしつつ、開発用(マウント+--reload)と本番用(イメージ固定・--reload なし)をうまく切り替えられるようになる。

タイトルとURLをコピーしました