GitHub Actions完全ガイド — CI/CDパイプラインをゼロから構築する


GitHub Actionsは、GitHubに統合されたCI/CDプラットフォームです。コードのプッシュやプルリクエストをトリガーに、テスト・ビルド・デプロイを自動化できます。本記事では、基本概念から実践的なパイプライン構築まで、動作するYAMLコードとともに徹底解説します。

1. GitHub Actionsの基本概念

GitHub Actionsを理解するうえで押さえるべき4つの要素があります。

ワークフロー(Workflow)

ワークフローは.github/workflows/ディレクトリに置かれるYAMLファイルです。1つのリポジトリに複数のワークフローを定義できます。

.github/
└── workflows/
    ├── ci.yml          # テスト・Lint
    ├── deploy.yml      # 本番デプロイ
    └── release.yml     # リリース管理

ジョブ(Job)

ワークフロー内で並列または直列に実行される処理単位です。各ジョブは独立したランナー上で動きます。

ステップ(Step)

ジョブ内で順番に実行されるコマンドやアクションの単位です。前のステップの結果を次のステップで参照できます。

ランナー(Runner)

ジョブが実行されるサーバー環境です。GitHubが提供するホスト型ランナー(ubuntu-latest、windows-latest、macos-latest)と、自前のセルフホストランナーがあります。

ワークフロー
└── ジョブA(ubuntu-latest で実行)
    ├── ステップ1: コードをチェックアウト
    ├── ステップ2: Node.jsをセットアップ
    ├── ステップ3: 依存関係をインストール
    └── ステップ4: テストを実行
└── ジョブB(ジョブA成功後に実行)
    └── ステップ1: デプロイ

2. YAMLの基本構文と主要コンテキスト

ワークフローの最小構成

name: CI

on:
  push:
    branches: [main]

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

主要コンテキスト

GitHub Actionsでは、実行環境の情報にコンテキスト経由でアクセスします。

steps:
  - name: コンテキストの確認
    run: |
      echo "リポジトリ: ${{ github.repository }}"
      echo "ブランチ:   ${{ github.ref_name }}"
      echo "コミットSHA: ${{ github.sha }}"
      echo "イベント:   ${{ github.event_name }}"
      echo "実行者:     ${{ github.actor }}"
      echo "ワークスペース: ${{ github.workspace }}"
コンテキスト用途
githubリポジトリ・コミット・イベント情報
env環境変数
secrets暗号化されたシークレット
matrixマトリックスビルドの変数
steps前のステップの出力値
needs依存ジョブの出力値

3. トリガー設定

onキーでワークフローの起動条件を細かく制御できます。

on:
  # mainとdevelopへのプッシュ時
  push:
    branches:
      - main
      - develop
    paths:
      - 'src/**'
      - 'package.json'

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

  # スケジュール実行(毎日午前9時 JST = UTC 0時)
  schedule:
    - cron: '0 0 * * *'

  # 手動トリガー(入力パラメータ付き)
  workflow_dispatch:
    inputs:
      environment:
        description: 'デプロイ環境'
        required: true
        default: 'staging'
        type: choice
        options:
          - staging
          - production
      dry_run:
        description: 'ドライランモード'
        required: false
        type: boolean
        default: false

手動トリガーの入力値は${{ github.event.inputs.environment }}で参照できます。

4. Node.js/TypeScriptプロジェクトのCI

実際のNext.jsプロジェクトに使えるCIワークフローの完全版です。

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

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

jobs:
  lint-and-test:
    name: Lint & Test
    runs-on: ubuntu-latest

    steps:
      - name: コードをチェックアウト
        uses: actions/checkout@v4

      - name: Node.jsをセットアップ
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: 依存関係をインストール
        run: npm ci

      - name: TypeScript型チェック
        run: npm run type-check

      - name: ESLint実行
        run: npm run lint

      - name: Prettierチェック
        run: npm run format:check

      - name: ユニットテスト実行
        run: npm run test -- --coverage

      - name: カバレッジレポートをアップロード
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: ./coverage/lcov.info
          fail_ci_if_error: false

      - name: Next.jsビルド確認
        run: npm run build
        env:
          NEXT_TELEMETRY_DISABLED: 1

package.jsonのスクリプト定義例:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "lint": "eslint . --ext .ts,.tsx",
    "type-check": "tsc --noEmit",
    "format:check": "prettier --check .",
    "test": "vitest run",
    "test:watch": "vitest"
  }
}

5. マトリックスビルド

複数のNode.jsバージョンやOSで同時にテストを実行できます。

