LESSON 30分

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

ストーリー

「CIの実行時間が8分かかっている。うち4分が npm ci だ」

木村先輩がパイプラインの実行ログを指さした。

「毎回ゼロからnode_modulesをインストールしているからだ。 package-lock.jsonが変わっていないのに、毎回同じものをダウンロードしている。 これをキャッシュすれば、4分が30秒に短縮できる」

「4分が30秒......それは大きいですね」

「キャッシュとアーティファクトは似ているようで目的が違う。 キャッシュは同じワークフローの高速化、 アーティファクトはジョブ間やワークフロー間のデータ受け渡しだ」


キャッシュとアーティファクトの違い

キャッシュ vs アーティファクト

キャッシュ(Cache)
┌────────────────────────────────┐
│  目的: ワークフロー実行の高速化    │
│  対象: node_modules, .cache 等  │
│  寿命: 7日間(最終アクセスから)   │
│  共有: 同一リポジトリのワークフロー間│
│  例:  npm ci の結果を再利用       │
└────────────────────────────────┘

アーティファクト(Artifact)
┌────────────────────────────────┐
│  目的: ビルド成果物の保存・共有    │
│  対象: dist/, coverage/, logs  │
│  寿命: 1〜90日(設定可能)       │
│  共有: ジョブ間、ダウンロード可能  │
│  例:  ビルド出力を deploy に渡す  │
└────────────────────────────────┘
項目キャッシュアーティファクト
主な用途依存関係の高速復元ビルド成果物の保存
データの方向入力(復元して使う)出力(生成して渡す)
保持期間7日(自動削除)1〜90日(設定可能)
サイズ制限10GB/リポジトリ500MB〜2GB/アーティファクト
ダウンロード不可GitHub UIから可能

キャッシュの使い方

actions/cache の基本

yaml
- name: Cache node_modules
  uses: actions/cache@v4
  with:
    # キャッシュするディレクトリ
    path: node_modules
    # キャッシュキー(package-lock.json のハッシュで生成)
    key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
    # キーが一致しない場合のフォールバック
    restore-keys: |
      ${{ runner.os }}-node-

キャッシュの動作フロー

キャッシュの仕組み

1回目の実行(キャッシュなし)
  キャッシュ復元 → ミス! → npm ci (4分) → キャッシュ保存

2回目の実行(package-lock.json 変更なし)
  キャッシュ復元 → ヒット! → npm ci スキップ (30秒)

3回目の実行(package-lock.json 変更あり)
  キャッシュ復元 → 部分ヒット(restore-keys) → npm ci (1分) → キャッシュ保存

setup-node の組み込みキャッシュ(推奨)

actions/setup-node にはキャッシュ機能が内蔵されています。

yaml
- name: Setup Node.js
  uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'          # npm のグローバルキャッシュを自動管理

- name: Install dependencies
  run: npm ci             # キャッシュから復元されるため高速

言語別のキャッシュ設定

言語キャッシュ対象キーの基準
Node.js (npm)~/.npmpackage-lock.json
Node.js (pnpm)~/.pnpm-storepnpm-lock.yaml
Python (pip)~/.cache/piprequirements.txt
Go~/go/pkg/modgo.sum
Rust~/.cargo, target/Cargo.lock

Pythonのキャッシュ例

yaml
- name: Setup Python
  uses: actions/setup-python@v5
  with:
    python-version: '3.12'
    cache: 'pip'

- run: pip install -r requirements.txt

アーティファクトの使い方

アーティファクトのアップロード

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

      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-output         # アーティファクト名
          path: |                    # 保存するパス(複数指定可)
            dist/
            !dist/**/*.map
          retention-days: 7          # 保持日数
          if-no-files-found: error   # ファイルがない場合エラーにする

アーティファクトのダウンロード

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

      - name: Deploy
        run: |
          echo "Deploying files:"
          ls -la dist/

ジョブ間のデータ受け渡しパターン

アーティファクトによるジョブ間連携

  [build ジョブ]
       │
       │ upload-artifact
       │ (dist/ をアップロード)
       ▼
  ┌──────────┐
  │ Artifact  │
  │ Storage   │
  └──────────┘
       │
       │ download-artifact
       │ (dist/ をダウンロード)
       ▼
  [deploy ジョブ]

テストレポートの保存

yaml
- name: Run tests
  run: npm test -- --coverage
  continue-on-error: true

- name: Upload test results
  if: always()                    # テスト失敗時もレポートを保存
  uses: actions/upload-artifact@v4
  with:
    name: test-results
    path: |
      coverage/
      test-results/
    retention-days: 14

Job Summaryの活用

ワークフロー実行結果のサマリーをMarkdownで出力する機能です。

yaml
- name: Test summary
  if: always()
  run: |
    echo "## Test Results" >> $GITHUB_STEP_SUMMARY
    echo "" >> $GITHUB_STEP_SUMMARY

    if [ -f coverage/coverage-summary.json ]; then
      echo "### Coverage" >> $GITHUB_STEP_SUMMARY
      echo "| Category | Percentage |" >> $GITHUB_STEP_SUMMARY
      echo "|----------|-----------|" >> $GITHUB_STEP_SUMMARY
      cat coverage/coverage-summary.json | jq -r '
        .total | to_entries[] |
        "| \(.key) | \(.value.pct)% |"
      ' >> $GITHUB_STEP_SUMMARY
    fi

キャッシュの最適化テクニック

1. キャッシュキーの設計

yaml
# 良い: 具体的なキー + フォールバック
- uses: actions/cache@v4
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-${{ matrix.node-version }}-
      ${{ runner.os }}-node-

2. キャッシュヒット時のスキップ

yaml
- name: Cache node_modules
  id: cache
  uses: actions/cache@v4
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}

- name: Install dependencies
  if: steps.cache.outputs.cache-hit != 'true'    # キャッシュミス時のみ実行
  run: npm ci

実行時間の比較

状況npm ci 時間合計CI時間
キャッシュなし3〜5分8〜10分
キャッシュあり(ヒット)0分(スキップ)4〜5分
キャッシュあり(部分ヒット)30秒〜1分5〜6分

まとめ

ポイント内容
キャッシュ依存関係の高速復元でCI時間を短縮
アーティファクトビルド成果物のジョブ間受け渡しと保存
setup-node cache組み込みキャッシュが最も簡単
Job Summary実行結果をMarkdownでサマリー表示

チェックリスト

  • キャッシュとアーティファクトの違いを説明できる
  • actions/cache でキャッシュを設定できる
  • upload-artifact/download-artifact でジョブ間データ受け渡しができる
  • キャッシュキーの設計方法を理解した

次のステップへ

次のセクションでは、これまで学んだ知識を全て使って、本格的なテスト自動化パイプラインを構築する演習に挑戦します。


推定読了時間: 30分