GitHub Actionsの「キャッシュ爆発」を防ぐ!大規模プロジェクト向けストレージ容量節約術
こんにちは。テックリードの私たちが日々頭を悩ませる問題の一つに、「GitHub Actionsのストレージ容量肥大化」があります。
モノレポ構成、数百のマイクロサービス、頻繁に行われるPR(プルリクエスト)――。これらは開発スピードを加速させる一方で、GitHub Actionsのキャッシュ(Cache)ストレージを無慈悲に消費し続けます。気づけばリポジトリのデフォルト上限である10GBを突破し、新しいキャッシュが保存されなくなってビルドが低速化する「キャッシュ爆発」の悪夢。
今回は、このストレージ肥大化の根本原因を断ち切り、ビルド速度を落とさずにストレージ消費量を極限まで削減するプロの実践テクニックを理論とコードベースで徹底解説します。
—
1. キャッシュ爆発のメカニズムと「無駄」の正体
GitHub Actionsの `actions/cache` は非常に強力ですが、デフォルトの挙動のまま運用していると、以下のような「ゴミ」が無限に生成されます。
1. ブランチごとのキャッシュ重複: プルリクエストごとに微妙に異なる依存関係のツリーがキャッシュされ、マージ後も孤立したキャッシュが残り続ける。
2. 過剰なハッシュキー: `package-lock.json` や `yarn.lock` 全体をキーにしているため、わずか1行の依存関係の追加で全く新しい100MB超のキャッシュが生成される。
3. パージ(削除)戦略の欠如: GitHubはLRU(Least Recently Used:最近最も使われていない)方式で古いキャッシュを自動削除しますが、大規模プロジェクトでは「消えてほしくないものが消え、ゴミが残り続ける」という現象が起きます。
これらを解決するための3つのアプローチを導入しましょう。
—
2. キャッシュキーの設計思想:ヒット率を最大化し、容量を最小化する
「キャッシュを残したいが、容量は増やしたくない」。このジレンマを解決する鍵は、キャッシュのスコープ(粒度)の最適化です。
黄金のキー命名規則
単に `hashFiles(‘/package-lock.json’)` を使うのはアマチュアのやり方です。大規模プロジェクトでは、プレフィックスベースのリストアキー(restore-keys)の階層構造を設計します。
- name: Cache Node Modules
uses: actions/cache@v4
with:
path: ~/.npm
# 1. 完全一致キー:ロックファイルが完全に一致した場合
# 2. 部分一致キー:OSとロックファイルのハッシュ前方一致
# 3. フォールバックキー:OSのみ一致
key: ${{ runner.os }}-node-${{ hashFiles(‘/package-lock.json’) }}
restore-keys: |
${{ runner.os }}-node-
この設計により、新しい依存関係が追加されて完全一致しなくても、直近の類似したキャッシュをベース(部分一致)にして差分だけをダウンロード・インストールさせることができます。これにより、無駄な新規キャッシュの乱造を防ぎます。
—
3. チーム開発で絶対に守るべき「不要キャッシュ排除」のベストプラクティス
次に、ワークフロー定義(YAML)において、キャッシュすべきもの・すべきでないものを厳格に選別します。
- Build Artifacts(ビルド成果物)はキャッシュしない: `dist/` や `.next/` などのビルド成果物は、キャッシュするよりも `actions/upload-artifact` を使うか、ビルド自体を最適化するべきです。キャッシュはあくまで「外部依存関係(`node_modules`, `vendor`, `.cargo` 等)」に限定します。
- テストカバレッジやログを巻き込まない: パス指定が広すぎると、ビルド時に生成される一時ファイルまでキャッシュに含まれます。
実用的なワークフロー設定例(Node.js / Monorepo環境)
以下に、ストレージ節約と高速化を両立させたプロダクションレディなYAML構成を示します。
name: CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ’20’
# setup-nodeの標準キャッシュ機能は便利ですが、
# 大規模プロジェクトでは細やかな制御ができないためあえてオフにし、
# 下流で actions/cache を直接制御することをお勧めします。
caching: false
# — ここからが極限最適化セクション —
- name: Get npm cache directory
id: npm-cache-dir
run: echo “dir=$(npm config get cache)” >> $GITHUB_OUTPUT
- name.vue: Restore Node.js modules cache
uses: actions/cache@v4
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
# ロックファイルのハッシュに加え、PRのベースブランチ情報を排除した
# 堅牢なキー設計
key: ${{ runner.os-node-${{ hashFiles(‘/package-lock.json’) }}
restore-keys: |
${{ runner.os }}-node-
- name: Install Dependencies
run: npm ci –prefer-offline –no-audit
- name: Run Build & Test
run: npm run build
—
4. 古いキャッシュの自動クリーンアップ術(APIハック)
GitHub Actionsの標準機能では、「特定の古いキャッシュを手動またはスケジュールで強制削除する」痒いところに手が届く機能がデフォルトのUIにはありません(※リポジトリ全体の削除は可能ですが、細かな制御ができません)。
ここで、GitHub CLI (`gh`) または GitHub REST API を叩く自動クリーンアップスクリプトを定期実行(cron)するワークフローを導入します。これが「キャッシュ爆発を防ぐ最終防衛ライン」です。
キャッシュを自動掃除するメンテナンス用ワークフロー
`.github/workflows/clean-caches.yml` として配置してください。
name: Purge Stale Caches
on:
schedule:
# 毎週日曜日の深夜3時に実行
- cron: ‘0 3 0’
workflow_dispatch: # 手動実行も可能に
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Delete Stale Caches
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
run: |
echo “Fetching list of caches…”
# GitHub APIを使用してキャッシュ一覧を取得し、古いものを削除する
# 7日以上使われていないキャッシュをターゲットにする例
cache_ids=$(gh api –paginate -X GET “repos/$REPO/actions/caches” \
–jq ‘.actions_caches[] | select(.last_accessed_at < (now - 6060247 | todate)) | .id')
for id in $cache_ids; do
echo "Deleting cache ID: $id"
gh api -X DELETE "repos/$REPO/actions/caches/$id"
done
echo "Cache cleanup completed."
> 💡 テックリードのワンポイントアドバイス
> このスクリプトを走らせることで、PRの乱立によって放置されたゾンビキャッシュが自動的に消去され、リポジトリのストレージ使用量を常にクリーンな状態に保つことができます。
—
5. プロの現場で役立つ設定共有化ルール
組織全体の生産性を底上げするため、以下のルールをチームのドキュメント(CONTRIBUTING.mdやWiki)に明文化し、Pull Requestのレビュー観点に組み込みましょう。
1. 新規の `actions/cache` を追加する際は、必ず `restore-keys` をセットで記述すること。(完全一致のみのキャッシュは原則リジェクト)
2. パス(path)には絶対に関係のない一時ファイルを含めないこと。(ワイルドカードの乱用禁止)
3. モノレポの場合、パッケージごとの個別キャッシュではなく、ルートでのワークスペース一括キャッシュ戦略をとること。
まとめ
GitHub Actionsのキャッシュは「諸刃の剣」です。正しく管理しなければストレージ制限に阻まれ、開発チーム全体の足かせになります。しかし、適切なキー設計、依存関係の絞り込み、そしてAPIによる定期クリーンアップを導入すれば、ストレージ容量の悩みを完全に過去のものにできます。
今日からあなたのプロジェクトでも、この「極限のストレージ節約術」を導入し、爆速でストレスフリーなCI/CDパイプラインを手に入れてください。