CircleCIのworkspaceをcacheに切り替えてストレージ利用量を8GB節約する
この記事の操作
CircleCIを運用していると、ストレージ使用量の増加に悩まされることがあります。今回、あるNode.jsプロジェクトでストレージが圧迫されている状況を調査したところ、workspaceの不適切な使用が原因だとわかりました。設定を見直してcacheベースの実装に移行した結果、約8GBのストレージ削減に成功したため、その過程を共有します。
問題の発見
CircleCIのダッシュボードを確認したところ、ストレージ使用量が想定以上に増えていました。

詳しく調べると、workspaceの使用量が特に多くなっています。

設定ファイルを確認すると、.circleci/continue_config.yml で node_modules 全体を persist_to_workspace で保存する実装になっていました。

このコードでは、root に ~/project を指定し、paths に node_modules と package-lock.json を含めています。一見すると問題なさそうに見える実装ですが、workspaceの仕組みを理解すると、ストレージ効率の観点で改善の余地があるとわかります。
workspaceとcacheの違い
CircleCIには、ジョブ間でファイルを共有する仕組みとして workspace と cache の2つがあります。名前が似ているため混同しやすいのですが、保持期間と用途が大きく異なります。
workspace は同一workflow内のジョブ間でファイルを共有するための一時的なストレージです。重要なのは、デフォルトで15日間保持される点でしょう。ワークフロー終了後も即座に削除されず、15日間はストレージを占有し続けます。たとえば、ビルドジョブで作成したアーティファクトをテストジョブに渡す場合に使います。
一方、cache は異なるワークフロー実行間でファイルを再利用するための永続的なストレージです。package-lock.json のようなキーが同じであれば、同じキャッシュを再利用するため、ストレージ効率が高くなります。node_modules のような依存関係ファイルの保存に適しています。
この違いを理解すると、今回の問題が見えてきます。node_modules を workspace に保存すると、コミットのたびに新しい workspace が作られ、それぞれが15日間保持されます。一方、cache に保存すれば、package-lock.json が変わらない限り同じキャッシュを再利用するため、ストレージ使用量を大幅に削減できるわけです。
ストレージ使用量の試算
実際にどれくらいのストレージを使用しているのか試算してみました。対象プロジェクトの状況は次のとおりです。
過去15日間のコミット数は23回でした。node_modules の推定サイズは約400MBです。このプロジェクトは AWS SDK for JavaScript v3(S3とSSM)、Google Analytics Data API、LangChain と Anthropic SDK、googleapis、AWS CDK関連パッケージなどを使用しているため、それなりのサイズになります。
workspace を使用している場合、各コミットで新しい workspace が作られ、15日間保持されます。計算すると、400MB × 23個 = 約9.2GBのストレージを使用していることになります。
cache に移行した場合、package-lock.json が変更されたときだけ新しいキャッシュが作られます。過去15日間で package-lock.json が変更されたのは2〜3回程度だったため、400MB × 2〜3個 = 約1.2GB以下に抑えられます。
期待される削減量は約8GB以上です。これは無視できない差でしょう。
解決策の実装
CircleCIには Node Orb という公式パッケージがあり、このバージョン7.2.1には自動的にキャッシュ機能が組み込まれています。この機能を活用することにしました。
変更内容は3つあります。まず、install-node22 ジョブを削除しました。このジョブは node_modules を workspace に保存する処理を行っていたため、不要になります。
次に、各ジョブ(lint-node22、build-node22、test-node22)で node/install-packages を直接実行するようにしました。この設定により、各ジョブが独立して動作し、自動的にキャッシュを利用します。

最後に、ジョブ間の依存関係を削除しました。requires を削除することで、すべてのジョブが完全に並列実行されます。これにより、実行時間の短縮も期待できます。
変更後のワークフローでは、lint-node22、build-node22、test-node22 の3つのジョブが並列実行されます。各ジョブは独立して、リポジトリのチェックアウト、Node.jsのインストール、node/install-packages によるパッケージインストール(ここでキャッシュが自動利用されます)、各種タスクの実行という流れで動作します。
期待される効果
この変更によって4つの効果が期待できます。
ストレージ使用量の大幅削減は最大の目的です。約8GB以上の削減が見込まれるため、CircleCIの無料枠やストレージコストの面で大きなメリットがあります。
ジョブの並列実行により、実行時間が短縮されます。以前は install-node22 の完了を待ってから各テストジョブが実行されていましたが、今回の変更ですべてのジョブが同時に開始されるため、全体の実行時間が短くなります。
自動キャッシュ管理によって、運用負荷が軽減されます。Node Orb が package-lock.json の変更を検知して自動的にキャッシュを更新するため、手動でキャッシュキーを管理する必要がありません。
設定のシンプル化も実現できました。workspace の persist と attach を管理する必要がなくなり、設定ファイルの記述量が減りました。
まとめ
CircleCIの workspace と cache は似た名前ですが、保持期間と用途が大きく異なります。workspace はワークフロー内のジョブ間共有に適していますが、デフォルトで15日間保持されるため、node_modules のような大きなファイルを保存するとストレージを圧迫します。cache は異なるワークフロー間でファイルを再利用するため、依存関係ファイルの保存に適しています。
今回の事例では、workspace から cache への移行により約8GBのストレージ削減に成功しました。同様の問題を抱えているプロジェクトでは、workspace の使用状況を確認し、cache への移行を検討するとよいでしょう。CircleCIの公式Orbを活用することで、設定の変更も比較的簡単に実現できます。
開発ノートをもっと読む
技術的な学びや実践的な開発ノートをもっと探索してみませんか?
⭐ この記事への反応
はてなアカウントでスターを付けることができます
