
GitHub Actions による CI/CD パイプライン構築実践ガイド
受託開発・自社開発の現場では、コードの品質を保ちながら素早くリリースするために CI/CD パイプラインが不可欠です。GitHub Actions は GitHub に統合されており、追加のサービス契約なしで自動テスト・ビルド・デプロイを実現できます。
本記事では、実務で即使える GitHub Actions の実装パターンを、ワークフロー設計から本番デプロイまで具体例とともに解説します。
1. GitHub Actions の基本構成と設計方針
ワークフローファイルの配置
GitHub Actions は .github/workflows/ ディレクトリ配下の YAML ファイルで定義します。実務では用途別に複数ファイルに分割すると管理しやすくなります。
.github/
└── workflows/
├── ci.yml # プルリクエスト時の自動テスト
├── deploy-stg.yml # ステージング環境へのデプロイ
└── deploy-prod.yml # 本番環境へのデプロイ
設計の基本方針
| 観点 | 推奨アプローチ | 理由 | |------|--------------|------| | トリガー | PR 時は軽量テスト、main マージ時は完全テスト | フィードバック速度とコスト削減 | | ジョブ分割 | テスト・ビルド・デプロイを別ジョブに | 失敗箇所の特定が容易 | | 環境変数 | Repository Secrets で管理 | 認証情報の Git 管理を回避 | | キャッシュ | 依存パッケージをキャッシュ | ビルド時間を 30〜50% 短縮 | | 並列実行 | Matrix Strategy で複数環境テスト | Node.js 複数バージョン対応など |
2. プルリクエスト時の自動テストワークフロー
基本的な CI ワークフロー
TypeScript + Next.js プロジェクトでの典型例です。
# .github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
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 run test:unit
- name: Build
run: npm run build
env:
NODE_ENV: production
実装のポイント
npm ciを使う:npm installより高速で、package-lock.json と厳密に一致- Matrix Strategy: 複数の Node.js バージョンで並列テスト
- cache: 'npm': node_modules のキャッシュで 2 回目以降が高速化
- 段階的チェック: Lint → 型チェック → テスト → ビルド の順で早期に失敗させる
3. 環境変数とシークレット管理
Repository Secrets の設定
GitHub リポジトリの Settings > Secrets and variables > Actions で設定します。
必須シークレット例:
| Secret 名 | 用途 | 例 |
|-----------|------|----|
| DATABASE_URL | DB 接続文字列 | postgresql://user:pass@host/db |
| NEXT_PUBLIC_API_URL | API エンドポイント | https://api.example.com |
| VERCEL_TOKEN | Vercel デプロイ | xxxxx |
| AWS_ACCESS_KEY_ID | AWS 認証 | AKIAIOSFODNN7EXAMPLE |
| AWS_SECRET_ACCESS_KEY | AWS 認証 | wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY |
ワークフローでの使用例
- name: Run E2E tests
run: npm run test:e2e
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
Environment による環境別管理
ステージング・本番で異なる値を使う場合は Environment を活用します。
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # Environment 名
steps:
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }} # production 環境の値が使われる
実務 Tips:
- 環境ごとに Approval を設定すると、本番デプロイ前に手動承認を挟める
.env.exampleにキー一覧を記載し、ドキュメント化- ローカル開発用の
.env.localは.gitignoreに追加
4. キャッシュ戦略による高速化
依存パッケージのキャッシュ
actions/setup-node の cache オプションが最もシンプルです。
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # または 'yarn', 'pnpm'
ビルド成果物のキャッシュ
Next.js の .next ディレクトリなど、ビルド成果物もキャッシュできます。
- name: Cache Next.js build
uses: actions/cache@v4
with:
path: |
.next/cache
node_modules/.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-
キャッシュの効果測定
| 項目 | キャッシュなし | キャッシュあり | 削減率 | |------|--------------|--------------|--------| | npm install | 45 秒 | 8 秒 | 82% | | Next.js build | 120 秒 | 70 秒 | 42% | | 合計 | 165 秒 | 78 秒 | 53% |
5. テストカバレッジとレポート表示
Jest でのカバレッジ収集
- name: Run tests with coverage
run: npm run test:coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/coverage-final.json
fail_ci_if_error: true
PR コメントへの結果表示
actions/github-script を使うと、PR コメントにカバレッジを投稿できます。
- name: Comment coverage on PR
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const coverage = JSON.parse(fs.readFileSync('./coverage/coverage-summary.json', 'utf8'));
const total = coverage.total;
const comment = `## Test Coverage\n\n` +
`- **Statements**: ${total.statements.pct}%\n` +
`- **Branches**: ${total.branches.pct}%\n` +
`- **Functions**: ${total.functions.pct}%\n` +
`- **Lines**: ${total.lines.pct}%`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
6. ステージング・本番環境へのデプロイ
Vercel へのデプロイ例
# .github/workflows/deploy-prod.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
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'
AWS S3 + CloudFront へのデプロイ
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Build
run: npm run build
- name: Deploy to S3
run: |
aws s3 sync ./out s3://${{ secrets.S3_BUCKET }} --delete
- name: Invalidate CloudFront cache
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
--paths "/*"
デプロイ戦略の比較
| 戦略 | 実装方法 | メリット | 課題 |
|------|---------|---------|------|
| main マージ即デプロイ | on: push: branches: [main] | シンプル、速い | ロールバックが手動 |
| タグベースデプロイ | on: push: tags: ['v*'] | リリースタイミング制御 | タグ作成が必要 |
| 手動トリガー | on: workflow_dispatch | 完全制御 | 自動化されない |
| Environment 承認 | environment: production | 本番前チェック | 承認待ちで遅延 |
7. マトリクステストとブランチ戦略
複数環境での並列テスト
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18.x, 20.x]
include:
- os: ubuntu-latest
node-version: 20.x
run-e2e: true # Ubuntu + Node 20 でのみ E2E テスト実行
steps:
- name: Run E2E tests
if: matrix.run-e2e
run: npm run test:e2e
ブランチ別の実行制御
on:
push:
branches:
- main
- develop
- 'feature/**'
pull_request:
branches:
- main
- develop
jobs:
quick-test:
if: github.ref != 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: npm run test:unit # 軽量テストのみ
full-test:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: npm run test # 全テスト実行
- run: npm run test:e2e
実務での使い分け:
- Feature ブランチ: Lint + 単体テストのみ(5 分以内)
- Develop ブランチ: 単体 + 統合テスト(10 分以内)
- Main ブランチ: 全テスト + E2E + デプロイ(20 分以内)
8. トラブルシューティングとモニタリング
よくある失敗パターンと対処法
| 症状 | 原因 | 解決策 |
|------|------|--------|
| npm ci が失敗 | package-lock.json の不整合 | ローカルで npm install 後コミット |
| キャッシュが効かない | key の指定ミス | hashFiles() でファイル変更を検知 |
| シークレットが空 | Environment 未指定 | environment: production を追加 |
| タイムアウト | デフォルト 360 分制限 | timeout-minutes: 30 で早期終了 |
| 並列ジョブの依存関係 | needs 未指定 | needs: [test, build] で順序制御 |
デバッグ方法
- name: Debug environment
run: |
echo "Node version: $(node -v)"
echo "NPM version: $(npm -v)"
echo "Working directory: $(pwd)"
ls -la
printenv | grep -v SECRET # シークレット以外の環境変数表示
Slack 通知の追加
- name: Notify Slack on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "❌ Deployment failed: ${{ github.repository }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Workflow*: ${{ github.workflow }}\n*Branch*: ${{ github.ref }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
9. コスト最適化のチェックリスト
GitHub Actions は Public リポジトリでは無料ですが、Private では月 2,000 分の制限があります。
コスト削減のための実践項目
- [ ] キャッシュを活用:依存パッケージとビルド成果物をキャッシュ
- [ ] 軽量ランナーを選択:
ubuntu-latestはwindows-latestより 2 倍速い - [ ] 条件分岐で無駄な実行を削減:ドキュメント変更時はテストスキップ
- [ ] 並列数を制限:Matrix の組み合わせを必要最小限に
- [ ] タイムアウトを設定:無限ループ防止
- [ ] Self-hosted Runner を検討:大規模プロジェクトでは自前サーバーが安い
on:
push:
paths-ignore:
- '**.md'
- 'docs/**'
jobs:
test:
timeout-minutes: 15 # デフォルト 360 分を短縮
まとめ
GitHub Actions による CI/CD パイプラインは、以下の手順で段階的に構築できます。
- 基本の CI ワークフロー:Lint・型チェック・テスト・ビルドを自動化
- キャッシュ戦略:npm ci とビルド成果物のキャッシュで 50% 高速化
- 環境変数管理:Repository Secrets と Environment で安全に管理
- デプロイ自動化:main マージで自動デプロイ、Environment で承認制御
- マトリクステスト:複数環境での並列テストでカバレッジ向上
- モニタリング:Slack 通知とカバレッジレポートで品質可視化
実務では、まず PR 時の自動テストから始め、安定したら自動デプロイへ拡張するアプローチが成功しやすいです。
Yureate では、CI/CD パイプライン構築や GitHub Actions を活用した開発フロー改善を支援しています。ご相談は お問い合わせページ からお気軽にどうぞ。
