GitHub Actions CI/CD完全ガイド - 自動化パイプラインの構築

中級 | 75分 で読める | 2025.12.02

公式ドキュメント

今回やること

GitHub Actionsは、GitHubに統合されたCI/CD(継続的インテグレーション/継続的デリバリー)プラットフォームです。コードのプッシュやプルリクエストをトリガーに、テスト、ビルド、デプロイを自動化できます。本記事では、実践的なワークフローの構築方法を詳しく解説します。

最初から複雑なデプロイを組むのではなく、lint、test、buildを安定して回すCIから始めるのが安全です。

この記事で学ぶこと

  1. GitHub Actionsの基本概念
  2. ワークフローファイルの構文
  3. Node.js/Pythonプロジェクトのテスト自動化
  4. キャッシュによる高速化
  5. マトリックスビルド
  6. 本番環境へのデプロイ
  7. セキュリティベストプラクティス

基本概念

GitHub Actionsの構成要素

flowchart TB
 subgraph Workflow["Workflow(ワークフロー)<br/>.github/workflows/ci.yml"]
 subgraph TestJob["Job(ジョブ): test"]
 Step1["Step 1: actions/checkout@v4"]
 Step2["Step 2: actions/setup-node@v4"]
 Step3["Step 3: npm install"]
 Step4["Step 4: npm test"]
 Step1 --> Step2 --> Step3 --> Step4
 end

 subgraph DeployJob["Job(ジョブ): deploy"]
 DeploySteps["Deploy steps..."]
 end

 TestJob -->|depends on| DeployJob
 end
用語説明
WorkflowYAMLで定義された自動化プロセス全体
Jobワークフロー内の実行単位。同じランナーで実行される
Stepジョブ内の個々のタスク。アクションまたはシェルコマンド
Action再利用可能なタスク単位(actions/checkout等)
Runnerワークフローを実行するサーバー

最初のワークフロー

ファイルの配置

project/
└── .github/
 └── workflows/
 ├── ci.yml # テスト・ビルド用
 ├── deploy.yml # デプロイ用
 └── release.yml # リリース用

基本的なCIワークフロー

# .github/workflows/ci.yml
name: CI

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

jobs:
 test:
 runs-on: ubuntu-latest

 steps:
 - name: Checkout repository
 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 tests
 run: npm test

 - name: Build
 run: npm run build

トリガー(on)の詳細

各種トリガー

on:
 # プッシュ時
 push:
 branches:
 - main
 - 'release/**' # パターンマッチ
 paths:
 - 'src/**' # 特定パスの変更時のみ
 - '!src/**/*.md' # マークダウンは除外
 tags:
 - 'v*' # タグ付け時

 # プルリクエスト
 pull_request:
 branches: [main]
 types: [opened, synchronize, reopened]

 # 手動実行
 workflow_dispatch:
 inputs:
 environment:
 description: 'Deployment environment'
 required: true
 default: 'staging'
 type: choice
 options:
 - staging
 - production

 # スケジュール実行(UTC)
 schedule:
 - cron: '0 0 * * 1' # 毎週月曜 00:00 UTC

 # 他のワークフローからの呼び出し
 workflow_call:
 inputs:
 config-path:
 required: true
 type: string

条件付き実行

jobs:
 deploy:
 # mainブランチへのプッシュ時のみ実行
 if: github.ref == 'refs/heads/main' && github.event_name == 'push'
 runs-on: ubuntu-latest
 steps:
 # ...

 notify:
 # 前のジョブが失敗した場合のみ実行
 if: failure()
 needs: [test, deploy]
 runs-on: ubuntu-latest
 steps:
 # ...

環境変数とシークレット

環境変数の設定

# ワークフローレベル
env:
 NODE_ENV: production
 CI: true

jobs:
 build:
 runs-on: ubuntu-latest
 # ジョブレベル
 env:
 DATABASE_URL: postgres://localhost/test

 steps:
 - name: Build with environment
 # ステップレベル
 env:
 API_KEY: ${{ secrets.API_KEY }}
 run: |
 echo "Node env: $NODE_ENV"
 echo "Building..."

シークレットの使用

steps:
 - name: Deploy to production
 env:
 AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
 AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
 run: |
 aws s3 sync ./dist s3://my-bucket

 # GITHUB_TOKENは自動的に利用可能
 - name: Create release
 uses: actions/create-release@v1
 env:
 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Environment Secrets

