Developer Tools

GitHub Actions CI/CD:ゼロからビルド・テスト・デプロイのワークフローを構築する

継続的インテグレーションとデプロイのためのGitHub Actionsのセットアップ方法を解説します。トリガー、ジョブ、マトリックス、シークレット、キャッシュ、Docker、実践的なワークフロー例を網羅しています。

10分で読めます

GitHub code collaboration on screen

GitHub Actionsは、プッシュ・プルリクエスト・マージのたびに自動化されたパイプラインを起動し、テストの実行、アーティファクトのビルド、脆弱性のスキャン、本番環境へのデプロイを行います。インフラ管理が一切不要で、リポジトリの中に直接組み込まれたCI/CDプラットフォームです。

GitHub Actionsの仕組み

すべてのワークフローは.github/workflows/内のYAMLファイルです。トリガーイベントが発生すると、GitHubが新しい仮想マシンを起動してジョブを実行し、結果を報告します。これらはすべて数秒以内に完了します。

mainへのプッシュ
  ↓
ワークフローが起動
  ↓
ジョブ: ビルド & テスト (ubuntu-latest)
  ├── ステップ 1: コードのチェックアウト
  ├── ステップ 2: Node.jsのインストール
  ├── ステップ 3: npm ci
  ├── ステップ 4: npm test
  └── ステップ 5: npm run build
  ↓
✅ すべてのチェックが完了

最初のワークフロー

.github/workflows/ci.ymlを作成します:

name: CI

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

jobs:
  build:
    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 test
      - run: npm run build

これだけです。mainへのプッシュとすべてのPRで、テストスイートが自動的に実行されるようになります。

トリガー:ワークフローが実行されるタイミング

コードイベント

on:
  push:
    branches: [main, develop]
    paths: ['src/**', 'package.json']  # 変更があった場合のみ実行
  pull_request:
    types: [opened, synchronize]

スケジュール(cron)

on:
  schedule:
    - cron: '0 6 * * 1'  # 毎週月曜日 UTC 6:00

手動実行

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'デプロイ先'
        required: true
        type: choice
        options: [staging, production]

これにより、GitHub UIにパラメーターを選択できる「Run workflow」ボタンが追加されます。

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

on:
  workflow_call:
    inputs:
      node-version:
        type: string
        default: '20'

別のワークフローからuses: ./.github/workflows/reusable.ymlで呼び出せます。

ジョブとステップ

並列ジョブ

ジョブはデフォルトで並列に実行されます:

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

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

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]  # 両方が完了するまで待機
    steps:
      - uses: actions/checkout@v4
      - run: npm run build

マトリックス戦略 — 複数バージョンでテスト

複数の設定で同じジョブを実行します:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, windows-latest]
      fail-fast: false
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm test

これにより、6つの並列ジョブ(3バージョン × 2オペレーティングシステム)が作成されます。

シークレットと環境変数

シークレットの使用

機密情報はSettings → Secrets and variables → Actionsに保存します:

steps:
  - name: Deploy
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
    run: ./deploy.sh

シークレットはログでマスクされ、フォークには公開されません。

環境変数

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

jobs:
  build:
    # ジョブレベル
    env:
      CI: true
    steps:
      - name: Build
        # ステップレベル
        env:
          VITE_API_URL: https://api.example.com
        run: npm run build

高速ビルドのためのキャッシュ

キャッシュを使用しない場合、毎回すべての依存関係をゼロからダウンロードします。キャッシュを使うとビルド時間を50〜80%短縮できます:

- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: npm  # 組み込みのnpmキャッシュ

# 他のツール向けの手動キャッシュ
- uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
    restore-keys: |
      ${{ runner.os }}-pip-

アーティファクト:ジョブ間でのデータ共有

あるジョブのビルド出力をアップロードし、別のジョブでダウンロードします:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
      - run: ./deploy.sh

実践的なワークフロー例

Dockerのビルドとプッシュ

name: Docker

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

permissions:
  packages: write

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v5
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Cloudflare Pagesへのデプロイ

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci && npm run build
      - uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          command: pages deploy dist --project-name=my-site

変更ログ付きリリース

name: Release

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

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: 変更ログを生成
        run: |
          git log $(git describe --tags --abbrev=0 HEAD^)..HEAD \
            --pretty=format:"- %s" > CHANGELOG.md
      - uses: softprops/action-gh-release@v2
        with:
          body_path: CHANGELOG.md
          generate_release_notes: true

条件付き実行

ステップとジョブの実行タイミングを制御します:

steps:
  - name: 本番環境へデプロイ
    if: github.ref == 'refs/heads/main'
    run: ./deploy-prod.sh

  - name: ステージング環境へデプロイ
    if: github.event_name == 'pull_request'
    run: ./deploy-staging.sh

  - name: 失敗時に通知
    if: failure()
    run: curl -X POST ${{ secrets.SLACK_WEBHOOK }} -d '{"text":"Build failed!"}'

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

1. アクションのバージョンをSHAに固定する

# ❌ 変更可能なタグ — 侵害される可能性あり
- uses: actions/checkout@v4

# ✅ 正確なコミットSHAに固定
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11

2. 最小権限の原則を使用する

permissions:
  contents: read    # 必要なものだけ
  packages: write

3. シークレットをechoしない

# ❌ 絶対にやってはいけない
- run: echo ${{ secrets.API_KEY }}

# ✅ 環境変数を使用する
- env:
    API_KEY: ${{ secrets.API_KEY }}
  run: ./script-that-uses-api-key.sh

4. フォークからのPRの権限を制限する

on:
  pull_request_target:  # ベースブランチのコンテキストで実行
    types: [opened, synchronize]

失敗したワークフローのデバッグ

  1. ログを確認する — 失敗したステップをクリックして全出力を確認
  2. デバッグログを追加する — シークレットACTIONS_STEP_DEBUGtrueに設定
  3. actをローカルで使用するnektos/actでマシン上のワークフローを実行
  4. ランナーにSSH接続する — インタラクティブなデバッグにはmxschmitt/action-tmateを使用

ワークフローをビジュアルで構築する

YAMLを手書きしたくない場合は、**GitHub Actions Generator**を使いましょう。Node.js、Python、Docker、デプロイメントなどのテンプレートを使ってワークフローをビジュアルで構築し、本番環境対応のYAMLをダウンロードできます。

まとめ

GitHub Actionsは、リポジトリの中に直接組み込まれたCI/CDを提供します:

  1. シンプルに始める — ビルド + テストを含む1つのワークフローファイル
  2. キャッシュを追加するactions/cacheや組み込みの言語キャッシュでビルド時間を短縮
  3. マトリックスを使用する — 複数のバージョンとオペレーティングシステムでテスト
  4. シークレットを保護する — ハードコーディングせず、常に暗号化されたシークレットを使用
  5. すべてを自動化する — リリース、デプロイ、セキュリティスキャン、スケジュールタスク

最高のCI/CDパイプラインは、あなたが意識することなくすべてのコミットで実行されるものです。一度セットアップすれば、あとはGitHubに任せておけます。