CI/CD
Bobは手動デプロイのたびにミスをしています - マイグレーションの実行忘れ, 環境変数の設定ミス, テスト未通過のコードの本番へのプッシュ。CharlieはCI/CDの自動化を必要としています:コードプッシュ時の自動テスト, プルリクエストの自動プレビュー, mainブランチからの本番への自動デプロイ, すべて手動介入なしで実現します。
1. 学ぶ内容
- GitHub Actionsワークフロー:lint → test → build → deploy
- コード品質チェック:ESLint + Prettier + TypeCheck + Vitestコードカバレッジ
- 環境管理:development → staging → production
- デプロイ戦略:ブルーグリーンデプロイ + ローリングアップデート + ロールバック
- MegaShop PR自動プレビュー + main自動デプロイ
2. 管理者のリアルストーリー
(1) ペインポイント:手動デプロイでの頻繁なミス
BobはMegaShopを手動でデプロイしています。手順は:1) リポジトリをクローン 2) npm installを実行 3) テストを実行 (忘れた) 4) ビルド 5) アップロード 6) マイグレーションを実行 (忘れた) 7) サービスを再起動。1つのステップでも抜かすと問題が発生し, 月に平均2回のデプロイインシデントが起きています。
(2) GitHub Actions CI/CDソリューション
プッシュのたびにフルプロセスが自動実行されます:
YAML
# .github/workflows/deploy.yml
on: push
jobs:
test: → lint + typecheck + vitest
build: → npm run build
deploy: → docker compose up -d
(3) 利点:手作業ゼロ + インシデントゼロ
コードプッシュ後の完全自動テスト, ビルド, デプロイ;プルリクエストは自動的にプレビュー環境を生成;コードのmainブランチへのマージは自動デプロイ;デプロイインシデントがゼロに。
3. GitHub Actionsワークフロー
(1) CI/CDパイプラインの段階
flowchart LR
A[Push / PR] --> B[Lint + TypeCheck]
B --> C[ユニットテスト]
C --> D[ビルド]
D --> E{ブランチ?}
E -->|PR| F[プレビューデプロイ]
E -->|main| G[ステージングデプロイ]
G --> H[スモークテスト]
H --> I[本番デプロイ]
I --> J[ヘルスチェック]
J --> K[完了 ✅]
(1) ▶サンプル:完全なCIワークフロー
YAML
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npx nuxi typecheck
test:
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: megashop_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
DATABASE_URL: postgresql://test:test@localhost:5432/megashop_test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx prisma migrate deploy
- run: npm run test:coverage
- name: カバレッジのアップロード
uses: codecov/codecov-action@v4
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx prisma generate
- run: npm run build
- name: ビルド成果物のアップロード
uses: actions/upload-artifact@v4
with:
name: nuxt-build
path: .output/
出力:
TEXT
CI/CDパイプラインが読み込まれました
パイプラインステータス:合格
テスト:12件合格, 0件不合格
4. コード品質管理
(1) 品質ゲート設定
(1) ▶サンプル:ESLint + Prettier設定
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/eslint'],
eslint: {
config: {
stylistic: {
indent: 2,
quotes: 'single',
semi: false
}
}
}
})
出力:
TEXT
// 実行成功
(2) ▶サンプル:package.jsonスクリプト
JSON
{
"scripts": {
"dev": "nuxi dev",
"build": "nuxi build",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"typecheck": "nuxi typecheck",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"validate": "npm run lint && npm run typecheck && npm run test"
}
}
出力:
JSON
{
"scripts": {
"dev": "nuxi dev",
"build": "nuxi build",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"typecheck": "nuxi typecheck",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"validate": "npm run lint && npm run typecheck && npm run test"
}
}
(2) 品質ゲート指標
| 指標 | ツール | ゲート閾値 | 説明 |
|---|---|---|---|
| コードスタイル | ESLint | 0エラー | 一貫したコードスタイル |
| フォーマット | Prettier | 0警告 | 自動フォーマット |
| 型チェック | vue-tsc | 0エラー | TypeScript型安全性 |
| ユニットテスト | Vitest | ≥ 80%カバレッジ | コアロジックのカバー |
| E2Eテスト | Playwright | 全て合格 | 主要フローの検証 |
| バンドルサイズ | rollup-plugin | < 200 KB gzip | サイズ膨張の防止 |
5. マルチ環境管理
(1) ▶サンプル:環境設定ファイル
TEXT
# .env.development
DATABASE_URL=postgresql://dev:dev@localhost:5432/megashop_dev
REDIS_URL=redis://localhost:6379
JWT_ACCESS_SECRET=dev-access-secret
# .env.staging
DATABASE_URL=postgresql://staging:xxx@staging-db.internal:5432/megashop_staging
REDIS_URL=redis://staging-redis.internal:6379
JWT_ACCESS_SECRET=${{ secrets.STAGING_JWT_SECRET }}
# .env.production
DATABASE_URL=postgresql://prod:xxx@prod-db.internal:5432/megashop
REDIS_URL=redis://prod-redis.internal:6379
JWT_ACCESS_SECRET=${{ secrets.PROD_JWT_SECRET }}
(2) ▶サンプル:ステージングデプロイワークフロー
YAML
# .github/workflows/deploy-staging.yml
name: Deploy Staging
on:
push:
branches: [main]
jobs:
deploy-staging:
runs-on: ubuntu-latest
needs: [lint, test]
environment: staging
steps:
- uses: actions/checkout@v4
- name: ステージングにデプロイ
run: |
ssh staging-server << 'EOF'
cd /opt/megashop
git pull origin main
docker compose up -d --build
docker compose exec web npx prisma migrate deploy
EOF
- name: スモークテスト
run: |
sleep 10
curl -f https://staging.megashop.com/api/products?limit=1 || exit 1
- name: チームに通知
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{"text": "ステージングデプロイが失敗しました!"}
出力:
TEXT
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx:latest Up 2 hours 0.0.0.0:80->80/tcp
(1) 環境の比較
| 環境 | 目的 | データベース | デプロイ方法 | アクセス権限 |
|---|---|---|---|---|
| development | ローカル開発 | ローカルPostgreSQL | npm run dev | 開発者 |
| staging | 統合テスト | 独立したPostgreSQL | 自動 (mainプッシュ) | チーム |
| production | 本番環境 | 本番PostgreSQL | 自動 (tag/release) | 全ユーザー |
6. デプロイ戦略
(1) デプロイ戦略の比較
| 戦略 | 原理 | ダウンタイム | ロールバック速度 | 複雑さ |
|---|---|---|---|---|
| 直接置き換え | 古いものを止めて新しいものを起動 | 🔴 あり (5-30秒) | 🟡 再デプロイ | 🟢 シンプル |
| ブルーグリーンデプロイ | 2つの環境を切り替え | 🟢 なし | 🟢 数秒で切り替え | 🟡 中 |
| ローリングアップデート | インスタンスを1つずつ置き換え | 🟢 なし | 🟡 1つずつロールバック | 🟡 中 |
| カナリアリリース | 少数のユーザーで先に検証 | 🟢 なし | 🟢 即座にロールバック | 🔴 複雑 |
(1) ▶サンプル:ブルーグリーンデプロイスクリプト
BASH
#!/bin/bash
# deploy-blue-green.sh
CURRENT=$(docker compose ps --format '{{.Name}}' | grep -o 'blue\|green' | head -1)
if [ "$CURRENT" = "blue" ]; then
NEXT="green"
else
NEXT="blue"
fi
echo "$NEXT環境にデプロイ中..."
# 次の環境をビルドして起動
docker compose -f docker-compose.yml -f docker-compose.$NEXT.yml up -d --build
# ヘルスチェックを待機
for i in {1..30}; do
if curl -sf http://localhost:3001/health; then
echo "ヘルスチェック合格"
break
fi
sleep 2
done
# Nginxを新しい環境に切り替え
sed "s/$CURRENT/$NEXT/g" nginx.conf > /tmp/nginx.conf
docker compose exec nginx nginx -s reload
echo "$CURRENTから$NEXTに切り替えました"
出力:
TEXT
CONTAINER ID IMAGE STATUS
abc123 latest Up 2 hours
7. 総合例:MegaShopの完全なCI/CDフロー
YAML
# .github/workflows/deploy-production.yml
name: Deploy Production
on:
release:
types: [published]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Dockerイメージをビルド
run: docker build -t megashop:${{ github.sha }} .
- name: レジストリにプッシュ
run: |
docker tag megashop:${{ github.sha }} ghcr.io/megashop/megashop:latest
echo ${{ secrets.GHCR_TOKEN }} | docker login ghcr.io -u $ --password-stdin
docker push ghcr.io/megashop/megashop:latest
- name: 本番にデプロイ
run: |
ssh prod-server << EOF
cd /opt/megashop
docker pull ghcr.io/megashop/megashop:latest
docker compose up -d --no-build
docker compose exec web npx prisma migrate deploy
EOF
- name: ヘルスチェック
run: |
for i in {1..10}; do
if curl -sf https://megashop.com/api/health; then exit 0; fi
sleep 5
done
exit 1
- name: 失敗時にロールバック
if: failure()
run: |
ssh prod-server << EOF
cd /opt/megashop
docker compose down
docker tag megashop:previous megashop:latest
docker compose up -d
EOF
❓よくある質問
Q GitHub Actionsの無料枠で十分ですか?
A パブリックリポジトリは無制限の分数があります。プライベートリポジトリは月間2,000分の制限があります。MegaShopの1回のCI実行は約10分なので, 1日10回実行しても約100分であり, 十分です。
Q PRプレビュー環境はどのように設定しますか?
A Vercel Previewで自動生成されます。各PRには独自のURL (pr-123-megashop.vercel.app)があり, プルリクエストのマージ後に自動的に削除されます。
Q CIでデータベースマイグレーションはどのように実行しますか?
A CIでは
prisma migrate deployを使用してください (既存のマイグレーションのみを適用し, 新しいものは作成しません)。開発中はprisma migrate devでマイグレーションファイルを作成し, Gitにコミットしてください。Q ゼロダウンタイムデプロイはどのように実現しますか?
A ブルーグリーンデプロイ (2つの環境を切り替え)またはPM2クラスタリロード (ワーカーを1つずつ置き換え)を使用してください。Dockerではローリングアップデートを使用します。
Q ロールバックはどのように行いますか?
A
git revertして再デプロイしてください。Dockerでは前のイメージタグで再起動します。PM2ではpm2 stopしてから旧バージョンを起動します。自動ロールバックのためには, デプロイスクリプトにヘルスチェック失敗時の処理ロジックを追加してください。Q シークレットはどのように安全に管理すべきですか?
A シークレットはGitHub Secretsに環境変数として保存し, Gitにコミットしないでください。
runtimeConfigのプライベートフィールドはサーバーサイドのみです。CIでは${{ secrets.XXX }}で参照してください。📖まとめ
- GitHub Actionsを使用して完全自動化パイプライン (lint → test → build → deploy)を実装
- コード品質要件:ESLint + TypeCheck + Vitest ≥ 80%カバレッジ
- 3環境管理:development (ローカル)→ staging (統合テスト)→ production (本番)
- ブルーグリーンデプロイでダウンタイムゼロを確保;ヘルスチェック失敗時に自動ロールバック
- MegaShop:PR自動プレビュー + main自動ステージング + release自動本番デプロイ
📝練習問題
- 基本問題 (難易度:⭐):GitHub Actions CIワークフローを作成し, コミットプッシュ時に自動的にlint, 型チェック, テストを実行してください
- 応用問題 (難易度:⭐⭐):ステージングへの自動デプロイを追加してください - mainブランチのプッシュ時に自動的にステージングサーバーにデプロイし, デプロイ後にスモークテストを実行してください
- チャレンジ (難易度:⭐⭐⭐):ブルーグリーンデプロイスクリプト + 自動ロールバックを実装してください - ヘルスチェックが失敗した場合に自動的に前のバージョンに切り替える仕組みを構築してください
---|