jobs:
  test-matrix:
    name: Test (Node ${{ matrix.node-version }} / ${{ matrix.os }})
    runs-on: ${{ matrix.os }}

    strategy:
      fail-fast: false   # 一つが失敗しても他を継続
      matrix:
        node-version: ['18', '20', '22']
        os: [ubuntu-latest, windows-latest, macos-latest]
        # 特定の組み合わせを除外
        exclude:
          - os: windows-latest
            node-version: '18'
        # 特定の組み合わせに追加パラメータ
        include:
          - os: ubuntu-latest
            node-version: '20'
            experimental: false

    steps:
      - uses: actions/checkout@v4

      - name: Node.js ${{ matrix.node-version }} をセットアップ
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - run: npm ci
      - run: npm test

マトリックスビルドにより、3バージョン × 3OS = 9パターンのテストが並列実行されます。

6. アーティファクトとキャッシュ

npmキャッシュ

actions/setup-nodecacheオプションを使うと、node_modulesのキャッシュが自動管理されます。

- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'        # package-lock.json のハッシュでキャッシュ

高度なキャッシュ設定

- name: Next.jsビルドキャッシュ
  uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      ${{ github.workspace }}/.next/cache
    key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
    restore-keys: |
      ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
      ${{ runner.os }}-nextjs-

アーティファクトの保存と取得

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

      - name: ビルド成果物を保存
        uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: .next/
          retention-days: 7

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: ビルド成果物を取得
        uses: actions/download-artifact@v4
        with:
          name: build-output
          path: .next/

      - name: デプロイ実行
        run: echo "デプロイ処理..."

7. シークレット管理と環境変数

シークレットの登録と参照

GitHubリポジトリの Settings > Secrets and variables > Actions からシークレットを登録します。

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: 環境変数とシークレットの使い方
        run: |
          # シークレットはログに表示されない(マスクされる)
          echo "APIキーの長さ: ${#API_KEY}"
        env:
          API_KEY: ${{ secrets.API_KEY }}
          DATABASE_URL: ${{ secrets.DATABASE_URL }}

環境(Environment)ごとのシークレット管理

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment: staging    # Settings > Environments で定義
    steps:
      - run: echo "ステージングにデプロイ"
        env:
          API_URL: ${{ secrets.STAGING_API_URL }}

  deploy-production:
    runs-on: ubuntu-latest
    environment: production  # 承認者設定・デプロイブランチ制限が可能
    steps:
      - run: echo "本番にデプロイ"
        env:
          API_URL: ${{ secrets.PRODUCTION_API_URL }}

ステップ間での値の受け渡し

steps:
  - name: バージョンを取得
    id: get_version
    run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT

  - name: タグを作成
    run: git tag v${{ steps.get_version.outputs.version }}

8. Vercelへの自動デプロイ

Vercel CLIを使ったデプロイ

# .github/workflows/deploy.yml
name: Deploy to Vercel

on:
  push:
    branches: [main]

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

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Vercel CLIをインストール
        run: npm install -g vercel@latest

      - name: Vercelにプルリクエストプレビューをデプロイ
        if: github.event_name == 'pull_request'
        run: |
          vercel deploy --token=${{ secrets.VERCEL_TOKEN }} \
            --yes \
            --env NEXT_PUBLIC_API_URL=${{ secrets.STAGING_API_URL }}
        env:
          VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
          VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

      - name: Vercel本番デプロイ
        if: github.ref == 'refs/heads/main'
        run: |
          vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }} --yes
        env:
          VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
          VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

Vercelのトークンと各IDはvercel linkコマンド実行後に.vercel/project.jsonで確認できます。

9. DockerイメージのビルドとGitHub Container Registry push

# .github/workflows/docker.yml
name: Docker Build & Push

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

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

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write    # ghcr.io へのプッシュに必要

    steps:
      - uses: actions/checkout@v4

      - name: Docker Buildxをセットアップ
        uses: docker/setup-buildx-action@v3

      - name: GitHub Container Registryにログイン
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}  # 自動提供されるトークン

      - name: Dockerメタデータを抽出
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,prefix=sha-

      - name: Dockerイメージをビルド & プッシュ
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha        # GitHubActionsキャッシュを使用
          cache-to: type=gha,mode=max
          platforms: linux/amd64,linux/arm64   # マルチアーキテクチャ対応

マルチステージビルドのDockerfile例:

# --- ビルドステージ ---
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# --- 実行ステージ ---
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

EXPOSE 3000
CMD ["node", "server.js"]

10. Slack通知・PRへのコメント自動投稿

Slack通知

