Next.js: Docker セルフホスティング & デプロイメント

最終更新:2026-08-26

セルフホストデプロイメントは、アプリケーションの実行環境を完全に制御できます — コンプライアンス、コスト、またはネットワーク要件によりクラウドプラットフォームを使用できない場合、Docker は最も信頼できるパートナーです。

1. 学習内容



2. ある DevOps エンジニアの実話

(1) 課題:クライアントがデータを国外に転送できないと要求

Charlie は中東の金融機関にサービスを提供する SaaS 企業で働いています。彼らの TaskFlow 製品はサウジアラビアのローカルデータセンターにデプロイする必要があります — クライアントはすべてのユーザーデータをサウジアラビア国内に物理的に保存することを要求しています。

しかし、Vercel にはサウジアラビアにデータセンターがありません。Charlie が直面する問題:

課題 影響
データ主権コンプライアンス サウジアラビアの金融規制要件がデータの海外転送を禁止
ネットワーク遅延 欧州サーバーからのアクセス時の遅延 > 200 ms
ベンダーロックイン Vercel 月額請求額 $2,000 以上
内部ネットワーク要件 顧客が企業内部ネットワークへのデプロイを希望

(2) セルフホスト Docker ソリューション

Charlie は Docker を使用してポータブルなデプロイメントパッケージを構築しました:

BASH
# 一度ビルドすれば、どこでも実行可能
docker build -t taskflow:latest .
docker run -p 3000:3000 \
  -e DATABASE_URL="postgresql://..." \
  -e AUTH_SECRET="..." \
  taskflow:latest

(3) 成果

項目 Vercel セルフホスト Docker
データ所在地 Vercel リージョンのみ 任意のデータセンター
月間コスト $2,000+ $300(サーバー)
デプロイ遅延 グローバル ~100 ms ローカル < 20 ms
ベンダーロックイン 高い 低い(移行可能)


3. output: 'standalone' 設定

Next.js 16 の output: 'standalone' モードは、アプリケーションの実行に必要なすべてのファイルを含むスタンドアロン Node.js サーバーを作成します。

100%
graph TB
    A[next.config.js] --> B[output: 'standalone']
    B --> C[ビルドプロセス]
    C --> D[.next/standalone/ ディレクトリ]
    D --> E[server.js — 独立 HTTP サーバー]
    D --> F[.next/static — 静的リソース]
    D --> G[node_modules — 最小依存関係]
    D --> H[package.json — 入力設定]
    
    style A fill:#cce5ff
    style D fill:#d4edda

(1) next.config.js の設定

JS
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
  
  // 外部処理が必要な依存関係
  serverExternalPackages: ['@prisma/client'],
  
  // 本番環境の最適化
  productionBrowserSourceMaps: false,
  swcMinify: true,
  
  // 画像最適化を保持
  images: {
    unoptimized: false
  }
}

module.exports = nextConfig

(2) standalone 出力ディレクトリ構造

TEXT 📖 参照専用
.next/standalone/
├── server.js              # 独立 HTTP サーバー(エントリポイント)
├── package.json           # ランタイム依存関係の宣言
├── node_modules/          # ビルド時のみの依存関係
├── .next/
│   ├── server/            # サーバーサイドコード
│   ├── static/            # 静的リソース
│   ├── build-manifest.json
│   └── ...
├── public/                # パブリック静的リソース
└── trace                  # ビルド追跡情報

▶ サンプル: スタンドアロンビルドの検証

BASH
# プロジェクトのビルド
npm run build

# standalone ディレクトリサイズの確認
du -sh .next/standalone/

# 専用サーバーの起動
node .next/standalone/server.js

# 別のターミナルで検証
curl http://localhost:3000
💻 出力:

TEXT 📖 参照専用
.next/standalone/    358M    # 合計サイズ
.next/standalone/server.js   # 入力ファイル(自動生成)
💻 出力:

TEXT 📖 参照専用
.next/standalone/    358M
node .next/standalone/server.js
  ▲ Next.js 16.0.0
  - Local: http://localhost:3000
  ✓ Ready in 1.2s


