gpt-oss を Docker Compose で本番準備:ヘルスチェック・リソース制限・再起動方針
gpt-oss は、ChatGPT のようなチャットインターフェースを提供するオープンソースプロジェクトとして注目を集めています。開発環境では docker-compose up だけで簡単に動作しますが、本番環境で安定稼働させるには、ヘルスチェック・リソース制限・再起動方針といった運用設計が欠かせません。
この記事では、gpt-oss を Docker Compose で本番運用する際に必須となる 3 つの設定要素について、具体的な実装方法を交えながら解説します。これらの設定を適切に行うことで、サービスの可用性を高め、障害時の自動復旧やリソース枯渇の防止が実現できるでしょう。
背景
Docker Compose が本番環境で選ばれる理由
Docker Compose は、複数コンテナのオーケストレーションツールとして、開発環境だけでなく本番環境でも広く利用されています。特に小規模から中規模のアプリケーションでは、Kubernetes ほどの複雑さを必要とせず、YAML ファイル 1 つでインフラを管理できる手軽さが魅力です。
gpt-oss のような Web アプリケーションでは、フロントエンド・バックエンド・データベース・Redis など複数のサービスが連携して動作します。Docker Compose を使えば、これらのサービス間の依存関係やネットワーク設定を一元管理でき、デプロイの再現性も確保できますね。
本番運用で求められる信頼性
開発環境では、コンテナが停止しても手動で再起動すれば問題ありません。しかし本番環境では、夜間や休日でもサービスが自動復旧し、ユーザーに影響を与えないことが求められます。
以下の図は、Docker Compose による本番環境の基本構成を示しています。
mermaidflowchart TB
user["ユーザー"] -->|HTTPS| nginx["Nginx<br/>(リバースプロキシ)"]
nginx -->|HTTP| frontend["gpt-oss Frontend<br/>(Next.js)"]
frontend -->|API 呼び出し| backend["Backend API<br/>(Node.js)"]
backend -->|クエリ| db[("PostgreSQL")]
backend -->|キャッシュ| redis[("Redis")]
monitor["Docker Engine"] -.->|ヘルスチェック| frontend
monitor -.->|ヘルスチェック| backend
monitor -.->|リソース監視| frontend
monitor -.->|リソース監視| backend
この図から分かるように、Docker Engine がヘルスチェックとリソース監視を担当し、各コンテナの健全性を保ちます。
gpt-oss の構成要素
gpt-oss は一般的に以下のコンポーネントで構成されています。
| # | コンポーネント | 役割 | 重要度 |
|---|---|---|---|
| 1 | Frontend (Next.js) | ユーザーインターフェース | ★★★ |
| 2 | Backend API (Node.js) | ビジネスロジック・AI 連携 | ★★★ |
| 3 | PostgreSQL | ユーザーデータ・会話履歴 | ★★★ |
| 4 | Redis | セッション・キャッシュ | ★★☆ |
これらすべてが正常に動作し続けることで、初めてサービスとして成立します。
課題
開発環境と本番環境のギャップ
開発環境では問題なく動いていた Docker Compose が、本番環境で以下のような問題を引き起こすケースがあります。
リソース枯渇による障害
メモリ制限を設定していないと、バックエンド API が無制限にメモリを消費し、ホストサーバー全体がダウンする恐れがあります。特に AI モデルとの通信で大量のデータを扱う gpt-oss では、メモリリークが発生しやすい傾向にありますね。
異常終了後の放置
コンテナがクラッシュしても再起動設定がないと、サービスが停止したままになってしまいます。ユーザーからの問い合わせで初めて障害に気づくという事態は避けたいものです。
不健全な状態での稼働継続
プロセスは起動しているものの、データベース接続が切れている、API が応答しないといった「半死状態」のコンテナが稼働し続けると、ユーザーはエラー画面を見続けることになります。
以下の図は、これらの課題が発生するフローを示しています。
mermaidstateDiagram-v2
[*] --> Running: コンテナ起動
Running --> Unhealthy: メモリリーク発生
Running --> Crashed: 予期せぬエラー
Unhealthy --> Running: 設定なし→放置
Unhealthy --> Restart: ヘルスチェック検知
Crashed --> Stopped: 再起動設定なし
Crashed --> Restart: restart=always
Restart --> Running: 自動復旧
Stopped --> [*]: サービス停止
note right of Unhealthy
応答遅延・エラー頻発
ユーザー影響大
end note
note right of Stopped
完全停止
手動復旧が必要
end note
図で理解できる要点:
- ヘルスチェックがないと不健全な状態が検知されない
- 再起動設定がないとクラッシュ後に停止したまま
- 適切な設定で自動復旧のサイクルが確立される
運用負荷の増大
これらの問題に対処するため、運用担当者が 24 時間監視し、手動で再起動やリソース調整を行うのは現実的ではありません。自動化された仕組みが必要です。
解決策
ヘルスチェックで異常を自動検知
Docker Compose の healthcheck 機能を使うと、コンテナが本当に健全かどうかを定期的に確認できます。単にプロセスが動いているだけでなく、HTTP エンドポイントが正常に応答するかをチェックしましょう。
ヘルスチェックの仕組み
ヘルスチェックは以下のパラメータで制御されます。
| # | パラメータ | 説明 | 推奨値 |
|---|---|---|---|
| 1 | test | 実行するコマンド | curl -f http://localhost:3000/health |
| 2 | interval | チェック間隔 | 30s |
| 3 | timeout | タイムアウト時間 | 10s |
| 4 | retries | 失敗許容回数 | 3 |
| 5 | start_period | 起動猶予期間 | 40s |
ヘルスチェックが連続して失敗すると、コンテナは unhealthy 状態になります。この状態を検知して自動的に再起動させることで、サービスの自己修復が可能になりますね。
リソース制限でホストを保護
deploy.resources セクションで CPU とメモリの上限を設定すると、1 つのコンテナが暴走してもホスト全体への影響を抑えられます。
制限設定の考え方
リソース制限には 2 つのレベルがあります。
- limits:絶対に超えてはいけない上限値
- reservations:最低限確保する予約値
gpt-oss のバックエンドは AI API との通信で一時的に負荷が高くなるため、通常時は控えめに、ピーク時は上限まで使えるよう設定するのが効果的です。
再起動方針で自動復旧
restart ポリシーを設定すると、コンテナが停止した際の動作を制御できます。
Docker Compose で指定できる再起動ポリシーは以下の通りです。
| # | ポリシー | 動作 | 用途 |
|---|---|---|---|
| 1 | no | 再起動しない | テスト・開発 |
| 2 | always | 常に再起動 | 本番サービス |
| 3 | on-failure | 異常終了時のみ再起動 | バッチ処理 |
| 4 | unless-stopped | 手動停止以外は再起動 | 本番サービス(推奨) |
本番環境では unless-stopped を使うことで、手動でのメンテナンス停止は尊重しつつ、予期せぬクラッシュからは自動復旧できます。
以下の図は、再起動ポリシーの動作フローを示しています。
mermaidflowchart TD
start["コンテナ起動"] --> running["Running 状態"]
running --> check{"終了原因は?"}
check -->|正常終了<br/>exit 0| policy1{"restart ポリシー"}
check -->|異常終了<br/>exit 1-255| policy2{"restart ポリシー"}
check -->|手動停止<br/>docker stop| policy3{"restart ポリシー"}
policy1 -->|always| restart["再起動"]
policy1 -->|unless-stopped| restart
policy1 -->|on-failure| stopped["停止"]
policy1 -->|no| stopped
policy2 -->|always| restart
policy2 -->|unless-stopped| restart
policy2 -->|on-failure| restart
policy2 -->|no| stopped
policy3 -->|always| restart
policy3 -->|unless-stopped| stopped
policy3 -->|on-failure| stopped
policy3 -->|no| stopped
restart --> running
stopped --> finish["終了"]
図で理解できる要点:
alwaysはすべてのケースで再起動unless-stoppedは手動停止を尊重on-failureは異常終了のみ対応
具体例
docker-compose.yml の基本構成
それでは、gpt-oss の本番環境向け docker-compose.yml を段階的に構築していきましょう。まずは全体の骨格を定義します。
yamlversion: '3.8'
services:
frontend:
# Frontend サービス設定(後述)
backend:
# Backend サービス設定(後述)
postgres:
# PostgreSQL 設定(後述)
redis:
# Redis 設定(後述)
networks:
gpt-oss-network:
driver: bridge
volumes:
postgres-data:
redis-data:
この構成では、4 つのサービスをプライベートネットワークで接続し、データは永続化ボリュームに保存します。
Frontend サービスの設定
Next.js で構築された Frontend には、ヘルスチェック・リソース制限・再起動方針のすべてを適用します。
イメージとネットワークの定義
yamlfrontend:
image: gpt-oss/frontend:latest
container_name: gpt-oss-frontend
networks:
- gpt-oss-network
ports:
- '3000:3000'
このコードでは、Frontend を 3000 番ポートで公開し、内部ネットワークに接続しています。
環境変数の設定
yamlenvironment:
- NODE_ENV=production
- NEXT_PUBLIC_API_URL=http://backend:4000
- NEXT_TELEMETRY_DISABLED=1
本番環境では NODE_ENV=production を必ず設定し、最適化されたビルドを使用しましょう。
ヘルスチェックの実装
yamlhealthcheck:
test:
[
'CMD',
'curl',
'-f',
'http://localhost:3000/api/health',
]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
このヘルスチェックは、30 秒ごとに /api/health エンドポイントにアクセスし、10 秒以内に応答がなければ失敗と判定します。起動直後の 40 秒間は猶予期間として、失敗してもカウントされません。
リソース制限の設定
yamldeploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
Frontend は CPU 1 コア、メモリ 1GB を上限とし、通常時は 0.5 コア・512MB を確保します。Next.js のビルド時にメモリを多く使うため、1GB の上限は妥当な設定です。
再起動方針の適用
yamlrestart: unless-stopped
depends_on:
backend:
condition: service_healthy
unless-stopped により、クラッシュ時は自動再起動し、手動停止時は停止したままになります。また、Backend のヘルスチェックが通るまで起動を待機しますね。
Backend サービスの設定
Backend API は gpt-oss の心臓部であり、最も慎重なリソース管理が必要です。
基本設定とネットワーク
yamlbackend:
image: gpt-oss/backend:latest
container_name: gpt-oss-backend
networks:
- gpt-oss-network
ports:
- '4000:4000'
Backend は 4000 番ポートで API を提供します。
環境変数とシークレット
yamlenvironment:
- NODE_ENV=production
- DATABASE_URL=postgresql://gptoss:password@postgres:5432/gptoss
- REDIS_URL=redis://redis:6379
- OPENAI_API_KEY=${OPENAI_API_KEY}
- JWT_SECRET=${JWT_SECRET}
API キーやシークレットは、.env ファイルや環境変数から注入し、docker-compose.yml にハードコードしないよう注意しましょう。
ヘルスチェックの実装
yamlhealthcheck:
test:
['CMD', 'curl', '-f', 'http://localhost:4000/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
Backend はデータベース接続の初期化に時間がかかるため、start_period を 60 秒に設定しています。
リソース制限の詳細設定
yamldeploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '1.0'
memory: 1G
Backend は AI API との通信やデータ処理で負荷が高いため、CPU 2 コア・メモリ 2GB を上限とします。これにより、複数のユーザーが同時にチャットしても安定稼働できるでしょう。
再起動方針と依存関係
yamlrestart: unless-stopped
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
PostgreSQL のヘルスチェックが通過してから起動することで、データベース接続エラーを防ぎます。
PostgreSQL の設定
データベースは永続化とパフォーマンスのバランスが重要です。
基本設定
yamlpostgres:
image: postgres:15-alpine
container_name: gpt-oss-postgres
networks:
- gpt-oss-network
Alpine ベースのイメージを使うことで、軽量かつセキュアな環境を構築します。
環境変数とボリューム
yamlenvironment:
- POSTGRES_USER=gptoss
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=gptoss
- PGDATA=/var/lib/postgresql/data/pgdata
volumes:
- postgres-data:/var/lib/postgresql/data
データは名前付きボリュームに永続化し、コンテナを削除してもデータが失われないようにします。
ヘルスチェックの実装
yamlhealthcheck:
test: ['CMD-SHELL', 'pg_isready -U gptoss -d gptoss']
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
pg_isready コマンドでデータベースが接続可能かを確認します。データベースは他のサービスの前提条件なので、チェック間隔を 10 秒と短く設定していますね。
リソース制限
yamldeploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
restart: unless-stopped
PostgreSQL は効率的なメモリ管理を行うため、1GB の上限で十分なパフォーマンスを発揮します。
Redis の設定
Redis はセッション管理とキャッシュに使用します。
基本設定
yamlredis:
image: redis:7-alpine
container_name: gpt-oss-redis
networks:
- gpt-oss-network
command: redis-server --appendonly yes
--appendonly yes で AOF 永続化を有効にし、データの耐久性を確保します。
ボリュームとヘルスチェック
yamlvolumes:
- redis-data:/data
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 10s
timeout: 3s
retries: 3
start_period: 10s
redis-cli ping で Redis が応答するかを確認します。Redis は起動が速いため、start_period は 10 秒で十分でしょう。
リソース制限
yamldeploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
restart: unless-stopped
Redis は軽量なため、控えめなリソース制限で動作します。
ヘルスチェックエンドポイントの実装
Docker Compose のヘルスチェックを機能させるには、アプリケーション側にヘルスチェックエンドポイントを用意する必要があります。
Backend のヘルスチェックエンドポイント
以下は Express.js での実装例です。
typescriptimport express from 'express';
import { Router } from 'express';
const healthRouter = Router();
healthRouter.get('/health', async (req, res) => {
try {
// データベース接続確認
await checkDatabaseConnection();
このエンドポイントでは、データベースへの接続を確認します。
typescript// Redis 接続確認
await checkRedisConnection();
// レスポンス返却
res.status(200).json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
});
すべてのチェックが成功したら、ステータス 200 で健全性を報告します。
typescript } catch (error) {
// エラー時は 503 Service Unavailable を返す
res.status(503).json({
status: 'unhealthy',
error: error.message,
timestamp: new Date().toISOString()
});
}
});
export default healthRouter;
エラーが発生した場合は 503 Service Unavailable を返し、Docker にコンテナが不健全であることを通知します。
データベース接続確認の実装
typescriptimport { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function checkDatabaseConnection(): Promise<void> {
// シンプルなクエリで接続確認
await prisma.$queryRaw`SELECT 1`;
}
Prisma を使っている場合、$queryRaw で簡単なクエリを実行して接続を確認できますね。
Redis 接続確認の実装
typescriptimport Redis from 'ioredis';
const redis = new Redis({
host: process.env.REDIS_HOST || 'redis',
port: parseInt(process.env.REDIS_PORT || '6379'),
});
async function checkRedisConnection(): Promise<void> {
// PING コマンドで接続確認
const result = await redis.ping();
if (result !== 'PONG') {
throw new Error('Redis connection failed');
}
}
Redis の PING コマンドで接続を確認し、PONG が返ってこなければエラーをスローします。
本番環境へのデプロイ手順
設定が完成したら、以下の手順で本番環境にデプロイします。
環境変数ファイルの準備
bash# .env.production ファイルを作成
cat > .env.production << 'EOF'
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
JWT_SECRET=your-secure-random-secret
POSTGRES_PASSWORD=your-database-password
EOF
機密情報は .env.production ファイルに記載し、Git にはコミットしません。
イメージのビルドとプッシュ
bash# Frontend イメージをビルド
docker build -t gpt-oss/frontend:latest ./frontend
# Backend イメージをビルド
docker build -t gpt-oss/backend:latest ./backend
本番環境で使用するイメージを事前にビルドしておきます。
Docker Compose の起動
bash# 環境変数を読み込んで起動
docker-compose --env-file .env.production up -d
# ログを確認
docker-compose logs -f
-d オプションでバックグラウンド起動し、ログで起動状態を確認しましょう。
ヘルスチェック状態の確認
bash# すべてのコンテナの状態を確認
docker-compose ps
# 特定のコンテナのヘルスチェック詳細を確認
docker inspect gpt-oss-backend | grep -A 10 Health
docker-compose ps の STATUS 列に (healthy) と表示されれば、ヘルスチェックが正常に機能しています。
トラブルシューティング
本番運用で発生しやすい問題と対処法を紹介します。
Error: Container is unhealthy
ヘルスチェックが連続して失敗し、コンテナが unhealthy 状態になった場合の対処法です。
bash# ヘルスチェックログを確認
docker inspect --format='{{json .State.Health}}' gpt-oss-backend | jq
# コンテナ内でヘルスチェックコマンドを手動実行
docker exec gpt-oss-backend curl -f http://localhost:4000/health
ヘルスチェックコマンドを手動で実行し、エラー内容を特定します。データベース接続エラーやポート設定ミスが原因のケースが多いですね。
Error: OOMKilled (Out of Memory)
メモリ制限を超えてコンテナが強制終了された場合です。
bash# コンテナの終了理由を確認
docker inspect gpt-oss-backend | grep OOMKilled
# メモリ使用状況をモニタリング
docker stats gpt-oss-backend
OOMKilled: true と表示された場合は、deploy.resources.limits.memory の値を増やす必要があります。
yamldeploy:
resources:
limits:
memory: 3G # 2G から 3G に増量
メモリ使用量の傾向を観察し、ピーク時に余裕を持った値に設定しましょう。
Error: Container restart loop
コンテナが起動と停止を繰り返す場合の対処法です。
bash# 直近のログを確認
docker-compose logs --tail=100 backend
# 再起動回数を確認
docker inspect gpt-oss-backend | grep RestartCount
起動時のエラーログから原因を特定します。環境変数の設定ミス、データベース接続失敗、ポート競合などが考えられます。
監視とアラート設定
本番環境では、ヘルスチェックの結果を監視システムに連携することが重要です。
Prometheus との連携
以下は、Docker のヘルスチェック状態を Prometheus で収集する設定例です。
yaml# prometheus.yml に追加
scrape_configs:
- job_name: 'docker'
static_configs:
- targets: ['localhost:9323']
Docker Engine のメトリクスエンドポイントから、コンテナのヘルスチェック状態を収集できます。
アラート条件の定義
yaml# alert.rules.yml
groups:
- name: docker_health
interval: 30s
rules:
- alert: ContainerUnhealthy
expr: docker_container_health_status != 1
for: 2m
labels:
severity: critical
annotations:
summary: 'コンテナ {{ $labels.container }} が unhealthy 状態'
description: '2分以上 unhealthy 状態が続いています'
この設定により、コンテナが 2 分以上 unhealthy 状態になるとアラートが発火します。
まとめ
gpt-oss を Docker Compose で本番運用する際には、ヘルスチェック・リソース制限・再起動方針の 3 つの設定が欠かせません。これらを適切に実装することで、以下のメリットが得られます。
可用性の向上
ヘルスチェックと再起動方針により、障害発生時の自動復旧が実現し、サービスの稼働率が向上します。夜間や休日でも、人手を介さずにサービスが復旧するのは大きな安心材料ですね。
リソース枯渇の防止
メモリや CPU の制限により、1 つのコンテナが暴走してもホスト全体への影響を抑えられます。複数のサービスを同じサーバーで運用する場合、この設定は必須と言えるでしょう。
運用負荷の軽減
自動化された監視と復旧により、運用担当者の負担が大幅に軽減されます。手動での再起動やリソース調整の頻度が減り、より戦略的な業務に時間を使えますね。
本番環境では、これらの設定を組み合わせて使用することで、安定したサービス提供が可能になります。最初は控えめなリソース制限から始め、実際の負荷を観察しながら調整していくアプローチをお勧めします。
また、ヘルスチェックエンドポイントは単純な「生存確認」だけでなく、外部サービスとの接続状態まで含めた「健全性確認」を実装することで、より信頼性の高いシステムが構築できるでしょう。
関連リンク
articlegpt-oss を Docker Compose で本番準備:ヘルスチェック・リソース制限・再起動方針
articlegpt-oss アーキテクチャを分解図で理解する:推論ランタイム・トークナイザ・サービング層の役割
articlegpt-oss 運用監視ダッシュボード設計:Prometheus/Grafana/OTel で可観測性強化
articlegpt-oss が OOM/VRAM 枯渇で落ちる:モデル分割・ページング・バッチ制御の解決策
articlegpt-oss の量子化別ベンチ比較:INT8/FP16/FP8 の速度・品質トレードオフ
articlegpt-oss でナレッジ検索アシスタント:根拠表示・更新検知・検索ログ最適化
articleHaystack で最小の検索 QA を作る:Retriever + Reader の 30 分ハンズオン
articleJest のフレークテスト撲滅作戦:重試行・乱数固定・リトライ設計の実務
articleGitHub Copilot セキュア運用チェックリスト:権限・ポリシー・ログ・教育の定着
articleGrok で社内 FAQ ボット:ナレッジ連携・権限制御・改善サイクル
articleGitHub Actions ランナーのオートスケール運用:Kubernetes/actions-runner-controller 実践
articleClips AI で書き出しが止まる時の原因切り分け:メモリ不足・コーデック・権限
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来