GitHub Actions parallel steps + 4vCPU 実測検証 — 45%短縮+コスト減の条件と、効果ゼロだった条件
2026年6月GAのparallel stepsを4vCPUランナーと併用し2リポジトリで実測。Docker build並列化で45%短縮かつコスト14%減を達成した一方、ESLint律速のリポジトリでは効果ゼロ。その分岐点を判断フレームワークとともに解説します。4vCPU ランナーと parallel steps の組み合わせで、CI が 45% 速くなりコストも下がりました。ただし、それは律速工程がマルチコアを活用できるリポジトリに限った話です。もう片方では parallel steps よりジョブ分割のほうが速く、別のアプローチが正解でした。
2026年6月に GA になった GitHub Actions の parallel steps を TECH PLAY の開発チームが2つのリポジトリで検証した結果です。
| リポジトリ | 律速工程 | Before | 最適構成 | After | 短縮率 |
|---|---|---|---|---|---|
| Laravel API(PHP, arm64) | Docker build ×3 | 11.5分 | 4vCPU + parallel steps | 6.3分($0.050) | 45%(コスト14%減) |
| Next.js 管理画面(TypeScript, x64) | ESLint | 5分30秒 | 2vCPU ジョブ分割 | 2分35秒 | 53% |
分かれ目は1つ、律速工程がマルチコアを活用できるかどうかです。
なぜ結果が割れたのか
Next.js 管理画面の律速は ESLint(TypeScript lint)です。ESLint はデフォルトでシングルスレッド動作であるため、アムダールの法則の通り、CPU を 2→4 コアに増やしても実行時間は変わりません。
一方、Laravel API の律速は Docker build 3本(合計5分)と parallel tests(php artisan test --parallel、3分46秒)です。Docker の BuildKit は独立レイヤーを並列にビルドし、parallel tests は複数の PHP プロセスを起動します。どちらもマルチコアを活用する設計であるため、4vCPU の恩恵を直接受けます。
Next.js 管理画面の律速:
ESLint ──────────────────── [1コアしか使わない]
(残り3コアは遊んでいる)
Laravel API の律速:
Docker build app ████████ [4コア並列]
Docker build ws ████
Docker build deploy ████████
parallel tests ████████████ [4コアでワーカー増加]
ここまでは理論から予測できる範囲です。以下のケーススタディでは、予測しにくかった部分 — 2vCPU での I/O 競合の実態、arm64 の料金体系によるコスト逆転 — を掘り下げます。
ケース1: Next.js 管理画面 — parallel steps よりジョブ分割が速かった
parallel steps vs ジョブ分割の実測
Next.js + TypeScript の管理画面リポジトリで、逐次実行・ジョブ分割・parallel steps の3パターンを同一コミットで比較しました。TTG(Time To Green — push から CI が緑になるまでの所要時間)で評価します。
| 方式 | TTG | vs Before | ランナー数 |
|---|---|---|---|
| Before(逐次) | 5分30秒 | — | 1台 |
| ジョブ分割(3並列) | 2分35秒 | 53%短縮 | 3台 |
| parallel steps(1ジョブ) | 3分58秒 | 28%短縮 | 1台 |
ジョブ分割のほうが 1分23秒速い。原因はリソース競合です。
GitHub-hosted standard runner は 2vCPU です。parallel steps で3タスクを同時実行すると、CPU だけでなく、Docker build によるディスク I/O やネットワーク帯域も圧迫されます。ジョブ分割では各タスクが独立したランナーを専有するため、リソース競合が発生しません。
| タスク | ジョブ分割(独立 2vCPU) | parallel steps(2vCPU 共有) |
|---|---|---|
| cfn-lint | 24秒 | 2分08秒 |
| lint (ESLint) | 1分24秒 | 2分04秒 |
| docker build | 2分36秒 | 3分01秒 |
特に cfn-lint の劣化が大きく、24秒から2分08秒に膨らんでいます。cfn-lint は Python の軽量ツールで CPU 負荷は小さいため、この劣化は CPU タイムシェアリングだけでは説明が難しく、Docker build のレイヤー書き込みによる I/O 競合が主因と考えられます。
4vCPU にしても逐次の改善は限定的
4vCPU 検証は別日に実施しました。同日の 2vCPU ベースラインは 6.5分です(前述の比較実験時は 5分30秒。ランナーの実行時間のばらつきと計測時点の差異による)。
| 構成 | TTG | コスト/run |
|---|---|---|
| 2vCPU 逐次 | 6.5分 | $0.039 |
| 4vCPU 逐次 | 6.3分 | $0.076 |
| 4vCPU 3ジョブ並列 | 3.2分 | ~$0.072 |
4vCPU にしても逐次の TTG はほぼ変わりません(6.5分→6.3分、短縮率3%)。律速の ESLint がシングルスレッドであるため、コアを増やしても使われません。コストだけが2倍になりました。
このケースでは、ランナーへの課金ではなくワークフローの設計変更(ジョブ分割)が正解でした。
ケース2: Laravel API — 4vCPU + parallel steps で速くて安くなった
律速の構造
Laravel + PHP の API リポジトリの CI は単一ジョブで以下を逐次実行していました。
Docker build app (2分09秒) → Docker build workspace (49秒) → Install packages (38秒)
→ Docker build deploy (2分02秒) → cfn-lint (8秒) → PHP testing (3分46秒)
※ 上記はステップ単体の所要時間。checkout・setup 等のオーバーヘッド(約2分)を加えた全体の TTG が 11.5分です。
Docker build 3本は互いに独立しているのに逐次で積まれており、合計5分を費やしていました。さらに PHP テストは --parallel フラグで並列実行される設計です。つまり、ワークロード自体がマルチコアを前提としているにもかかわらず、2vCPU では能力を発揮しきれていませんでした。
parallel steps で Docker build を並列化
3本の Docker build を parallel ブロックにまとめ、4vCPU ランナーで実行しました。
jobs:
testing:
runs-on: ubuntu-arm64-4core
steps:
- uses: actions/checkout@v5
- uses: docker/setup-buildx-action@v3
# キャッシュ設定(省略)
- parallel:
- name: Build api app
uses: docker/build-push-action@v6
with:
file: ./docker/local/Dockerfile
# ...
- name: Build api workspace
uses: docker/build-push-action@v6
with:
file: ./docker/workspace83/Dockerfile
# ...
- name: Build api deploy
uses: docker/build-push-action@v6
with:
file: ./docker/deploy/Dockerfile
# ...
- name: PHP testing
run: docker compose exec workspace bash -c "composer run test"
実測結果
| 構成 | 平均TTG | vs Baseline | コスト/run |
|---|---|---|---|
| 2vCPU(現状) | 11.5分 | — | $0.058 |
| 4vCPU(構成そのまま) | 8.8分 | -24% | $0.070 |
| 4vCPU + parallel steps | 6.3分 | -45% | $0.050 |
4vCPU + parallel steps は baseline より 速くて安い。
45% の短縮は2段階で構成されています。4vCPU 化だけで24%改善(11.5分→8.8分)し、これは PHP テストの --parallel ワーカーが増加したことによる効果が大きいと考えられます。parallel steps による Docker build の並列化でさらに28%改善(8.8分→6.3分)しました。parallel steps 単体の寄与は28%であり、4vCPU ランナーとの組み合わせが前提です。
なぜ安くなるのか
GitHub Actions の料金では、arm64 ランナーの 2-core → 4-core は 1.6倍の単価増です($0.005/分 → $0.008/分)。x64 の2倍($0.006/分 → $0.012/分)とは異なります。
コスト = 実行時間 × 単価/分
arm64 の場合:
2vCPU: 11.5分 × $0.005 = $0.058
4vCPU: 6.3分 × $0.008 = $0.050 ← 安い!
損益分岐点:
arm64(単価1.6倍): 37.5%以上の時間短縮でコスト逆転
x64 (単価2.0倍): 50%以上の時間短縮でコスト逆転
今回の短縮率: 45% > 37.5% → コスト逆転成立
コスト逆転は arm64 の料金体系(4-core が 2-core の1.6倍)に依存しています。x64 では単価が2倍になるため、同じ45%の短縮でも損益分岐点ぎりぎりです。
ジョブ分割(3台のランナーで並列)との比較でも、parallel steps は有利です。ジョブ分割では checkout・依存インストールが3回走りますが、parallel steps は 1ランナー内で完結するため setup が1回で済みます。
parallel steps vs ジョブ分割: 構造的な違い
両者は「タスクを並列実行する」という目的は同じですが、実行モデルが根本的に異なります。
| parallel steps | ジョブ分割 | |
|---|---|---|
| ランナー数 | 1台 | N台 |
| setup(checkout, install) | 1回 | N回 |
| 課金 | 1ランナー × 実行時間 | N ランナー × 各実行時間 |
| CPU | 共有(vCPU 数で上限) | 各ジョブ独立 |
| データ共有 | ファイルシステム共有 | artifact 経由 |
parallel steps が有利な条件:
- 4vCPU 以上のランナーを使える(リソース競合が緩和される)
- setup が重い(npm ci、composer install 等が1回で済む)
- 並列タスクが同じファイルシステム上のデータを参照する
ジョブ分割が有利な条件:
- 2vCPU の standard runner しか使えない
- タスク間で環境が大きく異なる(Node.js と Python など)
- TTG 最優先でコストは二の次
律速の移動: 最適化は1回では終わらない
parallel steps やジョブ分割で並列化を達成した後も、最適化は終わりません。Next.js 管理画面では、施策を重ねるたびにボトルネックが移動しました。
| 段階 | 施策 | TTG | 律速 |
|---|---|---|---|
| 0 | Before(逐次) | 5分30秒 | 逐次実行全体 |
| 1 | ジョブ分割 | 2分35秒 | docker-build(2分36秒) |
| 2 | Docker キャッシュ最適化(type=gha) | 1分26秒 | lint(1分20秒) |
| 3 | paths-filter(Dockerfile 未変更時スキップ) | 1分23秒 | lint(1分20秒) |
段階2で docker-build を1分06秒に短縮した瞬間、律速が lint に移動しました。段階3で docker-build を丸ごとスキップしても、TTG は3秒しか縮みません。lint の壁(約80秒)が次の天井です。最適化は「律速を特定 → 律速を攻める → 新しい律速を特定」のサイクルであり、1回の施策では完結しません。
lint が律速になった次の一手は、ESLint の --cache オプション、あるいは oxlint / Biome のような高速 linter への移行です。
では、担当プロジェクトで最初に手をつけるべき「律速」をどう見つけるか。以下のフレームワークで判断できます。
判断フレームワーク: 月曜日に何をするか
担当プロジェクトの CI を最適化する手順です。
ステップ1: TTG と律速を計測する
# 直近の成功 run から TTG を取得
gh api repos/{owner}/{repo}/actions/runs \
--jq '.workflow_runs[] | select(.conclusion=="success") |
[.name, .created_at, .updated_at] | @tsv'
10件以上サンプリングし、p50 を確認してください。
ステップ2: 律速工程の CPU 特性を判定する
| 律速工程の例 | CPU 特性 | 4vCPU 効果 | 推奨施策 |
|---|---|---|---|
| ESLint, Prettier, cfn-lint | シングルスレッド | × | ジョブ分割 or linter 高速化 |
| Docker build(マルチステージ) | 並列レイヤー | ○ | parallel steps + 4vCPU |
| php artisan test --parallel | マルチプロセス | ◎ | 4vCPU でワーカー増加 |
| npm ci, composer install | I/O + 一部並列 | △ | キャッシュが先 |
ステップ3: 並列化の方式を選ぶ
律速工程はマルチコアを活用できるか?
│
├─ YES → 4vCPU + parallel steps を検討
│ └─ 損益分岐: arm64 なら37.5%短縮、x64 なら50%短縮で元が取れる
│
└─ NO(シングルスレッド) → ジョブ分割を推奨
└─ または律速工程自体の高速化(linter 変更等)
ステップ4: 計測して比較する
予測ではなく実測で判断することをお勧めします。今回のデータが示す通り、同じ施策でもリポジトリによって効果が正反対になります。ベンチマーク用のブランチとワークフローを作成し、3回以上走らせて比較してください。
測定条件と限界
本記事のデータには以下の制約があります。
- サンプル数: 各構成2〜7回。GitHub-hosted ランナーは実行時間にばらつきがあるため、少ないサンプル数では外れ値の影響を受けやすい点に注意してください。本記事中の倍率・パーセンテージは中央値ベースの概算であり、統計的な有意差検定は実施していません
- キャッシュ状態: 全測定は warm cache 条件(2回目以降)で実施。初回(cold cache)の TTG はこれより長くなります
- アーキテクチャの違い: Laravel API は arm64、Next.js 管理画面は x64 です。リポジトリ間の絶対値比較はできません。各リポジトリ内での Before/After 比較のみが有効です
- リソース競合の原因: parallel steps 使用時の性能劣化について「リソース競合」と記述していますが、CPU・ディスク I/O・メモリ帯域の切り分けは未実施です
- 料金: 2026年7月時点の GitHub Actions runner pricing に基づきます。Larger runners は included minutes の対象外(private リポジトリでは常に従量課金)です
- スコープ: 本記事ではランナー構成とワークフロー設計にスコープを絞っています。ESLint 自体の高速化(
--cache、oxlint、Biome)は有効な選択肢ですが、別の検証が必要です
まとめ
parallel steps は銀の弾丸ではありません。2vCPU の standard runner ではリソース競合により、既存のジョブ分割より遅い結果でした。しかし 4vCPU ランナーと組み合わせることで、Laravel API では 45% の時間短縮と 14% のコスト削減を同時に達成しました(うち parallel steps 単体の寄与は28%、残りは 4vCPU 化の効果)。
分かれ目は律速工程がマルチコアを活用できるかどうかです。Docker build や parallel tests のように並列性を持つワークロードには parallel steps + larger runner が効きます。ESLint のようにシングルスレッドの工程が律速なら、ランナーにいくら課金しても改善しません。
まず担当プロジェクトの律速工程を特定し、その CPU 特性を確認してください。マルチコアが効くワークロードなら、parallel steps + 4vCPU は「速くて安い」選択肢になります。
参考文献













