ウェブエンジニア問題集
第7章

キャッシュとアーティファクト — CIを高速化し、成果物を受け渡す

7
この章の目次開く

第5章で学んだ通り、ランナーは毎回まっさらです。つまり何もしなければ、CIのたびに依存パッケージを全部ダウンロードし直すことになります。この「毎回ゼロから」を補うのがキャッシュアーティファクトです。

2つは似ているようで役割がまったく違います。先に対比を頭に入れてしまいましょう。

キャッシュアーティファクト
目的高速化(作り直せるものを取っておく)受け渡し・保存(成果物そのもの)
npmのダウンロードキャッシュ、Next.jsのビルドキャッシュビルド成果物、テストレポート、スクリーンショット
消えたら遅くなるだけ(また作れる)困る(その実行の成果が失われる)
主な行き先次回以降の実行同じ実行内の別ジョブ、または人間がダウンロード
学習者学習者

なるほど、キャッシュは「速くするための使い回し」で、アーティファクトは「持ち出したい荷物」なんだ。

その理解で完璧です。それぞれ見ていきます。

キャッシュ①: setup-nodeの組み込みキャッシュ

実は前章のワークフローには、すでにキャッシュが入っていました。

      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm        # ← これ
yaml

cache: npm の1行で、npmのダウンロードキャッシュ~/.npm)が実行をまたいで保存・復元されます。パッケージをレジストリから再ダウンロードする時間が消えるので、npm ci が体感で数十秒速くなることも珍しくありません。

ポイントは、キャッシュの鍵(キー)がpackage-lock.jsonのハッシュから自動生成されることです。

  • lockファイルが同じ → キャッシュがヒットして高速
  • lockファイルが変わった(依存を追加した等) → キャッシュを作り直す

依存関係が変わればキャッシュも自動で切り替わるので、「古いキャッシュのせいで変な状態になる」ことは起きにくい設計になっています。

キャッシュ②: actions/cache で任意のディレクトリをキャッシュする

npm以外のものをキャッシュしたいときは、汎用の actions/cache を使います。代表例がNext.jsのビルドキャッシュ(.next/cache)です。

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

初見だと呪文に見えるので、部品を分解します。

項目意味
pathキャッシュするディレクトリ
keyキャッシュの識別子。完全一致したら復元される
restore-keyskeyが一致しなかったときの前方一致のフォールバック
hashFiles(...)指定ファイル群のハッシュ値を計算する関数

キーの設計思想はこうです。

nextjs-Linux-<lockのハッシュ>-<ソースのハッシュ>
   │      │        │              │
   │      │        │              └ ソースが変わるたびに新キャッシュを保存
   │      │        └ 依存が変わったら古いキャッシュは使わない
   │      └ OSが違うキャッシュは混ぜない
   └ 何のキャッシュかの名前空間

ソースコードは毎回変わるので key の完全一致はほぼ起きません。そこで restore-keys の前方一致により、「同じ依存関係で作った一番新しいキャッシュ」を復元して差分だけビルドする——という動きになります。

速く走る人

キャッシュの落とし穴

便利な一方で、キャッシュには知っておくべき性質があります。

  • 合計10GBの上限(リポジトリごと)。超えると古いものから削除される
  • 7日間アクセスがないと自動削除される
  • 「キャッシュのせいで挙動がおかしい」疑惑が出たら、Actionsタブの Caches 画面から手動削除できる
  • キャッシュはあくまで高速化。キャッシュがなくても成功するワークフローであること(キャッシュ前提の設計にしない)

詳細は依存関係をキャッシュしてワークフローを高速化する(公式ドキュメント)を参照してください。

アーティファクト: 成果物を保存・受け渡しする

次はアーティファクトです。ユースケースは2つあります。

① 実行後にファイルをダウンロードしたい

テストのカバレッジレポートやE2Eテストの失敗時スクリーンショットなど、「CIが作ったファイルを後から人間が見たい」ケースです。actions/upload-artifact でアップロードします。

      - name: テストを実行する
        run: npm run test -- --coverage
 
      - name: カバレッジレポートを保存する
        uses: actions/upload-artifact@v4
        if: always()                # テストが落ちてもレポートは保存する
        with:
          name: coverage-report
          path: coverage/
          retention-days: 7         # 保存期間(デフォルト90日)
yaml

アップロードされたファイルは、Actionsタブの実行ページ下部からzipでダウンロードできます。if: always() は第4章で学んだステータス関数の実践例で、「テストが失敗したときこそレポートを見たい」ので付けています。

② ジョブ間でファイルを受け渡したい

第5章で「ジョブは別マシンなのでファイルを共有できない」と学びました。ビルド成果物を後続ジョブで使いたいときは、アーティファクト経由で受け渡します。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: npm }
      - run: npm ci
      - run: npm run build
 
      - name: ビルド成果物をアップロードする
        uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: .next/
 
  deploy:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: ビルド成果物をダウンロードする
        uses: actions/download-artifact@v4
        with:
          name: build-output
          path: .next/
 
      - run: echo "この .next/ をデプロイする(第9章で実践)"
yaml

upload-artifact で名前を付けて預け、後続ジョブが download-artifact で同じ名前を指定して受け取る——荷物の一時預かりのイメージです。「ビルドは1回だけ、デプロイはその成果物を使う」という構成は、テストしたものと同じ成果物を本番に出すという意味で重要なプラクティスです。

メンターメンター

デプロイ直前にもう一度ビルドし直す構成だと、「テストで検証したビルド」と「本番に出たビルド」が別物になります。アーティファクトで同一の成果物を運ぶ——地味ですが、信頼できるデリバリーの基本ですよ。

キャッシュとアーティファクトの使い分け・再確認

この章の冒頭の表に、判断基準を1つ足して締めくくります。

「消えても作り直せるならキャッシュ、消えたら困るならアーティファクト」

  • node_modulesの元データ → 作り直せる → キャッシュ
  • .next/cache → 作り直せる(遅くなるだけ) → キャッシュ
  • 本番に出すビルド成果物 → その実行の成果そのもの → アーティファクト
  • テストレポート → その実行の記録 → アーティファクト

まとめ

  • ランナーは毎回まっさら。キャッシュで「作り直せるもの」を持ち越して高速化する
  • npmは setup-nodecache: npm だけでOK。lockファイルのハッシュで自動管理される
  • 任意のディレクトリは actions/cache。キーは「名前空間-OS-依存ハッシュ-ソースハッシュ」+ restore-keys の前方一致が定石
  • アーティファクトは成果物の保存と受け渡し。upload-artifact / download-artifact のペアで使う
  • ビルドは1回、デプロイはその成果物を——が信頼できるパイプラインの基本形

次章では、ジョブ定義の重複問題に取り組みます。複合アクションとReusable Workflowで、ワークフローをDRYに保つ方法です。