steps:
  - name: テスト実行
    id: tests
    run: npm test
    continue-on-error: true

  - name: 成功時にSlack通知
    if: steps.tests.outcome == 'success'
    uses: slackapi/slack-github-action@v1
    with:
      payload: |
        {
          "text": "✅ テスト成功: ${{ github.repository }}@${{ github.ref_name }}",
          "blocks": [
            {
              "type": "section",
              "text": {
                "type": "mrkdwn",
                "text": "*✅ CI成功* — <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|詳細を見る>"
              }
            }
          ]
        }
    env:
      SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
      SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

  - name: 失敗時にSlack通知
    if: steps.tests.outcome == 'failure'
    uses: slackapi/slack-github-action@v1
    with:
      payload: |
        {
          "text": "❌ テスト失敗: ${{ github.repository }}@${{ github.ref_name }}"
        }
    env:
      SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
      SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

PRへのコメント自動投稿

- name: PRにカバレッジコメントを投稿
  if: github.event_name == 'pull_request'
  uses: actions/github-script@v7
  with:
    script: |
      const coverage = require('./coverage/coverage-summary.json');
      const pct = coverage.total.lines.pct;
      const emoji = pct >= 80 ? '✅' : '⚠️';

      const body = [
        `## ${emoji} テストカバレッジレポート`,
        '',
        `| 種類 | カバレッジ |`,
        `|------|-----------|`,
        `| Lines | ${coverage.total.lines.pct}% |`,
        `| Branches | ${coverage.total.branches.pct}% |`,
        `| Functions | ${coverage.total.functions.pct}% |`,
      ].join('\n');

      await github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body,
      });

11. セルフホストランナーの設定

クラウドのランナーでは対応できない環境(プライベートネットワーク内のデプロイ、GPU処理、高スペック要件)にはセルフホストランナーが有効です。

# セルフホストランナーの設定手順(Ubuntu)
mkdir actions-runner && cd actions-runner

# ランナーパッケージをダウンロード(GitHubのUIから最新URLを取得)
curl -o actions-runner-linux-x64-2.321.0.tar.gz -L \
  https://github.com/actions/runner/releases/download/v2.321.0/actions-runner-linux-x64-2.321.0.tar.gz

tar xzf ./actions-runner-linux-x64-2.321.0.tar.gz

# 設定(トークンはGitHub UIから取得)
./config.sh --url https://github.com/your-org/your-repo \
            --token YOUR_REGISTRATION_TOKEN \
            --labels self-hosted,linux,production

# サービスとして登録
sudo ./svc.sh install
sudo ./svc.sh start

ワークフローでの使用:

jobs:
  deploy-internal:
    runs-on: [self-hosted, linux, production]   # ラベルでランナーを指定
    steps:
      - uses: actions/checkout@v4
      - name: 内部サービスへのデプロイ
        run: ./scripts/deploy-internal.sh

12. ワークフローの再利用

再利用可能ワークフロー(Reusable Workflows)

共通の処理を切り出して複数のワークフローから呼び出せます。

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

on:
  workflow_call:
    inputs:
      node-version:
        required: false
        type: string
        default: '20'
      run-e2e:
        required: false
        type: boolean
        default: false
    secrets:
      CODECOV_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'
      - run: npm ci
      - run: npm test -- --coverage
      - name: E2Eテスト(オプション)
        if: inputs.run-e2e
        run: npm run test:e2e

呼び出し側:

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

on:
  push:
    branches: [main]

jobs:
  run-tests:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: '20'
      run-e2e: true
    secrets:
      CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

コンポジットアクション(Composite Actions)

複数ステップをひとつのアクションとして切り出します。

# .github/actions/setup-project/action.yml
name: 'Setup Project'
description: 'Node.jsのセットアップと依存関係インストール'

inputs:
  node-version:
    description: 'Node.jsバージョン'
    required: false
    default: '20'

runs:
  using: 'composite'
  steps:
    - uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}
        cache: 'npm'

    - name: 依存関係をインストール
      shell: bash
      run: npm ci

    - name: キャッシュ情報を出力
      shell: bash
      run: echo "セットアップ完了: Node.js ${{ inputs.node-version }}"

使用例:

steps:
  - uses: actions/checkout@v4
  - uses: ./.github/actions/setup-project
    with:
      node-version: '22'
  - run: npm test

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

OIDCによるクラウド認証(AWS例)

シークレットを使わずに、OpenID ConnectでAWSに一時的なクレデンシャルで認証できます。