jobs:
 deploy-prod:
 runs-on: ubuntu-latest
 environment:
 name: production
 url: https://myapp.com

 steps:
 # productionの環境変数・シークレットにアクセス可能
 - name: Deploy
 env:
 DATABASE_URL: ${{ secrets.DATABASE_URL }}
 run: ./deploy.sh

キャッシュ戦略

実践メモ: actions/cacheでnode_modulesをキャッシュすると、CIの実行時間を50%以上短縮できることがあります。

npm キャッシュ

steps:
 - uses: actions/checkout@v4

 - uses: actions/setup-node@v4
 with:
 node-version: '20'
 cache: 'npm' # 自動キャッシュ

 - run: npm ci

カスタムキャッシュ

steps:
 - name: Cache node modules
 id: cache-npm
 uses: actions/cache@v4
 with:
 path: ~/.npm
 key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
 restore-keys: |
 ${{ runner.os }}-npm-

 - name: Install dependencies
 if: steps.cache-npm.outputs.cache-hit != 'true'
 run: npm ci

 # ビルド成果物のキャッシュ
 - name: Cache build output
 uses: actions/cache@v4
 with:
 path: |
 .next/cache
 dist
 key: ${{ runner.os }}-build-${{ github.sha }}
 restore-keys: |
 ${{ runner.os }}-build-

依存関係のキャッシュ(複数言語)

steps:
 # Python
 - uses: actions/setup-python@v5
 with:
 python-version: '3.12'
 cache: 'pip'

 # Go
 - uses: actions/setup-go@v5
 with:
 go-version: '1.22'
 cache: true

 # Rust
 - uses: actions/cache@v4
 with:
 path: |
 ~/.cargo/bin/
 ~/.cargo/registry/index/
 ~/.cargo/registry/cache/
 target/
 key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

ポイント: マトリックスビルドを使うと、複数のNode.jsバージョンやOSの組み合わせを一度にテストできます

マトリックスビルド

複数バージョンでのテスト

jobs:
 test:
 runs-on: ubuntu-latest
 strategy:
 matrix:
 node-version: [18, 20, 22]
 include:
 - node-version: 20
 is-primary: true
 fail-fast: false # 1つ失敗しても他は継続

 steps:
 - uses: actions/checkout@v4

 - name: Use Node.js ${{ matrix.node-version }}
 uses: actions/setup-node@v4
 with:
 node-version: ${{ matrix.node-version }}

 - run: npm ci
 - run: npm test

 # プライマリバージョンでのみカバレッジレポート
 - name: Upload coverage
 if: matrix.is-primary
 uses: codecov/codecov-action@v4

クロスプラットフォームテスト

jobs:
 test:
 strategy:
 matrix:
 os: [ubuntu-latest, macos-latest, windows-latest]
 node-version: [18, 20]
 exclude:
 # Windows + Node 18の組み合わせをスキップ
 - os: windows-latest
 node-version: 18

 runs-on: ${{ matrix.os }}

 steps:
 - uses: actions/checkout@v4
 - uses: actions/setup-node@v4
 with:
 node-version: ${{ matrix.node-version }}
 - run: npm ci
 - run: npm test

ジョブ間の依存関係

順次実行

jobs:
 lint:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - run: npm ci && npm run lint

 test:
 needs: lint # lintが成功後に実行
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - run: npm ci && npm test

 build:
 needs: [lint, test] # 複数ジョブに依存
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - run: npm ci && npm run build

アーティファクトの受け渡し

jobs:
 build:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - run: npm ci && npm run build

 - name: Upload build artifacts
 uses: actions/upload-artifact@v4
 with:
 name: dist
 path: dist/
 retention-days: 1

 deploy:
 needs: build
 runs-on: ubuntu-latest
 steps:
 - name: Download build artifacts
 uses: actions/download-artifact@v4
 with:
 name: dist
 path: dist/

 - name: Deploy
 run: ./deploy.sh dist/

実践的なワークフロー例

Node.jsプロジェクトの完全なCI/CD

# .github/workflows/ci-cd.yml
name: CI/CD

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

env:
 NODE_VERSION: '20'

