docker compose upでアプリが動いた── だがそれは「開発で動く」段階だ.本番で落ちず,再起動に耐え,安全に更新できるcompose設定は,もう一段の作り込みが要る.

本番運用のcomposeには,自動復帰・ヘルスチェック・秘密情報の分離・リソース制限・安全なデプロイといった定番パターンがある.これらを知っているかどうかで,サービスの安定性は大きく変わる.

この記事は,VPSでdocker composeを使ってサービスを公開する個人開発者に向けている.開発用composeを「本番で安定稼働するcompose」へ引き上げる実践パターンを,具体的な設定で解説する.

読み終えたとき,あなたのcomposeはサーバー再起動後も自動復帰し,壊れたコンテナを検知し,安全に更新できる本番品質になっている.

なぜ本番用composeは作り込みが要るのか

開発用composeは「今動けばよい」が,本番は「落ちない・再起動に耐える・安全に更新できる・原因を追える」が求められる.これらは明示的に設定しないと得られない.

たとえばrestartポリシーを設定しなければ,VPS再起動やクラッシュでコンテナは止まったままになる.ヘルスチェックがなければ,「起動はしたが中身は壊れている」状態を検知できない.

また秘密情報をcompose.ymlに直書きすれば,Gitに漏れる事故につながる.リソース制限がなければ,1つのコンテナがメモリを食い尽くして全体を巻き込む.

これらの定番パターンを押さえることが,個人開発のサービスを「趣味の動作」から「安定したサービス」へ引き上げる条件になる.

restartポリシー ― 落ちても再起動に耐える

本番composeの基本中の基本がrestartポリシーだ.これを設定しないと,クラッシュやVPS再起動でコンテナが止まったままになる.

restartポリシーの設定

services:
  api:
    image: myapi
    restart: always        # 常に再起動(VPS再起動後も復帰)
  db:
    image: postgres:16
    restart: always
挙動
no再起動しない(既定)
always常に再起動(本番常駐の基本)
unless-stopped手動停止時以外は再起動
on-failure異常終了時のみ再起動

本番で常駐させるサービスはalwaysまたはunless-stoppedが基本だ.これでVPSを再起動しても,Dockerデーモンの起動とともにコンテナが自動で立ち上がる.「再起動したらサービスが止まっていた」を防ぐ最重要設定だ.

ヘルスチェックと依存制御 ― 「起動」と「使える」は違う

コンテナが「起動した」ことと「リクエストを処理できる」ことは別だ.特にDBは,プロセスが立ち上がってから接続を受け付けるまでに時間がかかる.ヘルスチェックでこれを検知する.

ヘルスチェックと依存(DB起動待ち)

services:
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 3s
      retries: 5
  api:
    image: myapi
    depends_on:
      db:
        condition: service_healthy   # DBが正常になってから起動

depends_oncondition: service_healthyを付けると,DBがヘルスチェックを通って初めてアプリが起動する.これにより「DBがまだ準備できていないのにアプリが接続を試みて失敗」という起動時の競合を防げる.単なるdepends_onは起動順を制御するだけで「準備完了」は待たない点に注意.

環境変数と秘密情報の分離 ― .envとenv_file

秘密情報(DBパスワード・APIキー)をcompose.ymlに直書きしてはいけない.Gitに漏れる事故の温床だ..envファイルに分離し,リポジトリから除外する.

.envへの分離

# .env (.gitignoreに追加)
DB_PASSWORD=強くて長いパスワード
API_KEY=sk-xxxx

# compose.yml
services:
  api:
    env_file: .env
  db:
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}   # .envから展開

.env.gitignoreに必ず追加する.より厳格にするならDocker secrets(ファイルとして安全に渡す仕組み)も使えるが,個人開発では.env.gitignore+適切なファイル権限(600)で十分なことが多い(シークレット管理の記事も参照).

リソース制限 ― 1コンテナの暴走を全体に波及させない

1つのコンテナがメモリやCPUを食い尽くすと,同居する他のコンテナやVPS全体を巻き込んで不安定になる.リソース制限で「暴走の隔離」をしておく.

メモリ・CPUの制限

services:
  api:
    image: myapi
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "0.5"

メモリ制限を設けると,そのコンテナがリークしても上限で止まり(OOMで該当コンテナだけ再起動),VPS全体の巻き添えを防げる.1台に複数サービスを同居させるほど,この隔離は重要になる.制限値は実測しながら調整する.

安全なデプロイ更新 ― ダウンタイムを最小化する