jobs:
  deploy-aws:
    runs-on: ubuntu-latest
    permissions:
      id-token: write   # OIDCトークンの発行に必要
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: AWSクレデンシャルを設定(OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
          aws-region: ap-northeast-1

      - name: S3にデプロイ
        run: aws s3 sync ./dist s3://my-bucket/

最小権限の原則

jobs:
  read-only-job:
    runs-on: ubuntu-latest
    permissions:
      contents: read      # リポジトリの読み取りのみ
      pull-requests: write  # PRへのコメント書き込み
      # packages: write   # 不要な権限はコメントアウト

Dependabotによる自動更新設定

# .github/dependabot.yml
version: 2
updates:
  # npm依存関係の自動更新
  - package-ecosystem: 'npm'
    directory: '/'
    schedule:
      interval: 'weekly'
      day: 'monday'
      time: '09:00'
      timezone: 'Asia/Tokyo'
    groups:
      # マイナー・パッチをまとめてPR
      minor-and-patch:
        update-types:
          - minor
          - patch
    ignore:
      - dependency-name: 'some-problematic-package'

  # GitHub Actionsの自動更新
  - package-ecosystem: 'github-actions'
    directory: '/'
    schedule:
      interval: 'weekly'

アクションのバージョン固定

# 危険: タグは書き換えられる可能性がある
- uses: actions/checkout@v4

# 安全: コミットSHAで固定
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

サードパーティアクションのセキュリティレビュー

# 信頼できるアクションのみ使用する
# - actions/* (GitHub公式)
# - docker/* (Docker公式)
# - aws-actions/* (AWS公式)
# それ以外は必ずソースを確認し、コミットSHAで固定

フルスタックなNext.js CIパイプラインの例

上記を統合した実践的なワークフロー:

# .github/workflows/full-pipeline.yml
name: Full CI/CD Pipeline

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

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true   # 古い実行を自動キャンセル

jobs:
  # ジョブ1: コード品質チェック
  quality:
    name: Code Quality
    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: npm run type-check
      - run: npm run format:check

  # ジョブ2: テスト(マトリックス)
  test:
    name: Test (Node ${{ matrix.node }})
    needs: quality
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: ['18', '20', '22']
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: 'npm'
      - run: npm ci
      - run: npm test -- --coverage

  # ジョブ3: ビルド
  build:
    name: Build
    needs: test
    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 build
        env:
          NEXT_TELEMETRY_DISABLED: 1
      - uses: actions/upload-artifact@v4
        with:
          name: next-build
          path: .next/

  # ジョブ4: 本番デプロイ(mainブランチのみ)
  deploy:
    name: Deploy to Production
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
        with:
          name: next-build
          path: .next/
      - run: npm install -g vercel@latest
      - run: vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }} --yes
        env:
          VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
          VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

まとめ

GitHub Actionsを活用することで、コードをプッシュするだけでテスト・ビルド・デプロイが自動的に行われるCI/CDパイプラインを構築できます。

重要なポイントをまとめると:

  1. ワークフロー = ジョブ + ステップの階層構造を理解することが基本
  2. needsでジョブの依存関係を定義して直列実行を制御する
  3. マトリックスビルドで複数バージョン・OSのテストを並列化
  4. キャッシュを活用してCI実行時間を短縮する
  5. シークレットは環境(Environment)単位で管理してステージング/本番を分離
  6. OIDC認証でクラウドへの静的シークレット不要な認証を実現
  7. 再利用可能ワークフローでDRYな設定管理
  8. concurrency設定で無駄な並列実行を防ぐ

CI/CDパイプラインの構築はソフトウェア開発の品質と速度を同時に向上させる投資です。最初は小さなワークフローから始め、段階的に自動化の範囲を広げていくことをお勧めします。


なお、GitHub Actionsのワークフロー実行履歴の確認、YAML構文の検証、環境変数の管理といった作業には、DevToolBoxのYAML Validator・Env Manager・Base64 Encoderなどのツールが役立ちます。YAMLのインデントエラーはCI失敗の主要原因のひとつなので、事前に検証する習慣をつけておくと開発効率が上がります。


スキルアップ・キャリアアップのおすすめリソース

GitHub ActionsとCI/CDのスキルは、DevOpsエンジニア・SREとして市場価値を高める核心スキルだ。

転職・キャリアアップ

  • レバテックキャリア — ITエンジニア専門の転職エージェント。DevOps・SREエンジニアの高単価求人が充実。CI/CDの実績はポートフォリオとして有力。無料相談可能。
  • Findy — GitHubのワークフロー実績が直接評価対象。スカウト型でDevOps・インフラエンジニア求人が多い。リモート・フルフレックスの求人が充実。

オンライン学習

  • Udemy — GitHub Actions・Terraform・ArgoCD等を組み合わせたCI/CDパイプライン構築コースが充実。実際のプロジェクトを通じて本番対応のスキルが身につく。セール時は大幅割引。

関連記事