4. マルチステージ Docker ビルド

マルチステージビルドはイメージを 3 つの段階に分割します:依存関係のインストール → アプリケーションのビルド → 最小ランタイム環境。

DOCKERFILE
# ============================================
# Dockerfile — Next.js 16 マルチステージ構築
# ============================================

# --- フェーズ 1: 依存関係のインストール ---
FROM node:20-alpine AS deps
LABEL stage=deps

RUN apk add --no-cache libc6-compat

WORKDIR /app

COPY package.json package-lock.json pnpm-lock.yaml ./

RUN npm ci --only=production && \
    npm cache clean --force

# --- フェーズ 2: ビルド ---
FROM node:20-alpine AS build
LABEL stage=build

WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production

RUN npm run build

# --- フェーズ 3: 実行 ---
FROM node:20-alpine AS runner
LABEL stage=runner

RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nextjs

WORKDIR /app

# ビルド成果物のコピー
COPY --from=build --chown=nextjs:nodejs \
    /app/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs \
    /app/.next/static ./.next/static
COPY --from=build --chown=nextjs:nodejs \
    /app/public ./public

# ヘルスチェック
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1

USER nextjs

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
ENV NODE_ENV=production

CMD ["node", "server.js"]

(1) ビルドと実行

BASH
# イメージのビルド
docker build -t taskflow:latest .

# イメージサイズの確認
docker images taskflow:latest

# コンテナの実行
docker run -d \
  --name taskflow-app \
  -p 3000:3000 \
  -e DATABASE_URL="postgresql://user:pass@host:5432/taskflow" \
  -e AUTH_SECRET="your-secret-key" \
  -e NEXT_PUBLIC_API_URL="https://api.taskflow.local" \
  --restart unless-stopped \
  taskflow:latest

(2) ステージごとのイメージサイズ比較

ステージ ベースイメージ サイズ 内容
deps node:20-alpine ~150 MB node_modules + システム依存関係
build node:20-alpine ~450 MB ソースコード + node_modules + ビルド成果物
runner node:20-alpine ~358 MB standalone + 本番依存関係
ベース node:20-alpine ~126 MB 基本システム

▶ サンプル: Docker での環境変数注入

💻 出力:

TEXT 📖 参照専用
Sending build context to Docker daemon  4.096kB
Step 1/8 : FROM node:20-alpine AS deps
 ---> 1dd67de0f936
...
Successfully built a7b3c2d1e0f9
Successfully tagged shophub:latest
Docker command completed successfully.
d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4
BASH
# .env ファイルを使用した環境変数の注入
cat > .env.production << EOF
DATABASE_URL=postgresql://user:pass@db:5432/taskflow
AUTH_SECRET=super-secret-key
NEXT_PUBLIC_API_URL=https://api.taskflow.local
NEXT_PUBLIC_POSTHOG_KEY=phc_xxxx
REDIS_URL=redis://redis:6379
EOF

docker run -d \
  --name taskflow-app \
  --env-file .env.production \
  -p 3000:3000 \
  --network taskflow-net \
  taskflow:latest
💻 出力:

TEXT 📖 参照専用
Docker operation completed.


5. Nginx リバースプロキシ

Nginx は SSL 終端、静的リソースキャッシュ、ロードバランシングを処理し、本番環境に不可欠なコンポーネントです。

