deployment について
deploymentは、Next.js、フルスタック、コンテナ化、サーバーレスのアプリを本番環境へデプロイする開発者向けのスキルです。プラットフォーム選定、CI/CD、ヘルスチェック、監視、ロールバックを扱い、検証スクリプトも含みます。
主な機能
- 01プラットフォーム選定と環境設定
- 02GitHub ActionsによるCI/CD構築
- 03本番用Dockerイメージの作成
- 04ヘルスチェックと監視の設定
- 05プレビューとロールバックの計画
- 06デプロイ前チェックの実行
活用シーン
- 01Next.jsアプリの本番デプロイ
- 02コンテナサービスのリリース手順整備
- 03プルリクエスト用プレビューの作成
- 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,
});
稼働状況のモニタリング
可用性の監視には外部サービスを使用します。
- Better Uptime:https://betteruptime.com
- Pingdom:https://www.pingdom.com
- UptimeRobot:https://uptimerobot.com
/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"
}
}
マイグレーションの安全性
破壊的なマイグレーションを自動で実行しないでください。
-
まず後方互換性のあるマイグレーションを実行する
- 新しいカラムは NULL を許容する形で追加します
- 旧スキーマと新スキーマの両方で動作するコードをデプロイします
- マイグレーションを実行します
- 新しいスキーマを必要とするコードをデプロイします
- 今後のマイグレーションで古いカラムを削除します
-
本番環境では手動承認を必須にする
- 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
スクリプトでは次の項目を確認します。
- Dockerfile が存在する
- .env.example が存在し、必要な変数が記載されている
- CI/CD の設定が存在する
- ヘルスチェック用エンドポイントが実装されている
- .dockerignore が存在する
- コードにハードコードされたシークレットがない
- ビルドコマンドが成功する
- データベースマイグレーションの設定が存在する
よくある落とし穴
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 イメージを保持します。
まとめ
主な原則:
- 環境変数をビルド時に検証する - 本番環境ではなく、早い段階で失敗させます
- すべてを自動化する - CI/CD で lint、test、build、deploy を実行します
- ヘルスチェックは必須 - すべてのサービスにヘルスチェック用エンドポイントが必要です
- すべての PR にプレビュー環境を用意する - マージ前に問題を検出します
- 必ずロールバック計画を用意する - 前方修正より即時ロールバックを優先します
- 初日から監視する - エラー追跡と稼働時間の監視は必須です
- マイグレーションにはリスクがある - 後方互換性を確保し、慎重に実行します
次のステップ:
- プロジェクトで
validate-deployment.shを実行します - GitHub Actions を使って CI/CD パイプラインを設定します
- プラットフォームで環境変数を設定します
- ヘルスチェック用エンドポイントを追加します
- ステージング環境へのデプロイをテストします
- 本番環境にデプロイします
- 監視とアラートを設定します
プラットフォームの詳しい設定とテンプレートについては、references/deployment-platforms.md を参照してください。