【GitHub】ActionsでCI/CDを自動化する方法

【GitHub】ActionsでCI/CDを自動化する方法 Git

GitHub ActionsはGitHubリポジトリ内のYAMLでワークフローを定義し、プッシュやプルリクエストなどのイベントをトリガーにビルドやテスト、デプロイを自動化できるCI/CD基盤です。外部サービスなしで開始でき、Marketplaceのアクションを組み合わせることで高度なパイプラインも短い記述で構築できます。ここでは基本概念から最小構成、キャッシュやマトリクス、シークレット管理、デプロイまでを一気通貫で解説します。

基本概念と全体像

ワークフローは.github/workflows配下のYAMLで定義します。ワークフローは一つ以上のジョブで構成され、ジョブは一つ以上のステップを順番に実行します。ステップはアクションまたはシェルコマンドのいずれかで、ジョブはデフォルトで独立並列に走ります。実行環境はGitHubホストのランナーか、独自のセルフホストランナーを選べます。典型的な流れはコード取得、依存解決、ビルド、テスト、成果物の保存、条件に応じたデプロイという手順です。

最小のCIワークフローを作成する

最初の自動化はプッシュとPRをトリガーにテストを走らせる構成が適します。以下はNode.jsを例にした最小YAMLです。

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - name: Install
        run: npm ci
      - name: Test
        run: npm test -- --ci --reporter jest-junit

複数環境で同時検証するマトリクス戦略

異なるランタイムやOSで同一テストを並列実行すると互換性のリスクを早期に検出できます。以下はNode.jsの複数バージョンとOSを組み合わせる例です。

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

ビルド時間を短縮する依存キャッシュ

setup-nodeのcacheオプションやactions/cacheで依存やビルド成果物を保存し、再利用することで実行時間を短縮できます。キーはロックファイルやOSで変えるとヒット率と一貫性を両立できます。

steps:
  - uses: actions/checkout@v4
  - uses: actions/setup-node@v4
    with:
      node-version: 20
      cache: npm
  - run: npm ci
  - run: npm run build

成果物を保存しPRで共有する

テストレポートやビルド済みバンドルをアーティファクトに保存してダウンロードできるようにします。

- name: Upload artifact
  uses: actions/upload-artifact@v4
  with:
    name: web-dist
    path: dist/
    retention-days: 7

シークレットと環境で安全にデプロイ

APIキーやトークンはリポジトリや組織のSecretsに保存し、envやwithで参照します。環境(environments)を用いると承認ステップや環境別シークレットを付与できます。

jobs:
  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
        run: ./scripts/deploy.sh

静的サイトをGitHub Pagesへデプロイする

Pages専用のアクションを使えばビルド後に自動公開できます。

name: Deploy to Pages
on:
  push:
    branches: [ main ]
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci && npm run build
      - uses: actions/upload-pages-artifact@v3
        with:
          path: ./dist
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/deploy-pages@v4

コンテナをビルドしてレジストリへプッシュする

Docker Buildxを利用するとキャッシュとマルチプラットフォームに対応したビルドが可能です。以下はGHCRにプッシュする例です。

name: Docker
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v6
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

モノレポで無関係ジョブを避けるパス条件と同時実行制御

pathsフィルターで変更があるときだけ実行し、concurrencyで重複実行をキャンセルします。レビュー中の古いコミットを先に実行してしまう無駄を抑えられます。

on:
  pull_request:
    paths:
      - web/**

concurrency:
  group: web-${{ github.ref }}
  cancel-in-progress: true

再利用可能ワークフローで共通化する

複数リポジトリで同じ品質ゲートを使う場合は呼び出し可能なワークフローにまとめます。

# .github/workflows/call-test.yml
name: Call Reusable
on:
  workflow_call:
    inputs:
      node:
        required: true
        type: string
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: ${{ inputs.node }} }
      - run: npm ci && npm test
# 呼び出し側
jobs:
  reuse:
    uses: org/repo/.github/workflows/call-test.yml@main
    with:
      node: '20'

ブランチ保護と必須ステータスチェックで品質を担保する

保護ルールでmainに直接プッシュを禁止し、特定ワークフローの成功をマージ条件に設定します。レビューとCIの両輪で品質を維持できます。

セルフホストランナーの導入ポイント

特殊な依存やGPUが必要な場合はセルフホストランナーを用意します。ラベルを付けてジョブに選択させ、セキュアなネットワーク上で運用します。キュー詰まりや停止時に備えて監視と自動再起動を仕込むと安定します。

jobs:
  gpu-train:
    runs-on: [self-hosted, linux, gpu]
    steps:
      - uses: actions/checkout@v4
      - run: nvidia-smi

トラブル対処の勘所

ワークフローが起動しないときはon条件とpathsの一致を見直します。依存の取得に失敗する場合はトークンや権限セクション、シークレット名を確認します。ジョブが遅いときはキャッシュキーやマトリクス数、不要なステップを点検します。ログはステップごとに展開して失敗箇所を特定し、再実行はRun rerun jobsを活用します。

まとめ

GitHub Actionsの核はYAMLで宣言的にパイプラインを記述する点にあります。チェックアウトとセットアップ、キャッシュ、テスト、成果物、環境別デプロイの順で小さく始め、マトリクスや再利用ワークフロー、ブランチ保護で拡張していくと堅牢なCI/CDが完成します。まずは最小構成をmainとPRで動かし、実行時間の最適化とセキュアなシークレット管理を並行して整備することが成功の近道です。