100%
graph LR
    A[ユーザーのブラウザ] --> B[Nginx :443]
    B --> C{パスマッチング}
    C -->|/_next/static/*| D[Nginx 直接配信<br/>1 年間キャッシュ]
    C -->|/api/health| E[Next.js :3000]
    C -->|/*| E
    B --> F[SSL 終端<br/>Let's Encrypt]
    
    style B fill:#cce5ff
    style D fill:#d4edda

Nginx 設定

NGINX
# nginx/nginx.conf
upstream nextjs_upstream {
    server app:3000;
    keepalive 64;
}

server {
    listen 80;
    server_name taskflow.local;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name taskflow.local;

    # SSL 証明書
    ssl_certificate /etc/nginx/ssl/taskflow.crt;
    ssl_certificate_key /etc/nginx/ssl/taskflow.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # セキュリティヘッダー
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

    # ログ
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # 静的リソースのキャッシュ(Next.js で処理)
    location /_next/static/ {
        proxy_pass http://nextjs_upstream;
        expires 365d;
        add_header Cache-Control "public, immutable";
    }

    location /static/ {
        proxy_pass http://nextjs_upstream;
        expires 30d;
        add_header Cache-Control "public";
    }

    # ヘルスチェックエンドポイント
    location /api/health {
        proxy_pass http://nextjs_upstream;
        access_log off;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }

    # その他すべてのリクエストは Next.js に転送
    location / {
        proxy_pass http://nextjs_upstream;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
    }
}


6. PM2 プロセスマネージャー

PM2 は Node.js プロセスがクラッシュ後に自動再起動することを保証し、ログ管理とクラスターモードを提供します。

(1) PM2 設定

JS
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'taskflow',
    script: 'server.js',
    cwd: '/app',
    
    // クラスターモード(全 CPU コアを使用)
    exec_mode: 'cluster',
    instances: 'max',
    
    // 環境変数
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
      HOSTNAME: '0.0.0.0'
    },
    
    // ログ設定
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
    error_file: '/var/log/pm2/taskflow-error.log',
    out_file: '/var/log/pm2/taskflow-out.log',
    merge_logs: true,
    
    // 自動再起動
    max_restarts: 10,
    restart_delay: 1000,
    min_uptime: 5000,
    
    // メモリ監視
    max_memory_restart: '500M',
    
    // ヘルスチェック
    listen_timeout: 3000,
    kill_timeout: 5000
  }]
}

(2) PM2 Docker 統合

DOCKERFILE
# runner ステージに PM2 をインストール
FROM node:20-alpine AS runner

RUN npm install -g pm2 && \
    addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nextjs

WORKDIR /app

COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=build --chown=nextjs:nodejs /app/public ./public
COPY --chown=nextjs:nodejs ecosystem.config.js ./

USER nextjs

EXPOSE 3000

# PM2 でクラスターモードを有効化
CMD ["pm2-runtime", "start", "ecosystem.config.js"]

▶ サンプル: よく使う PM2 コマンド

💻 出力:

TEXT 📖 参照専用
Docker image built and container started successfully.
BASH
# 全プロセスの表示
pm2 list

# ログの表示
pm2 logs taskflow
pm2 logs taskflow --lines 100

# リソースの監視
pm2 monit

# リロード(ゼロダウンタイム)
pm2 reload taskflow

# 停止/再起動
pm2 stop taskflow
pm2 restart taskflow

# 現在のプロセスリストを保存
pm2 save
pm2 startup
💻 出力:

TEXT 📖 参照専用
PM2 command executed successfully.
PM2 command executed successfully.
PM2 command executed successfully.
PM2 command executed successfully.
PM2 command executed successfully.
PM2 command executed successfully.
┌────┬──────────┬─────────┬─────────┐
│ id │ name     │ status  │ cpu     │
├────┼──────────┼─────────┼─────────┤
│ 0  │ shophub  │ online  │ 0%      │
└────┴──────────┴─────────┴─────────┘
PM2 command executed successfully.
┌────┬──────────┬─────────┬─────────┐
│ id │ name     │ status  │ cpu     │
├────┼──────────┼─────────┼─────────┤
│ 0  │ shophub  │ online  │ 0%      │
└────┴──────────┴─────────┴─────────┘


7. Docker Compose: 3 つのコンテナをオーケストレーション

Docker Compose は App、Nginx、PostgreSQL の 3 つのコンテナをオーケストレーションし、ワンクリックで環境全体を起動します。

YAML
# docker-compose.yml
version: '3.8'

networks:
  taskflow-net:
    driver: bridge

volumes:
  postgres-data:
    driver: local
  nginx-logs:
    driver: local

services:
  # === 1. PostgreSQL データベース ===
  db:
    image: postgres:16-alpine
    container_name: taskflow-db
    restart: unless-stopped
    networks:
      - taskflow-net
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./db/init:/docker-entrypoint-initdb.d
    environment:
      POSTGRES_USER: taskflow
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: taskflow
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U taskflow"]
      interval: 10s
      timeout: 5s
      retries: 5
    ports:
      - "5432:5432"

  # === 2. Next.js アプリケーション ===
  app:
    build:
      context: .
      dockerfile: Dockerfile
      target: runner
    image: taskflow:latest
    container_name: taskflow-app
    restart: unless-stopped
    networks:
      - taskflow-net
    depends_on:
      db:
        condition: service_healthy
    environment:
      NODE_ENV: production
      PORT: 3000
      HOSTNAME: "0.0.0.0"
      DATABASE_URL: postgresql://taskflow:${DB_PASSWORD}@db:5432/taskflow
      AUTH_SECRET: ${AUTH_SECRET}
      AUTH_URL: ${AUTH_URL}
      NEXT_PUBLIC_API_URL: ${PUBLIC_API_URL}
      NEXT_PUBLIC_POSTHOG_KEY: ${POSTHOG_KEY:-}
    env_file:
      - .env.production
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 3s
      retries: 3

  # === 3. Nginx リバースプロキシ ===
  nginx:
    image: nginx:alpine
    container_name: taskflow-nginx
    restart: unless-stopped
    networks:
      - taskflow-net
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
      - nginx-logs:/var/log/nginx
    depends_on:
      app:
        condition: service_healthy

(1) 環境変数ファイル

BASH
# .env.production(Git にコミットしないでください)
DB_PASSWORD=StrongPassword123!
AUTH_SECRET=your-auth-secret-key-min-32-chars
AUTH_URL=https://auth.taskflow.local
PUBLIC_API_URL=https://api.taskflow.local
POSTHOG_KEY=phc_exampleKey123

(2) 起動と管理

BASH
# 初回起動
docker compose up -d

# ログの表示
docker compose logs -f app
docker compose logs -f nginx

# アプリケーションの再ビルド
docker compose build app
docker compose up -d app

# データベースマイグレーションの更新
docker compose exec app npx prisma migrate deploy

# 稼働状況の表示
docker compose ps

# 全サービスの停止
docker compose down

# 完全クリーンアップ(ボリューム含む)
docker compose down -v

▶ サンプル: docker-compose.override.yml(開発環境)

💻 出力:

TEXT 📖 参照専用
上記の YAML 設定を指定されたファイルパスに保存してください。設定は次回のサーバー再起動時に有効になります。
YAML
# docker-compose.override.yml
version: '3.8'

services:
  app:
    build:
      target: build  # 開発フェーズでは runner ではなく build を使用
    environment:
      NODE_ENV: development
    volumes:
      - ./src:/app/src:ro
      - ./public:/app/public:ro
    command: npm run dev  # 開発サーバーを使用

  db:
    ports:
      - "5432:5432"  # 開発中はデータベースポートを公開

  nginx:
    ports:
      - "3000:80"  # 開発中はポートマッピングを簡略化
💻 出力:

TEXT 📖 参照専用
上記の YAML 設定を指定されたファイルパスに保存してください。設定は次回のサーバー再起動時に有効になります。


8. ランタイム環境変数の注入

Docker コンテナの環境変数はビルド時ではなく実行時に注入されます — これにより単一のイメージを複数の環境にデプロイできます。

100%
graph LR
    A[Docker ビルド] --> B[イメージ<br/>(環境変数なし)]
    B --> C[ランタイム注入]
    C --> D[開発環境 .env.dev]
    C --> E[テスト環境 .env.test]
    C --> F[本番環境 .env.prod]
    D --> G[コンテナ起動]
    E --> G
    F --> G
    G --> H[server.js が process.env を読み取り]
    
    style B fill:#cce5ff
    style G fill:#d4edda

(1) ビルド時変数とランタイム変数

変数タイプ 注入タイミング 保存場所
ビルド時 docker build NEXT_PUBLIC_*、バージョン番号 Dockerfile ARG
ランタイム docker run DATABASE_URLAUTH_SECRET docker compose env_file
混合 両方必要 NEXT_PUBLIC_API_URL ビルド時にフロントエンドに注入、ランタイムにバックエンドに注入

(2) ビルド時の変数注入

DOCKERFILE
# Dockerfile で ARG を使用してビルド時変数を渡す
FROM node:20-alpine AS build

ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL

ARG SENTRY_DSN
ENV SENTRY_DSN=$SENTRY_DSN

RUN npm run build
BASH
# ビルド時に変数を渡す
docker build \
  --build-arg NEXT_PUBLIC_API_URL=https://api.taskflow.com \
  --build-arg SENTRY_DSN=https://xxx@sentry.io/123 \
  -t taskflow:latest .

▶ サンプル: ランタイム環境検証スクリプト

💻 出力:

TEXT 📖 参照専用
Sending build context to Docker daemon  4.096kB
Step 1/8 : FROM node:20-alpine AS deps
 ---> 1dd67de0f936
...
Successfully built a7b3c2d1e0f9
Successfully tagged shophub:latest
TS
// src/lib/env.ts
// ランタイム環境変数検証
function getRequiredEnvVar(name: string): string {
  const value = process.env[name]
  if (!value) {
    throw new Error(`必須の環境変数が不足しています: ${name}`)
  }
  return value
}

export const env = {
  databaseUrl: getRequiredEnvVar('DATABASE_URL'),
  authSecret: getRequiredEnvVar('AUTH_SECRET'),
  authUrl: process.env.AUTH_URL || 'http://localhost:3000',
  publicApiUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000',
  posthogKey: process.env.NEXT_PUBLIC_POSTHOG_KEY,
  nodeEnv: process.env.NODE_ENV || 'development',
  isProduction: process.env.NODE_ENV === 'production',
  port: parseInt(process.env.PORT || '3000', 10)
}
💻 出力:

TEXT 📖 参照専用
エクスポート: env。


9. 完全な例: TaskFlow Docker デプロイメント

BASH
# ============================================
# 本番デプロイメントスクリプト: deploy.sh
# 機能: ビルド → マイグレーション → 起動 → ヘルスチェック
# ============================================

#!/bin/bash
set -euo pipefail

echo "=== TaskFlow 本番デプロイメント ==="

# 1. 環境変数の読み込み
if [ ! -f .env.production ]; then
    echo "エラー: .env.production が見つかりません"
    exit 1
fi
source .env.production

# 2. Docker イメージのビルド
echo "Docker イメージをビルド中..."
docker compose build app

# 3. データベースの起動(実行中でない場合)
echo "データベースを起動中..."
docker compose up -d db
echo "データベースの準備完了を待機中..."
sleep 5

# 4. データベースマイグレーションの実行
echo "データベースマイグレーションを実行中..."
docker compose run --rm app npx prisma migrate deploy

# 5. アプリと Nginx の起動
echo "アプリケーションと Nginx を起動中..."
docker compose up -d app nginx

# 6. ヘルスチェック
echo "ヘルスチェックを実行中..."
for i in {1..10}; do
    if curl -s -o /dev/null -w "%{http_code}" http://localhost:80/api/health | grep -q 200; then
        echo "ヘルスチェック合格!"
        break
    fi
    echo "待機中... ($i/10)"
    sleep 3
done

# 7. 古いイメージのクリーンアップ
echo "古いイメージをクリーンアップ中..."
docker image prune -f

# 8. デプロイメント情報
echo ""
echo "=== デプロイメント完了 ==="
echo "アプリ:      http://localhost:80"
echo "API:         http://localhost:80/api/health"
echo "DB:          postgresql://taskflow@localhost:5432/taskflow"
echo "ログ:        docker compose logs -f app"
echo "再起動:      docker compose restart app"
TS
// src/app/api/health/route.ts
// ============================================
// ヘルスチェック API: Docker HEALTHCHECK から呼び出されます
// ============================================
import { NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'

export async function GET() {
  const checks = {
    status: 'healthy',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    checks: {} as Record<string, boolean>
  }

  try {
    // データベース接続の確認
    await prisma.$queryRaw`SELECT 1`
    checks.checks.database = true
  } catch {
    checks.checks.database = false
    checks.status = 'degraded'
  }

  try {
    // Redis の確認(設定されている場合)
    // await redis.ping()
    checks.checks.redis = true
  } catch {
    checks.checks.redis = false
    if (!checks.checks.database) {
      checks.status = 'unhealthy'
    }
  }

  const statusCode = checks.status === 'healthy' ? 200 : 503

  return NextResponse.json(checks, { status: statusCode })
}

❓ よくある質問

Q output: 'standalone'output: 'export' の違いは何ですか?
A standalone は Node.js サーバーを含むスタンドアロンパッケージを生成し、SSR、ISR、API ルートなどのすべての Next.js 機能をサポートします。export は純粋な静的 HTML を生成し(SSR は無効になります)、CDN ホスティングに適しています。Docker でのセルフホスティングには、standalone モードを使用する必要があります。
Q マルチステージビルドがシングルステージビルドよりも優れているのはなぜですか?
A (1) イメージが小さくなります — ランタイムステージには実行に必要な最小限のファイルのみが含まれます(358 MB vs. 1.2 GB)。(2) より安全です — ビルドツールとソースコードが最終イメージに含まれません。(3) ビルドキャッシュがより効率的です — 依存関係レイヤーはほとんど変更されないため、Docker のキャッシュレイヤーを再利用できます。
Q Nginx は必須ですか、それともオプションですか?
A 本番環境では Nginx を強く推奨します:(1) SSL 終端 — HTTPS 証明書の処理。(2) 静的リソースのキャッシュ — Node.js の負荷を軽減します。(3) セキュリティヘッダーの注入 — XSS、CSP、HSTS など。(4) ロードバランシング — 複数インスタンスへのリクエスト分散。シンプルな内部ネットワーク環境では、このステップを省略して Next.js のポートを直接公開することもできます。
Q PM2 と Docker の再起動ポリシーの両方を使用する必要がありますか?
A 両方の使用をお勧めします。Docker の restart: unless-stopped はコンテナレベルのクラッシュ(OOM など)を処理し、PM2 は Node.js プロセスレベルのクラッシュ(未捕捉例外など)を処理します。また、PM2 はログローテーション、クラスターモード、ゼロダウンタイム再起動など、Docker 自体にはない機能も提供します。
Q Docker Compose と Kubernetes のどちらを選択すべきですか?
A 単一サーバーデプロイメントには Docker Compose を選択します(設定がシンプルで学習曲線が低いです)。マルチサーバークラスター、自動スケーリング、サービスディスカバリには Kubernetes を選択します。中小規模のチーム(1〜5 サーバー)では、Docker Compose の Swarm モードでほとんどのシナリオに十分対応できます。

📖 まとめ


📝 練習問題

  1. 基本問題 (⭐): output: 'standalone' を含む next.config.js を作成し、マルチステージ Dockerfile を記述して、正常にビルドして docker run を実行し、curl localhost:3000 で検証します。

  2. 応用問題 (⭐⭐): Docker Compose に Nginx リバースプロキシコンテナを追加します:(1) 自己署名 SSL 証明書を設定する。(2) 静的リソースのキャッシュルールを追加する。(3) /_next/static を 365 日間キャッシュするように設定する。(4) HTTPS アクセスが正常に機能することを確認する。

  3. 発展問題 (⭐⭐⭐): 完全なセルフホスト CI/CD + Docker パイプラインを構築します:(1) GitHub Actions を使用して Docker イメージを自動ビルドし GHCR にプッシュする。(2) SSH 経由でターゲットサーバーに新しいイメージをプルする。(3) Docker Compose を使用してゼロダウンタイム更新を行う(docker compose up -d --no-deps --build app)。(4) PM2 クラスターモードとログローテーションを設定する。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%