Convika

GitHub Actions が遅いときの高速化:キャッシュから順に効く 6 つの手(2026 年 11 月)

Convika Team読了目安: 14 分

  • CI
  • GitHub
目次

GitHub Actions が遅い理由は 2 つです。ジョブのたびに新しい VM が用意され、依存関係のダウンロードも Docker のビルドも最初からやり直すこと。そして、プライベートリポジトリの ubuntu-latest が 2 コアであること(GitHub のドキュメント、2026 年 11 月 11 日に確認)。直す順番は、時間を読む、キャッシュする、並列にする、コアを増やすかディスクを残す、です。

Skipbox は、Convika と同じ株式会社 Fluxenic が作っています。ジョブのあともディスクが残る GitHub Actions のランナーで、この記事の手の 1 つは自分たちの製品です。GitHub、Docker、Playwright の記載は、それぞれのドキュメントから引用しました。どれも 2026 年 11 月 11 日に読み、出典にリンクを並べています。

6 つの手と、それぞれがなくすもの

順番手なくなるもの代わりにかかるもの
1ステップごとの時間を読む当てずっぽうなし
2依存関係をキャッシュするレジストリからのダウンロード(キャッシュが当たったとき)ジョブごとの復元と保存。GitHub のキャッシュは 1 リポジトリ 10 GB まで、7 日使われないと消える
3Docker のレイヤーをキャッシュする変わっていないレイヤーの作り直しネットワーク越しの書き出しと読み込み。同じ 10 GB の中
4並列にする、テストを分割する長いジョブ 1 本を待つ時間課金される分数が増える。ジョブごとに準備をやり直し、分に切り上げられる
5GitHub の大きいランナーにするCPU を使い切るステップの遅さ高い単価。4 コアは 1 分 $0.012、8 コアは $0.022、16 コアは $0.042
6ジョブのあともディスクが残るランナーにする:Skipbox(このサイトを運営する株式会社 Fluxenic 製)ダウンロードと作り直しそのもの。Docker のレイヤー、パッケージのキャッシュ、ツールキャッシュが VM に残っている定額。4・8・16 vCPU が月 6,000 円・12,000 円・23,000 円(税込)で、実行時間は無制限

手の 1〜4 は、いまのランナーのままできます。先にやるのはこちらです。

1. どのステップが遅いかを読む

実行を開き、ジョブを選ぶと、ステップごとに時間が出ます。GitHub のドキュメントに "You can see the time it took for each step to run." とあります。

いつもの実行を 1 つ選び、時間の長い順に並べて、何を待っているのかを分けます。

遅いステップ待っているもの効く手
Node、Python、Java のセットアップツールのダウンロード6(ツールキャッシュが残るランナー)
依存関係のインストールレジストリからのダウンロード2
docker buildレイヤーの作り直し3 か 6
コンパイル、バンドルCPU5 か 6
テストCPU、または 1 列に並んだテストファイル4、次に 5
ジョブの最後のキャッシュ保存キャッシュのアップロード6

コマンドを 5 つ並べたステップは、時間が 1 つしか出ません。5 つのステップに分けるか、各コマンドの前に time をつけます。

全体の形も見ます。3 分のジョブが 10 本あっても、14 分のジョブを 1 本待っているなら、パイプラインは 14 分です。

2. 依存関係をキャッシュする

GitHub ホストランナーのジョブは、毎回パッケージをダウンロードし直します。GitHub の setup アクションなら、入力を 1 つ足すだけでキャッシュできます。

steps:
  - uses: actions/checkout@v6
  - uses: actions/setup-node@v7
    with:
      node-version: 24
      cache: "npm"
  - run: npm ci

パッケージマネージャーごとのアクションは、GitHub のキャッシュのリファレンスに載っています。

パッケージマネージャーアクション
npm、Yarn、pnpmactions/setup-node
pip、pipenv、Poetryactions/setup-python
Gradle、Mavenactions/setup-java
RubyGemsruby/setup-ruby
Goactions/setup-go
.NET NuGetactions/setup-dotnet

