mcpField
D
deployment-automation

deployment-automation

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

deployment-automation について

本番環境でNext.jsアプリを運用するチーム向けのデプロイガイドスキルです。Vercel、GitHub ActionsのCI/CD、環境管理、事前確認、監視、ロールバックを扱います。

主な機能

  1. 01Vercelの本番・プレビュー環境へのデプロイ
  2. 02GitHub ActionsのCI/CD例
  3. 03環境変数の管理
  4. 04デプロイ前確認とマイグレーション
  5. 05監視とロールバックの戦略
  6. 06機能フラグとパフォーマンス予算

活用シーン

  1. 01Next.jsの自動デプロイ設定
  2. 02プルリクエスト用プレビュー構築
  3. 03リリース前の確認と移行実行
  4. 04本番環境のロールバック計画

インストール

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

$npx skills add https://github.com/jmsktm/claude-settings --skill deployment-automation

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

詳細

デプロイ自動化スキル

概要

このスキルは、本番環境で Next.js アプリケーションをデプロイし、管理するのに役立ちます。Vercel へのデプロイから CI/CD パイプラインまで、デプロイをスムーズに自動化するために必要なすべてを網羅しています。

Vercel へのデプロイ

Vercel CLI のインストール
npm i -g vercel
vercel login
本番環境へのデプロイ
# Deploy to production
vercel --prod

# Deploy with specific environment
vercel --prod --env production
Git からのデプロイ
# Link project
vercel link

# Auto-deploy on git push (configured in Vercel dashboard)
git push origin main  # Auto-deploys to production
git push origin develop  # Auto-deploys to preview
プロジェクト設定
// vercel.json
{
  "buildCommand": "npm run build",
  "devCommand": "npm run dev",
  "installCommand": "npm install",
  "framework": "nextjs",
  "regions": ["iad1"],  // AWS us-east-1
  "env": {
    "NEXT_PUBLIC_APP_URL": "https://myapp.com"
  },
  "build": {
    "env": {
      "NEXT_PUBLIC_VERCEL_ENV": "@vercel-env"
    }
  },
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "X-Content-Type-Options",
          "value": "nosniff"
        },
        {
          "key": "X-Frame-Options",
          "value": "DENY"
        },
        {
          "key": "X-XSS-Protection",
          "value": "1; mode=block"
        }
      ]
    }
  ],
  "redirects": [
    {
      "source": "/old-page",
      "destination": "/new-page",
      "permanent": true
    }
  ],
  "rewrites": [
    {
      "source": "/api/:path*",
      "destination": "https://api.backend.com/:path*"
    }
  ]
}
環境変数

Vercel CLI を使用する場合:

# Add production env var
vercel env add SUPABASE_URL production

# Add to all environments
vercel env add DATABASE_URL

# Pull env vars locally
vercel env pull .env.local

Vercel ダッシュボードを使用する場合:

  1. Project Settings → Environment Variables に移動します
  2. 各環境用の変数を追加します:
    • 本番環境
    • プレビュー
    • 開発環境

暗号化されたシークレット:

# Add sensitive data
vercel secrets add database-url "postgresql://..."

# Reference in vercel.json
{
  "env": {
    "DATABASE_URL": "@database-url"
  }
}
環境ごとの設定
// lib/config.ts
const config = {
  development: {
    apiUrl: 'http://localhost:3000/api',
    supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
  },
  preview: {
    apiUrl: process.env.NEXT_PUBLIC_API_URL!,
    supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
  },
  production: {
    apiUrl: 'https://api.myapp.com',
    supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
  },
}

const env = (process.env.NEXT_PUBLIC_VERCEL_ENV || 'development') as keyof typeof config

export const appConfig = config[env]

GitHub Actions CI/CD

基本的なワークフロー
# .github/workflows/ci.yml
name: CI

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

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run linter
        run: npm run lint

      - name: Run type check
        run: npm run type-check

      - name: Run tests
        run: npm test

      - name: Build
        run: npm run build
        env:
          NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
          NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
