mcpField
D
deployment

deployment

github.com/mgd34msuクラウド・DevOps653 回インストール10 週間前に更新
リポジトリ

deployment について

deploymentは、Next.js、フルスタック、コンテナ化、サーバーレスのアプリを本番環境へデプロイする開発者向けのスキルです。プラットフォーム選定、CI/CD、ヘルスチェック、監視、ロールバックを扱い、検証スクリプトも含みます。

主な機能

  1. 01プラットフォーム選定と環境設定
  2. 02GitHub ActionsによるCI/CD構築
  3. 03本番用Dockerイメージの作成
  4. 04ヘルスチェックと監視の設定
  5. 05プレビューとロールバックの計画
  6. 06デプロイ前チェックの実行

活用シーン

  1. 01Next.jsアプリの本番デプロイ
  2. 02コンテナサービスのリリース手順整備
  3. 03プルリクエスト用プレビューの作成
  4. 04設定とロールバック準備の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mgd34msu/goodvibes-plugin --skill deployment

インストール後、Claude Code で/deploymentを入力して読み込まれたか確認します。

同梱ファイルreferences/deployment-platforms.mdscripts/validate-deployment.sh

詳細

リソース

scripts/
  validate-deployment.sh
references/
  deployment-platforms.md

デプロイ

このスキルでは、最新のプラットフォームやツールを使用してアプリケーションを本番環境にデプロイする手順を説明します。Next.js、フルスタックアプリ、コンテナ化されたサービス、サーバーレス関数をデプロイする際に、このワークフローを使用してください。

このスキルを使用する場面

  • Vercel、Railway、Fly.io、AWS へのアプリケーションのデプロイ
  • GitHub Actions を使用した CI/CD パイプラインのセットアップ
  • 本番環境向け Docker コンテナの設定
  • ヘルスチェックとモニタリングの実装
  • プルリクエスト用のプレビュー環境の作成
  • ロールバックとカナリアデプロイ戦略のセットアップ

プラットフォームの選択

アプリケーションのニーズに応じて、適切なプラットフォームを選択してください。

Vercel(Next.js に最適)

使用する場面:

  • Next.js アプリケーション(App Router または Pages Router)
  • エッジ関数を備えた静的サイト
  • PR ごとの自動プレビュー環境
  • 設定不要のデプロイ

セットアップ:

# Install Vercel CLI
npm install -g vercel

# Deploy
vercel --prod

環境変数:

# Set production secrets
vercel env add DATABASE_URL production
vercel env add NEXTAUTH_SECRET production
Railway(フルスタックに最適)

使用する場面:

  • データベースを備えたフルスタックアプリ
  • モノレポのデプロイ
  • PostgreSQL、Redis、MongoDB のホスティング
  • WebSocket のサポート

セットアップ:

# Install Railway CLI
npm install -g @railway/cli

# Login and deploy
railway login
railway up

railway.json:

{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS",
    "buildCommand": "npm run build"
  },
  "deploy": {
    "startCommand": "npm start",
    "healthcheckPath": "/api/health",
    "healthcheckTimeout": 100,
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 3
  }
}
Fly.io(コンテナに最適)

使用する場面:

  • カスタムコンテナ要件
  • グローバルエッジへのデプロイ
  • 長時間実行プロセス
  • きめ細かなスケーリング制御

セットアップ:

# Install Fly CLI
curl -L https://fly.io/install.sh | sh

# Initialize and deploy
fly launch
fly deploy

fly.toml:

app = "my-app"
primary_region = "sjc"

[build]
  dockerfile = "Dockerfile"

[env]
  PORT = "8080"

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0

[[http_service.checks]]
  grace_period = "10s"
  interval = "30s"
  method = "GET"
  timeout = "5s"
  path = "/api/health"

[[vm]]
  cpu_kind = "shared"
  cpus = 1
  memory_mb = 256
Docker(セルフホストに最適)

使用する場面:

  • セルフホスト可能なインフラストラクチャ
  • VPS へのデプロイ(DigitalOcean、Linode)
  • ローカル開発環境との一貫性
  • 複数サービスのオーケストレーション

Dockerfile の例については、references/deployment-platforms.md を参照してください。

AWS(エンタープライズに最適)

使用する場面:

  • エンタープライズ要件
  • コンプライアンス/規制上のニーズ
  • 複雑なインフラストラクチャ
  • マルチリージョンへのデプロイ

サービス:

  • ECS Fargate:サーバーレスコンテナ
  • Lambda:サーバーレス関数
  • Amplify:フルスタックのデプロイ
  • Elastic Beanstalk:マネージドプラットフォーム

環境設定

.env の管理

シークレットを git にコミットしないでください。ドキュメントには必ず .env.example を使用してください。

.env.example:

# Database
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"

# Authentication
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="generate-with-openssl-rand-base64-32"

# External APIs
STRIPE_SECRET_KEY="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..."

# Feature Flags
NEXT_PUBLIC_ENABLE_ANALYTICS="false"
環境変数の検証

ビルド時に環境変数を検証し、問題を早期に検出できるようにします。

src/env.mjs:

import { z } from 'zod';

