トラス構造が幾何学的に組まれた建築物のファサード
設計と運用

GitHub Actions composite actionsが遅い原因は$/構文のフルクローン

目次を見る

モノレポ(複数プロジェクトを1つのリポジトリで管理する構成)でGitHub Actionsを運用していて、ジョブ開始直後の「Set up job」ステップが妙に長いと感じたことはないでしょうか。

この記事は、composite actions(複数のステップを1つの再利用可能な単位にまとめる仕組み)を大規模モノレポで使っているエンジニア向けに、遅延の原因と確認方法を整理するものです。GitHub Communityで報告された事例をもとに、アーキテクチャ観点での対処判断を整理します。

何が起きているのか

発端は、llvm/llvm-projectという巨大リポジトリでの報告です。composite actionを$/構文(自リポジトリ内のパスを指す参照方法)で呼び出すように変更したところ、セットアップだけで約3分かかるようになりました。

内訳を見ると、ほぼすべての時間が1行のログに集中していました。「Download action repository」という、リポジトリ全体をダウンロードする処理です。

CI/CDパイプライン(コードの統合とデプロイを自動化する仕組み)で、実作業が始まる前のセットアップに3分かかるのは致命的です。フィードバックループ(変更してから結果が返るまでの時間)が伸びれば、開発者の集中は途切れます。

なぜフルダウンロードが起きるのか

GitHub Actionsのランナー(ワークフローを実行する実行環境)は、composite actionへの参照方法によって取得の挙動を変えます。

通常はactions/checkoutというステップで、必要な範囲だけリポジトリを取得します。sparse-checkout(リポジトリの一部だけを取得する機能)を使えば、巨大なモノレポでも必要なディレクトリだけに絞り込めます。

ところが$/path/to/actionという構文でcomposite actionを参照すると、ランナーはそのactionを外部パッケージとして扱います。パッケージとして扱われたactionは、明示的なcheckoutが実行される前に、リポジトリ全体をアクション定義として取得しにいきます。

つまり、composite action内部でsparse-checkoutを設定していても、その設定が効く前の段階で、すでにフルクローンが完了してしまっているのです。GB単位のリポジトリであれば、この時点で数分が消費されます。効率化のための設定が、設定が効く前の全取得によって無力化される、という構造的な問題です。

関連する仕組みとの比較で理解する

この挙動は、GitHub Actionsの参照方法によって取得コストが大きく変わるという点を示しています。整理すると次のようになります。

参照方法取得範囲モノレポでの挙動
actions/checkout(sparse-checkout設定あり)指定ディレクトリのみ高速。設定通りに部分取得される
uses: ./path(同一リポジトリのローカル参照)チェックアウト済みの範囲に依存先にcheckoutが終わっていれば追加取得なし
uses: $/path/to/actionリポジトリ全体をパッケージとして取得checkoutより先にフルクローンが走る

この比較から分かる通り、$/構文は便利な新しい参照方法に見えて、実装上は別リポジトリを外部actionとして扱う経路を通っています。モノレポの巨大さがそのままコストに直結する設計です。

Dockerイメージのビルドキャッシュや、npm/yarnのモノレポでのworkspace管理と同様、参照の粒度と取得コストは常にトレードオフの関係にあります。GitHub Actionsに限らず、依存解決の仕組みを採用する際は、この対応関係を確認する習慣が有効です。

非機能要件としてのCI速度をどう評価するか

セットアップ時間の増大は、単なる待ち時間の問題ではなく、非機能要件(性能・可用性・保守性など機能以外の品質特性)の劣化として捉えるべき事象です。

影響は3つの軸に分解できます。

  • 性能: コミットからフィードバックまでの時間が伸び、開発サイクルが遅くなる
  • コスト: GitHub Actionsの実行時間はブランチ・コミット数に比例して課金されるため、無駄なフルクローンが積み重なると請求額に跳ね返る
  • 信頼性: パイプラインが遅いと、開発者がCIをスキップしたり結果を待たずにマージしたりする動機が生まれ、自動化への信頼が損なわれる

特に3点目は見落とされがちです。CI/CDへの投資は速くて信頼できることが前提であり、遅延が常態化すると、テストや静的解析をバイパスする運用に流れるリスクがあります。これは技術的負債として蓄積していく問題です。

今日確認できること

手元のワークフローがこの問題の影響を受けているか、以下の手順で確認できます。

# ワークフローファイル内でcomposite actionの参照方法を確認
grep -rn 'uses: \$' .github/workflows/
grep -rn 'uses: \./' .github/workflows/

uses: $/という記述が見つかった場合は、そのジョブの実行ログでSet up jobステップの所要時間を確認してください。GitHub ActionsのUI上で、各ステップの展開ログに「Download action repository」という行があれば、それが該当箇所です。

暫定的な回避策としては、次の選択肢が検討できます。

  • composite actionを$/pathではなく、明示的なactions/checkout(sparse-checkoutオプション付き)の後に./pathでローカル参照する形に書き換える
  • composite actionを別リポジトリに切り出し、必要な範囲だけを軽量に参照できる構成にする
  • モノレポ内でactionsディレクトリを独立したgit submoduleやサブツリーとして扱い、参照コストを下げる

どの方法を選ぶかは、モノレポの規模とチーム構成によって変わります。リポジトリサイズがGB単位に達している場合は、参照方法の見直し優先度は高いと判断してよいでしょう。

また、GitHub Community上では、$/構文がツリー全体を取得しない挙動に変更してほしいという要望が明示的に上がっています。プロダクト側の改善を待つ間は、ワークフロー側での書き換えが現実的な対処です。

まとめ

composite actionsの$/構文は、checkoutより先にリポジトリ全体を取得するという挙動を持っています。

巨大なモノレポでは、この挙動がセットアップ時間の大幅な増大につながります。sparse-checkoutを設定していても、フルクローンの後では効果がありません。

手元のワークフローでuses: $/という記述をgrepで洗い出し、Set up jobの所要時間をログで確認することが最初の一歩です。該当する場合は、明示的なcheckoutとローカル参照への書き換えを検討してください。

CI/CDの速度低下は放置すると開発者の自動化への信頼を損ないます。参照方法という小さな設定の違いが、パイプライン全体の非機能要件に直結する点を意識しておくと、今後の設計判断に役立ちます。

参考

Decoding Slow GitHub Actions: Optimizing Composite Actions in Large Monorepos for Faster Delivery

この記事について: 本記事は AI を活用して作成し、forva AI 編集部が内容を確認・監修しています。

AI 駆動開発のご相談は forva AI へ。まずはお気軽にどうぞ。