キャッシュが効かないときに見る、GitHub の決まり

「キャッシュを入れたのに速くならない」ときは、たいてい次のどれかです。どれも GitHub のドキュメントの記載です。

  • 7 日使われないと消える:"GitHub will remove any cache entries that have not been accessed in over 7 days."
  • 1 リポジトリ 10 GB まで:"By default, the limit is 10 GB per repository." 超えると "the cache eviction policy will create space by deleting the caches in order of last access date, from oldest to most recent."、つまり最後に使われた日が古いものから消えます。
  • 作っては消える:"The cache eviction process may cause cache thrashing, where caches are created and deleted at a high frequency." 上限に近いリポジトリでは、保存したキャッシュがすぐ消されます。
  • ブランチをまたげない:"Workflow runs cannot restore caches created for child branches or sibling branches." 新しいブランチが使えるのは、デフォルトブランチが保存したキャッシュだけです。
  • プルリクエストのキャッシュは、そのプルリクエストだけ:プルリクエストの実行が保存したキャッシュは "can only be restored by re-runs of the pull request" です。

当たっても、時間はかかります。ランナーは毎回新しい VM なので、ジョブのたびにキャッシュをダウンロードして展開し、キーが変われば保存し直します。

3. Docker のレイヤーをキャッシュする

新しい VM にはレイヤーがないので、docker build はすべての命令を実行し直します。Docker のビルド用アクションは、レイヤーを GitHub のキャッシュに置けます。

- name: Build and push
  uses: docker/build-push-action@v7
  with:
    context: .
    push: true
    tags: "<registry>/<image>:latest"
    cache-from: type=gha
    cache-to: type=gha,mode=max

Docker のドキュメントは、このバックエンドを "the recommended cache to use inside your GitHub Actions workflows, as long as your use case falls within the size and usage limits set by GitHub" と書いています。上限は 2 と同じ 10 GB と 7 日で、依存関係のキャッシュと分け合います。

当たるかどうかを決める設定は 2 つです。

  • mode=max:"In min cache mode (the default), only layers that are exported into the resulting image are cached, while in max cache mode, all layers are cached, even those of intermediate steps." 既定の min では、途中のステージのレイヤーが保存されません。マルチステージビルドには max が要ります。
  • scope:"By default, it is set to buildkit. If you build multiple images, each build will overwrite the cache of the previous, leaving only the final cache." イメージが複数あるなら、イメージごとに scope を分けます。

Dockerfile の順番は、どの設定よりも効きます。ロックファイルをコピーして依存関係を入れてから、ソースをコピーします。ソースだけが変わったとき、依存関係のレイヤーをそのまま使えます。

4. 並列にする、テストを分割する

GitHub のワークフローの文法では、ジョブは "run in parallel by default"、つまり何も書かなければ並列に動きます。lint、型チェック、単体テスト、ビルドを 4 つのジョブに分ければ、いちばん長いジョブの時間で終わります。

長いテストは、マトリックスで分割(シャーディング)します。Playwright のドキュメントに "To shard the test suite, pass --shard=x/y to the command line." とあります。

jobs:
  e2e:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        shardIndex: [1, 2, 3, 4]
        shardTotal: [4]
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: "npm"
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}

新しい push で要らなくなった実行は、止めます。

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

分割には、かかるものがあります。

  • 準備をやり直す:分割したジョブはそれぞれ、チェックアウトし、キャッシュを復元し、ブラウザーを入れ直します。12 分のテストを 4 つに分けると、1 つ 3 分に、その準備の時間が足されます。
  • 課金される分数が増える:GitHub の料金表に "GitHub rounds the minutes and partial minutes each job uses up to the nearest whole minute." とあります。ジョブごとに、分に切り上げられます。
  • 同時に動かせる数はプランで決まる:標準の GitHub ホストランナーが同時に動かせるジョブは、GitHub Free で 20、Pro で 40、Team で 60、Enterprise で 500 です。

分割は、分数を払って待ち時間を買う手です。分単位の料金のランナーでは、その分が請求に乗ります。

