キャッシュとアーティファクト
ストーリー
「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) | ~/.npm | package-lock.json |
| Node.js (pnpm) | ~/.pnpm-store | pnpm-lock.yaml |
| Python (pip) | ~/.cache/pip | requirements.txt |
| Go | ~/go/pkg/mod | go.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: 14Job 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分