GitHub Actions から Vercel へのデプロイ
# .github/workflows/deploy.yml
name: Deploy to Vercel

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    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'
PR でのテスト実行
# .github/workflows/pr-checks.yml
name: PR Checks

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  quality:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Type check
        run: npm run type-check

      - name: Unit tests
        run: npm test

      - name: E2E tests
        run: npx playwright test

      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

デプロイ前のチェック

カスタムデプロイ前スクリプト
// package.json
{
  "scripts": {
    "predeploy": "npm run check:all",
    "check:all": "npm run lint && npm run type-check && npm test",
    "lint": "next lint",
    "type-check": "tsc --noEmit",
    "test": "jest"
  }
}
ヘルスチェックエンドポイント
// app/api/health/route.ts
import { NextResponse } from 'next/server'

export async function GET() {
  try {
    // Check database connection
    await db.$queryRaw`SELECT 1`

    // Check external services
    const services = await Promise.allSettled([
      fetch(process.env.API_URL!),
      fetch(process.env.SUPABASE_URL!),
    ])

    const allHealthy = services.every(s => s.status === 'fulfilled')

    return NextResponse.json({
      status: allHealthy ? 'healthy' : 'degraded',
      timestamp: new Date().toISOString(),
      version: process.env.NEXT_PUBLIC_APP_VERSION,
      services: {
        database: 'healthy',
        api: services[0].status === 'fulfilled' ? 'healthy' : 'unhealthy',
        supabase: services[1].status === 'fulfilled' ? 'healthy' : 'unhealthy',
      }
    })
  } catch (error) {
    return NextResponse.json(
      { status: 'unhealthy', error: error.message },
      { status: 503 }
    )
  }
}

データベースのマイグレーション

デプロイ時にマイグレーションを実行
// package.json
{
  "scripts": {
    "build": "npm run db:migrate && next build",
    "db:migrate": "npx supabase db push"
  }
}
安全なマイグレーション戦略
# 1. Test migration locally
npx supabase db reset
npx supabase db push

# 2. Create backup
npx supabase db dump > backup.sql

# 3. Apply to production
npx supabase db push --linked

# 4. Verify
curl https://myapp.com/api/health

モニタリングとアラート

Vercel Speed Insights
// app/layout.tsx
import { SpeedInsights } from '@vercel/speed-insights/next'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <SpeedInsights />
      </body>
    </html>
  )
}
Vercel Analytics
import { Analytics } from '@vercel/analytics/react'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
      </body>
    </html>
  )
}
カスタムモニタリング
// lib/monitoring.ts
export async function reportDeployment() {
  if (process.env.NODE_ENV === 'production') {
    await fetch('https://monitoring.example.com/deployments', {
      method: 'POST',
      body: JSON.stringify({
        version: process.env.NEXT_PUBLIC_APP_VERSION,
        timestamp: new Date().toISOString(),
        environment: process.env.NEXT_PUBLIC_VERCEL_ENV,
      }),
    })
  }
}

// Call in app initialization
reportDeployment()

フィーチャーフラグ

環境ベースのフラグ
// lib/features.ts
export const features = {
  newDesign: process.env.NEXT_PUBLIC_FEATURE_NEW_DESIGN === 'true',
  betaFeatures: process.env.NEXT_PUBLIC_FEATURE_BETA === 'true',
  analytics: process.env.NEXT_PUBLIC_FEATURE_ANALYTICS === 'true',
}

// Usage
import { features } from '@/lib/features'

export function Component() {
  if (!features.newDesign) {
    return <OldDesign />
  }
  return <NewDesign />
}
高度なフィーチャーフラグ(Vercel Edge Config)
import { get } from '@vercel/edge-config'

export async function getFeatureFlag(key: string): Promise<boolean> {
  try {
    return await get<boolean>(key) ?? false
  } catch {
    return false
  }
}