jobs:
 # コード品質チェック
 quality:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4

 - uses: actions/setup-node@v4
 with:
 node-version: ${{ env.NODE_VERSION }}
 cache: 'npm'

 - run: npm ci

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

 - name: Lint
 run: npm run lint

 - name: Format check
 run: npm run format:check

 # テスト
 test:
 runs-on: ubuntu-latest
 services:
 postgres:
 image: postgres:16
 env:
 POSTGRES_USER: test
 POSTGRES_PASSWORD: YOUR_TEST_DB_PASSWORD
 POSTGRES_DB: test
 ports:
 - 5432:5432
 options: >-
 --health-cmd pg_isready
 --health-interval 10s
 --health-timeout 5s
 --health-retries 5

 steps:
 - uses: actions/checkout@v4

 - uses: actions/setup-node@v4
 with:
 node-version: ${{ env.NODE_VERSION }}
 cache: 'npm'

 - run: npm ci

 - name: Run tests
 env:
 DATABASE_URL: postgres://test:YOUR_TEST_DB_PASSWORD@localhost:5432/test
 run: npm run test:coverage

 - name: Upload coverage
 uses: codecov/codecov-action@v4
 with:
 token: ${{ secrets.CODECOV_TOKEN }}

 # ビルド
 build:
 needs: [quality, test]
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4

 - uses: actions/setup-node@v4
 with:
 node-version: ${{ env.NODE_VERSION }}
 cache: 'npm'

 - run: npm ci
 - run: npm run build

 - uses: actions/upload-artifact@v4
 with:
 name: build
 path: dist/

 # ステージングデプロイ(PRマージ時)
 deploy-staging:
 needs: build
 if: github.event_name == 'push' && github.ref == 'refs/heads/main'
 runs-on: ubuntu-latest
 environment:
 name: staging
 url: https://staging.myapp.com

 steps:
 - uses: actions/download-artifact@v4
 with:
 name: build
 path: dist/

 - name: Deploy to staging
 env:
 DEPLOY_KEY: ${{ secrets.STAGING_DEPLOY_KEY }}
 run: |
 echo "Deploying to staging..."
 # デプロイスクリプト

 # 本番デプロイ(手動承認後)
 deploy-production:
 needs: deploy-staging
 runs-on: ubuntu-latest
 environment:
 name: production
 url: https://myapp.com

 steps:
 - uses: actions/download-artifact@v4
 with:
 name: build
 path: dist/

 - name: Deploy to production
 env:
 DEPLOY_KEY: ${{ secrets.PRODUCTION_DEPLOY_KEY }}
 run: |
 echo "Deploying to production..."
 # デプロイスクリプト

Docker イメージのビルドとプッシュ

name: Docker Build

on:
 push:
 tags: ['v*']

env:
 REGISTRY: ghcr.io
 IMAGE_NAME: ${{ github.repository }}

jobs:
 build-and-push:
 runs-on: ubuntu-latest
 permissions:
 contents: read
 packages: write

 steps:
 - uses: actions/checkout@v4

 - name: Set up Docker Buildx
 uses: docker/setup-buildx-action@v3

 - name: Log in to Container Registry
 uses: docker/login-action@v3
 with:
 registry: ${{ env.REGISTRY }}
 username: ${{ github.actor }}
 password: ${{ secrets.GITHUB_TOKEN }}

 - name: Extract metadata
 id: meta
 uses: docker/metadata-action@v5
 with:
 images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
 tags: |
 type=semver,pattern={{version}}
 type=semver,pattern={{major}}.{{minor}}
 type=sha

 - name: Build and push
 uses: docker/build-push-action@v5
 with:
 context: .
 push: true
 tags: ${{ steps.meta.outputs.tags }}
 labels: ${{ steps.meta.outputs.labels }}
 cache-from: type=gha
 cache-to: type=gha,mode=max

再利用可能なワークフロー

呼び出し可能ワークフローの定義

# .github/workflows/reusable-test.yml
name: Reusable Test Workflow

on:
 workflow_call:
 inputs:
 node-version:
 required: false
 type: string
 default: '20'
 secrets:
 npm-token:
 required: false

jobs:
 test:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4

 - uses: actions/setup-node@v4
 with:
 node-version: ${{ inputs.node-version }}
 cache: 'npm'
 registry-url: 'https://registry.npmjs.org'

 - run: npm ci
 env:
 NODE_AUTH_TOKEN: ${{ secrets.npm-token }}

 - run: npm test