5. GitHub の大きいランナーにする

ここまで削って残るのは本当の仕事で、その多くは CPU です。コンパイル、バンドル、テストのワーカー。GitHub で Linux x64 のジョブに割り当てられるものは次のとおりです(2026 年 11 月 11 日に確認)。

ランナーCPUメモリーディスク1 分の単価
ubuntu-latest(プライベートリポジトリ)28 GB14 GB$0.006
ubuntu-latest(パブリックリポジトリ)416 GB14 GB無料
大きいランナー、4 コア416 GB150 GB$0.012
大きいランナー、8 コア832 GB300 GB$0.022
大きいランナー、16 コア1664 GB600 GB$0.042

条件が 2 つあります。"Larger runners are only available for organizations and enterprises using the GitHub Team or GitHub Enterprise Cloud plans."、つまり GitHub Team か Enterprise Cloud の組織だけが使えます。そして "Larger runners are not free for public repositories."、パブリックリポジトリでも料金がかかります。

増えたコアは、ジョブが使わなければ意味がありません。

- run: make -j"$(nproc)"

ネットワークを待つステップは、コアを増やしても速くなりません。大きいランナーも、ジョブのたびに新しい VM です。npm ci も docker pull も、これまでどおりダウンロードします。

6. ジョブのあともディスクが残るランナーにする

2 と 3 は、「ジョブが始まるとき、ランナーのディスクは空」という 1 つの事実への対処です。ディスクが残るランナーなら、対処そのものが要りません。なくなっていないものは、復元しなくて済みます。

GitHub のドキュメントは、セルフホストランナーについて "Don't need to have a clean instance for every job execution."(ジョブごとにまっさらなマシンは要らない)と書いています。自分で立てることもできますが、マシンも、更新も、掃除も自分の仕事になります。中身はセルフホストランナーの構築と運用にかかるコストにまとめました。

Skipbox は、その運用を任せられるランナーです。アカウントごとに専用の Linux x64 の VM があり、ジョブのあとも残ります。

  • ディスクに残るもの:Docker のイメージ・レイヤー・ビルドキャッシュ。npm・pip・Go・Gradle・Cargo などのキャッシュ。setup-* のアクションが入れるツールキャッシュ。
  • ジョブごとに消すもの:ランナーの認証情報、チェックアウトしたコードがある作業ディレクトリ、すべてのコンテナー、~/.npmrc などの認証ファイル。
  • 7 日の決まりも、ブランチの決まりもない:キャッシュは GitHub の 10 GB の中ではなく、VM のディスクの上のファイルです。ディスクは、いちばん小さいプランで 80 GB あります。
  • コアが増える:runs-on: skipbox のジョブは 4 vCPU・8 GB。大きいプランなら、skipbox-8x16 と skipbox-16x32 で 8 vCPU と 16 vCPU を選べます。
  • 定額:月 6,000 円・12,000 円・23,000 円(税込)で、実行時間は無制限。テストを分割しても、やり直しても、請求は増えません。

Docker には注意が 1 つあります。docker build と docker compose build は、VM に残ったレイヤーを使います。docker/setup-buildx-action の既定のビルダーはジョブごとに空で始まるので、driver: docker を指定して VM のキャッシュを使います。

自分のジョブで測る

Skipbox の速さを測った結果は、まだ公開していません。そのため、この記事では Skipbox の速さの数字を出しません。確実なのは、自分のジョブで測ることです。同じコミットで、2 回目以降の実行を、ステップごとの時間で両方のランナーについて並べます。

料金

GitHub は料金をドルで請求するので、比べるときは Skipbox のドルの料金(月 $39・$79・$149)で計算します。Skipbox の M(8 vCPU、月 $79)は、月 $18 を含む GitHub Team で GitHub の 8 コア(1 分 $0.022)を使う場合と比べて、月 4,410 分を超えると安くなります。式は ($79 + $18) ÷ $0.022 です。S は 4 コアに対して月 4,750 分、L は 16 コアに対して月 3,977 分を超えたところです。