本番の更新は,「イメージをpull/build → 入れ替え」の手順だ.ただし素朴にやると一瞬のダウンが出る.個人開発で許容できる範囲なら,シンプルな手順で十分なことが多い.

デプロイ更新の基本手順

# コードを取得しイメージを再ビルドして入れ替え
git pull origin main
docker compose pull            # 外部イメージの更新
docker compose up -d --build   # 変更のあるコンテナだけ再作成
docker image prune -f          # 古いイメージを掃除

up -d --build変更のあったコンテナだけを再作成し,変わっていないものはそのまま動かす.DBは再作成されないのが普通だ.より無停止に近づけたいなら,前段のリバースプロキシ+複数レプリカでローリング更新する構成もあるが,個人開発はまずこのシンプル手順+デプロイ前スナップショットで十分実用的だ.

ログ管理 ― composeでログを溢れさせない

コンテナのログは放置するとディスクを食い尽くす.composeでログのローテーション(サイズ上限と世代数)を設定しておく.

ログのサイズ上限設定

services:
  api:
    image: myapi
    logging:
      driver: json-file
      options:
        max-size: "10m"     # 1ファイル10MBで分割
        max-file: "3"       # 3世代保持

この設定が無いと,コンテナのログが無制限に肥大化し,ある日ディスク満杯でサービスが止まる(ログ管理の記事も参照).max-sizemax-fileでサイズを制御するのは,本番composeの必須設定の一つだ.

補論:本番composeは「戻せる・余裕のある」VPSで安定する

本番composeの安定は,設定の作り込みと,それを支えるVPSの余裕の両輪だ.複数コンテナ+ヘルスチェック+リソース制限を回すには,メモリとディスクの余裕が要る.そしてデプロイ更新には「失敗したら戻せる」安心が要る.

高速NVMe・50種類以上のOSテンプレートに対応した国内VPS─シン・VPS─ はメモリをスケールアップで増やせ,NVMe SSDでビルドやイメージpullが軽快だ.スナップショットでデプロイ更新の前に丸ごと退避できるため,「up -d –buildで壊れたら即戻す」という安全なデプロイ運用がしやすい.本番composeの土台に向く.

サービスは独自ドメイン+HTTPSで公開するのが基本だ.取り扱い400種類以上のドメイン取得サービス─ムームードメイン─ でドメインを取得し,前段のリバースプロキシで終端すれば,compose構成のまま本格的なサービスとして公開できる.

よくある質問(FAQ)

Q1.本番でまず設定すべきは?

restart: alwaysだ.これがないとVPS再起動やクラッシュでサービスが止まったままになる.次にログのサイズ上限,ヘルスチェック,秘密情報の分離と進める.

Q2.depends_onだけでDB起動を待てる?

待てない.単なるdepends_onは起動順を制御するだけで「準備完了」は待たない.condition: service_healthyとヘルスチェックを組み合わせて初めて「DBが使える状態になってからアプリ起動」が実現する.

Q3.秘密情報はどう扱う?

compose.ymlに直書きせず.envに分離し,.gitignoreに追加する.ファイル権限も600に絞る.より厳格にはDocker secretsも使えるが,個人開発は.env方式で十分なことが多い.

Q4.リソース制限は必要?

1台に複数サービスを同居させるなら推奨だ.1コンテナのメモリリークがVPS全体を巻き込むのを防げる.制限値は実測しながら調整する.

Q5.無停止デプロイは個人開発でも要る?

多くの場合不要だ.up -d --buildの一瞬のダウンは許容できることが多い.本当に無停止が要るなら前段プロキシ+複数レプリカのローリング更新を検討する.まずはシンプル手順+デプロイ前スナップショットで十分.

Q6.ログでディスクが溢れる

composeのloggingmax-sizemax-fileを設定する.これでコンテナログが自動ローテートされ,肥大化を防げる.本番composeの必須設定だ.

まとめ ― 「動く」composeを「安定稼働する」composeへ

本番composeの要点は,restart・ヘルスチェック・秘密情報の分離・リソース制限・安全なデプロイ・ログ管理だ.これらを設定すれば,個人開発のサービスは「趣味の動作」から「安定したサービス」へ引き上がる.

今日やるべきことは,自分のcomposeにrestart: alwaysとログのサイズ上限を追加すること.この2つだけで,再起動耐性とディスク保護という本番の最低ラインを満たせる.

あとはヘルスチェックやリソース制限を順に足していけばよい.スナップショットで戻せるVPSがあれば,本番composeの作り込みも安心して進められる.