// Usage in Server Component
export default async function Page() {
  const showNewFeature = await getFeatureFlag('new-feature')

  if (showNewFeature) {
    return <NewFeature />
  }
  return <OldFeature />
}

ロールバック戦略

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

# Promote previous deployment to production
vercel promote <deployment-url>
エラー発生時の自動ロールバック
# .github/workflows/deploy-with-rollback.yml
name: Deploy with Rollback

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Get previous deployment
        id: prev-deploy
        run: |
          PREV_URL=$(vercel ls --token=${{ secrets.VERCEL_TOKEN }} | grep production | head -n 2 | tail -n 1 | awk '{print $2}')
          echo "prev_url=$PREV_URL" >> $GITHUB_OUTPUT

      - name: Deploy to Vercel
        id: deploy
        run: |
          URL=$(vercel --prod --token=${{ secrets.VERCEL_TOKEN }})
          echo "deploy_url=$URL" >> $GITHUB_OUTPUT

      - name: Health check
        id: health
        run: |
          sleep 10
          STATUS=$(curl -s -o /dev/null -w "%{http_code}" ${{ steps.deploy.outputs.deploy_url }}/api/health)
          if [ $STATUS -ne 200 ]; then
            echo "Health check failed"
            exit 1
          fi

      - name: Rollback on failure
        if: failure()
        run: |
          vercel promote ${{ steps.prev-deploy.outputs.prev_url }} --token=${{ secrets.VERCEL_TOKEN }}

プレビューデプロイ

プレビュー URL の自動生成

ブランチにプッシュするたびに固有の URL が生成されます:

https://myapp-git-feature-branch-username.vercel.app
PR へのプレビューコメント
# .github/workflows/preview-comment.yml
name: Preview Deployment Comment

on:
  deployment_status:

jobs:
  comment:
    if: github.event.deployment_status.state == 'success'
    runs-on: ubuntu-latest

    steps:
      - name: Comment PR
        uses: actions/github-script@v6
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `✅ Preview deployed to ${process.env.DEPLOYMENT_URL}`
            })

パフォーマンス予算

Lighthouse CI
# .github/workflows/lighthouse.yml
name: Lighthouse CI

on:
  pull_request:
    branches: [main]

jobs:
  lighthouse:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Run Lighthouse CI
        uses: treosh/lighthouse-ci-action@v10
        with:
          urls: |
            https://preview-url.vercel.app
            https://preview-url.vercel.app/dashboard
          uploadArtifacts: true
          temporaryPublicStorage: true
バンドルサイズのチェック
# .github/workflows/bundle-size.yml
name: Bundle Size Check

on: [pull_request]

jobs:
  size:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Check bundle size
        uses: andresz1/size-limit-action@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

ベストプラクティスのチェックリスト

  • シークレットには環境変数を使用する
  • Git からの自動デプロイを設定する
  • PR 用のプレビューデプロイを設定する
  • ヘルスチェックエンドポイントを実装する
  • モニタリングとアラートを設定する
  • デプロイ前にテストを実行する
  • 段階的なロールアウトにはフィーチャーフラグを使用する
  • ロールバック戦略を用意する
  • Core Web Vitals をモニタリングする
  • パフォーマンス予算を設定する
  • データベースのマイグレーションを安全に実行する
  • 環境を分けて使用する(開発/ステージング/本番)
  • 適切なエラートラッキングを実装する
  • デプロイプロセスを文書化する

このスキルを使用するタイミング

次の場合にこのスキルを呼び出します:

  • 初めて Vercel にデプロイするとき
  • CI/CD パイプラインを設定するとき
  • 環境変数を設定するとき
  • フィーチャーフラグを実装するとき
  • モニタリングを設定するとき
  • ロールバック戦略を作成するとき
  • デプロイ速度を最適化するとき
  • 本番環境の問題をデバッグするとき
  • プレビューデプロイを管理するとき
  • 自動テストを設定するとき

コメント