macOS、Windows、Arm のジョブは Skipbox では動きません。外部のサービスの応答を待つステップは、どのランナーでも同じ速さです。

試すには、ジョブを 1 つ選び、runs-on: を skipbox に書き換えて push します。Skipbox のトライアルは、4 vCPU のジョブを 1 本ずつ、最初のジョブから 7 日間か 3,000 分のどちらか早いほうまで無料で、カードは要りません。

Skipbox の無料トライアルを始める(skipbox.dev)

月額固定のランナーの一覧は GitHub Actions のランナーを月額固定で使えるサービス一覧、各社の 1 分あたりの単価は GitHub Actions の料金と高速ランナーの費用比較にあります。自分のランナーに GitHub の料金がかかるかどうかは、セルフホストランナーは有料? 料金は無料ですをどうぞ。

よくある質問

GitHub Actions を高速化するには、何からやればいいですか?

次の順番です。ステップごとの時間を読んで遅いステップを見つける。setup アクションの cache で依存関係をキャッシュする。cache-to: type=gha,mode=max で Docker のレイヤーをキャッシュする。--shard でテストを並列のジョブに分ける。CPU を使い切るステップにコアを足す。ジョブのあともディスクが残るランナーなら、ダウンロードそのものがなくなります。Skipbox はその 1 つで、料金は月額の定額です。Skipbox は、Convika と同じ株式会社 Fluxenic が作っています。

GitHub Actions はなぜ遅いのですか?

理由は 2 つです。GitHub ホストランナーは、GitHub の説明では "a new virtual machine"、つまりジョブごとに新しい VM です。ツールと依存関係を毎回ダウンロードし、Docker のイメージも前回のレイヤーなしでビルドします。もう 1 つはコアの数で、プライベートリポジトリの ubuntu-latest は 2 コア・8 GB(2026 年 11 月 11 日に確認)。パブリックリポジトリの 4 コア・16 GB の半分です。

キャッシュを入れたのに速くならないのは、なぜですか?

キャッシュが当たっていないか、当たっても復元に時間がかかっているかです。GitHub のキャッシュは、7 日使われないと消え、1 リポジトリ 10 GB を超えると古いものから消え、兄弟のブランチとは共有されません。新しいブランチは、キャッシュなしで始まることがよくあります。当たったときも、ランナーは毎回新しい VM なので、キャッシュのダウンロードと展開はジョブのたびに走ります。

Docker のレイヤーがジョブのあとも残るランナーはありますか?

あります。Skipbox はアカウントごとに専用の VM を用意し、ジョブのあとも残します。Docker のイメージ・レイヤー・ビルドキャッシュ、パッケージのキャッシュ、ツールキャッシュは、次のジョブが始まるときにはディスクにあります。料金は 4・8・16 vCPU が月 6,000 円・12,000 円・23,000 円(税込)の定額で、実行時間は無制限。動かせるのはパブリックリポジトリとプライベートリポジトリの Linux x64 のジョブで、書き換えるのは runs-on: skipbox の一行です。自分で運用するセルフホストランナーでも、ディスクは残ります。

大きいランナーにすれば速くなりますか?

CPU を使い切るステップは速くなります。コンパイラー、バンドラー、テストのワーカーは、割り当てられたコアを使うからです。GitHub の大きい Linux のランナーは、4 コアが 1 分 $0.012、8 コアが $0.022、16 コアが $0.042 です(2026 年 11 月 11 日に確認)。ネットワークを待つステップは変わりません。大きいランナーも、ジョブのたびに新しい VM です。

テストを分割すると、料金は増えますか?

課金される分数は増えます。分割したジョブはそれぞれチェックアウトとインストールをやり直し、GitHub はジョブごとに分に切り上げます("GitHub rounds the minutes and partial minutes each job uses up to the nearest whole minute.")。分数を払って待ち時間を短くする手です。定額のランナーなら、分割しても請求は変わりません。

出典(2026 年 11 月 11 日、日本時間に読んだもの)

関連記事

記事を共有する