const server = z.object({
  DATABASE_URL: z.string().url(),
  NEXTAUTH_SECRET: z.string().min(32),
  STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
});

const client = z.object({
  NEXT_PUBLIC_APP_URL: z.string().url(),
});

const processEnv = {
  DATABASE_URL: process.env.DATABASE_URL,
  NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
  STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
  NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
};

const merged = server.merge(client);
const parsed = merged.safeParse(processEnv);

if (!parsed.success) {
  console.error('[FAIL] Invalid environment variables:', parsed.error.flatten().fieldErrors);
  throw new Error('Invalid environment variables');
}

export const env = parsed.data;

起動時に検証するには、アプリの先頭でインポートします。

import { env } from './env.mjs';

// Use typed, validated env
const db = new PrismaClient({
  datasources: { db: { url: env.DATABASE_URL } },
});

CI/CD パイプライン

GitHub Actions ワークフロー

.github/workflows/deploy.yml を作成します。

name: Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  NODE_VERSION: '20'

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Lint
        run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build
        run: npm run build
        env:
          SKIP_ENV_VALIDATION: true

  deploy:
    runs-on: ubuntu-latest
    needs: [build]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'
キャッシュ戦略

適切なキャッシュを使って CI/CD を高速化します。

- name: Cache dependencies
  uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      .next/cache
    key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
    restore-keys: |
      ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
      ${{ runner.os }}-nextjs-

Docker の本番環境向けセットアップ

マルチステージ Dockerfile

最適化された本番環境向け Dockerfile を作成します。

Dockerfile(Next.js):

FROM node:20-alpine AS base

# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci

# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED=1

RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

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

COPY --from=builder /app/public ./public

# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next

# Automatically leverage output traces to reduce image size
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

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

next.config.js:

module.exports = {
  output: 'standalone', // Required for Docker
};
.dockerignore

Docker ビルドから不要なファイルを除外します。

Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git
.gitignore
.env*.local
.vscode
.idea
dist
build
coverage
*.md
!README.md
ビルドと実行
# Build the image
docker build -t my-app .

# Run with environment variables
docker run -p 3000:3000 \
  -e DATABASE_URL="postgresql://..." \
  -e NEXTAUTH_SECRET="..." \
  my-app

ヘルスチェック

ヘルスチェックエンドポイント

モニタリング用のヘルスチェックエンドポイントを作成します。

app/api/health/route.ts:

import { NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';

export async function GET() {
  try {
    // Check database connection
    await prisma.$queryRaw`SELECT 1`;
    
    return NextResponse.json({
      status: 'healthy',
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
      database: 'connected',
    });
  } catch (error) {
    return NextResponse.json(
      {
        status: 'unhealthy',
        timestamp: new Date().toISOString(),
        database: 'disconnected',
        error: error instanceof Error ? error.message : 'Unknown error',
      },
      { status: 503 }
    );
  }
}
Docker ヘルスチェック

Dockerfile にヘルスチェックを追加します。

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
Kubernetes のライブネス/レディネス
livenessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 15
  periodSeconds: 20

readinessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 10

プレビュー環境

PR の自動プレビュー

Vercel と Railway は、プルリクエスト用のプレビュー環境を自動的に作成します。

Railway 用 GitHub Actions:

on:
  pull_request:
    branches: [main]

jobs:
  preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Railway (PR)
        uses: bervProject/railway-deploy@main
        with:
          railway_token: ${{ secrets.RAILWAY_TOKEN }}
          service: ${{ secrets.RAILWAY_SERVICE }}
プレビュー URL を PR にコメント
- name: Comment PR
  uses: actions/github-script@v7
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '[DEPLOY] Preview deployed to: https://pr-${{ github.event.number }}.myapp.com'
      })

ロールバック戦略

即時ロールバック(Vercel)
# List deployments
vercel ls

# Promote a previous deployment to production
vercel promote <deployment-url>
ブルーグリーンデプロイ

新しいバージョンを古いバージョンと並行してデプロイし、その後トラフィックを切り替えます。

# Deploy new version (green)
fly deploy --strategy bluegreen

# Traffic switches automatically after health checks pass
# Rollback if needed:
fly releases rollback
カナリアデプロイ

新しいバージョンにトラフィックを段階的に移行します。

Fly.io のカナリアデプロイ:

# Deploy canary (10% traffic)
fly deploy --strategy canary

# Promote to 100% if successful
fly releases promote

モニタリングとエラー追跡

Sentry の統合
npm install @sentry/nextjs

sentry.client.config.ts:

import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: process.env.NODE_ENV,
  enabled: process.env.NODE_ENV === 'production',
});

sentry.server.config.ts:

import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: process.env.NODE_ENV,
});
稼働状況のモニタリング

可用性の監視には外部サービスを使用します。

/api/health エンドポイントを 1~5 分ごとに監視します。

ログの集約

Vercel:

  • 組み込みのログストリーミング
  • Datadog、LogDNA、Axiom との連携

Railway:

  • ダッシュボードに組み込みのログ
  • 外部サービスへのエクスポート

セルフホスト:

# Use Docker logging driver
docker run --log-driver=json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  my-app