再利用可能ワークフローの呼び出し

# .github/workflows/ci.yml
name: CI

on: [push, pull_request]

jobs:
 call-test:
 uses: ./.github/workflows/reusable-test.yml
 with:
 node-version: '20'
 secrets:
 npm-token: ${{ secrets.NPM_TOKEN }}

注意: シークレットはワークフローファイルに直書きしないでください。GitHubのSecretsへ登録し、`${{ secrets.XXX }}`で参照します。

セキュリティベストプラクティス

依存関係のスキャン

name: Security

on:
 push:
 branches: [main]
 schedule:
 - cron: '0 0 * * 1' # 週1回

jobs:
 dependency-scan:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4

 - name: Run npm audit
 run: npm audit --audit-level=high

 - name: Run Snyk scan
 uses: snyk/actions/node@master
 env:
 SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

シークレットの安全な取り扱い

steps:
 # 悪い例: シークレットをログに出力してしまう
 - name: Bad example
 run: echo ${{ secrets.API_KEY }} # ❌ ログに表示される可能性

 # 良い例: 環境変数として渡す
 - name: Good example
 env:
 API_KEY: ${{ secrets.API_KEY }}
 run: ./deploy.sh # スクリプト内で$API_KEYを使用

最小権限の原則

# ワークフローレベルで最小限の権限を設定
permissions:
 contents: read
 packages: write

jobs:
 build:
 runs-on: ubuntu-latest
 # ジョブレベルで上書きも可能
 permissions:
 contents: read
 steps:
 # ...

デバッグとトラブルシューティング

デバッグログの有効化

# リポジトリのSecretsに設定
# ACTIONS_STEP_DEBUG: true
# ACTIONS_RUNNER_DEBUG: true

steps:
 - name: Debug info
 run: |
 echo "GitHub Context:"
 echo '${{ toJson(github) }}'
 echo "Runner Context:"
 echo '${{ toJson(runner) }}'

手動でのジョブ再実行

on:
 workflow_dispatch:
 inputs:
 debug_enabled:
 description: 'Run with debug logging'
 required: false
 default: 'false'

jobs:
 build:
 runs-on: ubuntu-latest
 steps:
 - name: Setup tmate session
 if: inputs.debug_enabled == 'true'
 uses: mxschmitt/action-tmate@v3

動作確認

ワークフローを追加したら、次を確認します。

確認項目見る場所OKの状態
トリガーActionsタブpush / pull_requestで起動する
依存関係ログnpm ci などが成功する
テストログ失敗時に原因が読める
権限workflow YAMLpermissions が最小限
secretsSettingsログに秘密情報が出ない

CIが失敗したら、まずローカルでも同じコマンドが失敗するか確認します。

練習

Node.jsプロジェクトで次を作ってください。

  1. .github/workflows/ci.yml を作る
  2. pull_request で起動する
  3. npm cinpm testnpm run build を実行する
  4. Node.js 20と22のmatrixを試す
  5. permissions: contents: read を明示する

次のステップ

CI高速化は GitHub ActionsでCIを高速化する基本 を確認してください。失敗時の切り分けは テスト失敗の切り分けビルドエラーの読み方 が役立ちます。

まとめ

GitHub Actionsを使ったCI/CDパイプラインのポイントをまとめます。

ワークフロー設計のベストプラクティス

  1. ジョブの分離: lint、test、build、deployを分離
  2. キャッシュの活用: npm/pip等のキャッシュで高速化
  3. マトリックスビルド: 複数環境での並列テスト
  4. 環境の分離: staging/productionを明確に分離

セキュリティ

  1. 最小権限の原則: 必要最低限のpermissionsを設定
  2. シークレット管理: Environment Secretsを活用
  3. 依存関係スキャン: 定期的な脆弱性チェック
  4. コードスキャン: CodeQLの導入

高速化のポイント

  1. キャッシュの適切な設定
  2. 並列実行の最大化
  3. 不要なステップの削除
  4. スリムなDockerイメージの使用

GitHub Actionsを活用することで、開発プロセスを大幅に効率化できます。

参考リンク

参考リソース

← 一覧に戻る
PR
PR
PR
PR