こんにちは!日々の開発やCI/CDパイプラインの構築、本当にお疲れ様です。
今回は、GitHubを使っている多くのチームが、ある日突然直面する「恐怖の罠」――GitHub Actionsのキャッシュ爆発(ストレージ容量圧迫)について、その防ぎ方とスマートな管理術を徹底解説します。
「最近、GitHubからストレージ使用量の警告メールが来るようになった…」
「気づいたら無料枠を使い切って課金されていた…」
そんな悩みを抱えていませんか?これをマスターすれば、無駄なストレージコストを削減できるだけでなく、パイプラインのビルド速度も劇的に向上しますよ。さあ、一緒にスマートなリポジトリ管理の世界へ進みましょう!
—
そもそもGitHub Actionsの「キャッシュ」ってなに?
初心者の方に向けて、まずは「キャッシュ」の役割を優しく整理しておきましょう。
GitHub Actionsでは、Node.jsの `node_modules` や、Pythonの `pip` パッケージ、Javaの `Maven` リポジトリといった「外部の依存関係」を、ワークフローが実行されるたびに毎回インターネットからダウンロードしています。これだと、テストやビルドが始まるまでに毎回数分待たされてしまいますよね。
そこで登場するのが `actions/cache` です。
一度ダウンロードした依存関係をGitHubのサーバー上に保存(キャッシュ)しておき、次回のビルドではそれを使い回すことで、パイプラインを爆速にする――これがキャッシュの役割です。
なぜ「キャッシュ爆発」が起きるのか?
便利なキャッシュですが、デフォルトのまま使っていると、次のような問題でストレージがパンク(爆発)します。
1. キャッシュが無限に増え続ける: 古いキャッシュの自動削除機能が(リポジトリのライフサイクルポリシー以外では)弱いため、ブランチを切るたび、依存関係が少し変わるたびに新しいキャッシュが生成されます。
2. キーの設計ミス: キャッシュの「目印(キー)」が適切でないと、ヒットせずに毎回新しいファイルが作られ、ゴミだけが溜まっていきます。
3. 不要なものまでキャッシュしている: ビルド成果物(Artifact)とキャッシュをごちゃ混ぜにし、無駄に重いファイルを保存してしまいます。
GitHub全体のデフォルトのキャッシュ制限は、1リポジトリあたり10GBです。これを超えると、古いキャッシュから自動で削除されますが、無駄なキャッシュで溢れかえると「本当に必要なキャッシュが追い出されてビルドが遅くなる」という最悪の事態を招きます。
—
基礎セットアップ:まずは正しいキャッシュの書き方を知ろう
それでは、無駄なキャッシュを生み出さないための基本形を見てみましょう。
Node.js(npm)を例にした、最も精度が高く無駄のないワークフローの書き方です。
name: CI with Smart Caching
on:
push:
branches: [ “main” ]
pull_request:
branches: [ “main” ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: ソースコードのチェックアウト
uses: actions/checkout@v4
- name: Node.jsのセットアップ
uses: actions/setup-node@v4
with:
node-version: ’20’
# ※ setup-node自体にキャッシュ機能がありますが、
# ここではキャッシュの仕組みを理解するためにあえてactions/cacheを使います
- name: キャッシュの復元と保存の定義
uses: actions/cache@v4
with:
# キャッシュしたいディレクトリを指定
path: ~/.npm
# 【重要】package-hashベースでキーを生成し、内容が変わった時だけ更新する
key: ${{ runner.os }}-node-${{ hashFiles(‘/package-lock.json’) }}
# 万が一キーが完全一致しなかった場合のフォールバック(前方一致)
restore-keys: |
${{ runner.os }}-node-
- name: 依存関係のインストール
run: npm ci
- name: テストの実行
run: npm test
この設定のポイントは、`hashFiles(‘/package-lock.json’)` を使っているところです。
`package-lock.json` に変更がない限り、同じキャッシュキーが使われるため、無駄な新しいキャッシュが作られません。
—
現場で役立つ!ストレージ節約のための3つの極意
ここからが本題です。大規模プロジェクトで「キャッシュ爆発」を完全に防ぐための、実践的な3つのテクニックを伝授します。
1. キャッシュの有効期限(TTL)を意識する
GitHub Actionsのキャッシュは、過去7日間使われていない場合、自動的に削除されます。
一見これで十分に見えますが、活発なプロジェクトでは7日間の間に何百ものブランチが作られ、そのたびにユニークなキャッシュが生成されて10GBの制限を圧迫します。
対策として、Pull Requestがマージされたら、そのPR用のキャッシュは不要になるという意識を持ちましょう。キーの命名規則に `${{ github.ref }}` のようなブランチ名を直接含めすぎると、ブランチの数だけキャッシュが乱立します。
できる限り `hashFiles` を軸にした「内容依存のキー」に絞り、キャッシュの総数を減らすのがコツです。
2. 不要な依存関係やビルド成果物をキャッシュしない
やってしまいがちなのが、`node_modules` や `dist`、`.next` などのビルド成果物まるごとキャッシュすることです。これらは非常に容量が大きく、ストレージをすぐ圧迫します。
- キャッシュすべきもの: パッケージマネージャーのダウンロードキャッシュ(例: `~/.npm`, `~/.m2/repository`, `~/.gradle/caches`)
- キャッシュすべきではないもの: 各種ビルド成果物(これらは `actions/upload-artifact` を使い、ジョブ間やワークフロー間で一時的に共有し、数日後に自動消去させましょう)
3. 定期的なキャッシュの掃除(GitHub CLIを活用する)
「すでに溜まってしまったキャッシュをどうにかしたい!」というときは、GitHub CLI (`gh`) を使って一括削除するのがエンジニア流です。
手動、あるいは定期実行のワークフローで、古いキャッシュをキレイに掃除しちゃいましょう。
現在のリポジトリのキャッシュ一覧を確認する
gh cache list
特定のキャッシュをID指定で削除する
gh cache delete
(応用)古いキャッシュを一括削除するワンライナー
gh cache list –limit 100 | grep “refs/pull” | awk ‘{print $1}’ | xargs -I {} gh cache delete {}
※このように、PR(Pull Request)用のブランチで作られた一時的なキャッシュを定期的に掃除するスクリプトを定期実行(`schedule` トリガー)しておくと、ストレージ容量を常にクリーンに保てますよ。
—
まとめ:今日から始めるキャッシュ最適化
いかがでしたか?今回はGitHub Actionsの「キャッシュ爆発」を防ぐためのストレージ節約術についてお伝えしました。
- キャッシュキーを最適化し、無駄な重複生成を防ぐ
- パッケージマネージャーのキャッシュ(`~/.npm` など)に絞り、ビルド成果物はArtifactを使う
- GitHub CLI (`gh`) を活用して、不要になったキャッシュを定期的に掃除する
これらを意識するだけで、GitHubのストレージ容量は見違えるほどスッキリし、おまけにパイプラインの動作も安定します。
「動けばいいや」で作りがちなCI/CDパイプラインですが、こうした細かなリソース管理に気を配れるようになると、チーム全体から「おっ、頼れるな!」と思われるエンジニアになれますよ。
毎日の開発がもっと快適になるよう、ぜひ今日のプロジェクトに取り入れてみてくださいね!