CI/CD でのデータベースマイグレーション

Prisma のマイグレーション

デプロイ前にマイグレーションを実行します。

GitHub Actions:

- name: Run migrations
  run: npx prisma migrate deploy
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}

Railway: railway.json に追加します。

{
  "deploy": {
    "startCommand": "npx prisma migrate deploy && npm start"
  }
}
マイグレーションの安全性

破壊的なマイグレーションを自動で実行しないでください。

  1. まず後方互換性のあるマイグレーションを実行する

    • 新しいカラムは NULL を許容する形で追加します
    • 旧スキーマと新スキーマの両方で動作するコードをデプロイします
    • マイグレーションを実行します
    • 新しいスキーマを必要とするコードをデプロイします
    • 今後のマイグレーションで古いカラムを削除します
  2. 本番環境では手動承認を必須にする

    - name: Run migrations
      if: github.event_name == 'workflow_dispatch'
      run: npx prisma migrate deploy
    

Precision ツールとの連携

precision_exec でデプロイを検証する

precision_exec を使用して、期待値を設定したうえでデプロイコマンドを実行します。

precision_exec:
  commands:
    - cmd: "npm run build"
      expect:
        exit_code: 0
    - cmd: "docker build -t my-app ."
      expect:
        exit_code: 0
    - cmd: "npm run typecheck"
      expect:
        exit_code: 0
  verbosity: minimal
precision_fetch でヘルスチェックを行う

デプロイの健全性を検証します。

precision_fetch:
  requests:
    - url: "https://my-app.com/api/health"
      method: GET
      expect:
        status: 200
        body_contains: '"status":"healthy"'
デプロイに関する不足を検出する

デプロイ前に、設定の不足がないか確認します。

discover:
  queries:
    - id: env_example
      type: glob
      patterns: [".env.example"]
    - id: dockerfile
      type: glob
      patterns: ["Dockerfile", "docker-compose.yml"]
    - id: ci_config
      type: glob
      patterns: [".github/workflows/*.yml"]
    - id: health_check
      type: grep
      pattern: '/api/health|/health'
      glob: "**/*.{ts,tsx,js,jsx}"
  output_mode: count_only

デプロイ前のチェックリスト

検証スクリプトを実行します。

./plugins/goodvibes/skills/outcome/deployment/scripts/validate-deployment.sh /path/to/project

スクリプトでは次の項目を確認します。

  1. Dockerfile が存在する
  2. .env.example が存在し、必要な変数が記載されている
  3. CI/CD の設定が存在する
  4. ヘルスチェック用エンドポイントが実装されている
  5. .dockerignore が存在する
  6. コードにハードコードされたシークレットがない
  7. ビルドコマンドが成功する
  8. データベースマイグレーションの設定が存在する

よくある落とし穴

1. 環境変数の不足

問題: 環境変数が設定されていないため、デプロイに失敗します。

解決策: すべての変数を .env.example に記載し、zod を使ってビルド時に検証します。

2. データベースのコネクションプーリング

問題: サーバーレス関数がデータベース接続を使い果たします。

解決策: コネクションプーリングを使用します(PgBouncer、Prisma Accelerate、Supabase pooler)。

// Use connection pooler in serverless
const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL, // Use pooled connection string
    },
  },
});
3. ビルド出力が最適化されていない

問題: Docker イメージが大きく、コールドスタートが遅くなります。

解決策: マルチステージビルド、Next.js の standalone 出力、適切な .dockerignore を使用します。

4. デプロイのたびにマイグレーションが実行される

問題: コンテナの起動のたびに Prisma のマイグレーションが実行されます。

解決策: CI/CD でマイグレーションのステップをアプリの起動から分離します。

5. ロールバック計画がない

問題: 問題のあるデプロイによって本番環境に障害が発生し、簡単に修正できません。

解決策: 即時ロールバックが可能なプラットフォーム(Vercel、Railway、Fly.io)を使用するか、以前の Docker イメージを保持します。

まとめ

主な原則:

  1. 環境変数をビルド時に検証する - 本番環境ではなく、早い段階で失敗させます
  2. すべてを自動化する - CI/CD で lint、test、build、deploy を実行します
  3. ヘルスチェックは必須 - すべてのサービスにヘルスチェック用エンドポイントが必要です
  4. すべての PR にプレビュー環境を用意する - マージ前に問題を検出します
  5. 必ずロールバック計画を用意する - 前方修正より即時ロールバックを優先します
  6. 初日から監視する - エラー追跡と稼働時間の監視は必須です
  7. マイグレーションにはリスクがある - 後方互換性を確保し、慎重に実行します

次のステップ:

  1. プロジェクトで validate-deployment.sh を実行します
  2. GitHub Actions を使って CI/CD パイプラインを設定します
  3. プラットフォームで環境変数を設定します
  4. ヘルスチェック用エンドポイントを追加します
  5. ステージング環境へのデプロイをテストします
  6. 本番環境にデプロイします
  7. 監視とアラートを設定します

プラットフォームの詳しい設定とテンプレートについては、references/deployment-platforms.md を参照してください。

コメント