GitHub ActionsにおけるGitHub-hosted runnerとSelf-hosted runnerのパフォーマンス比較(CPU編)

システムプラットフォームチームの id:rskmm0chang です。

この記事は、はてなのSREが毎月交代で書いているSRE連載の2025年11月号です。10月の記事はid:cohalzさんの GitHub Organizationを安心して利用するための最近の機能紹介でした。

前回も11月に書いていて、11月になるとブログが書きたくなるようです。 developer.hatenastaff.com

GitHub Actions Runnerのパフォーマンス比較を始めた経緯

はてなでは、Actions Runner Controllerを利用して、Self-hosted runnersを提供しています。 もともとはスポットインスタンスの活用によるコストダウンを目指していましたが、(当然ながら)ジョブが途中で終了してしまうため、あまり活用されず、また、その時点ではRunnerのパフォーマンスに問題があり、あまり活用されない状況でした。

ジョブの中断に関しては、オンデマンドインスタンスにして解決しましたが、当然コストは上がります。その分パフォーマンスでカバーする必要があり、ボトルネックなどをdstatで調査したところ、Disk I/Oがボトルネックであることがわかりました。特にdocker-composeであれもこれも立ち上げてテスト、というジョブでは、Diskへのアクセスが多く、ボトルネックとなっていました。

当初はスポットインスタンスでの活用を目指していたこともあり、インスタンスの種類に縛られないようにEBSでのパフォーマンス改善を目指していましたが、IOPSなどを調整してもあまり改善が見られませんでした。

スポットインスタンスをやめて、オンデマンドに切り替えたことで、ローカルSSDを搭載しているEC2も候補になり、ローカルSSDを搭載しているEC2で、上記のようなジョブを実行したところ明らかにパフォーマンスが改善し、効果が確認できました。

この改善をもって、Self-hosted runnerのパフォーマンスの向上が確認できましたが、これが「GitHub-hosted Runnerに対してどれだけ優位なのか」、あるいは「Self-hosted runnerのどの要素(CPUやDisk I/Oなど)がボトルネックになりやすいのか」を客観的に把握する必要性を感じ、ベンチマークを用いてパフォーマンスを定期的に確認し、KPIとして改善していくこととしました。

パフォーマンスの比較対象としては

  • CPU
  • Disk I/O

としています。

それぞれの結果を1つのブログでどちらも記載すると長くなってしまうため、本記事ではCPUのみとし、Disk I/Oは別途ブログに記載予定のため、この記事のタイトルにも"(CPU)"をつけています。

なお、本記事におけるGitHub-hosted runnerの測定は、private repository上で実行しています。

ubuntu-slimの登場

もともとパフォーマンス試験はubuntu-latestをベースとした、2 Core Runnerで比較していましたが、先日1 Core Runnerであるubuntu-slimが発表されました。 すでに他の方がブログを記載しているため、ubuntu-slimの紹介はここでは記載しません。

zenn.dev

はてなのSelf-hosted runnersでは、ubuntu-slimが出る前から、1 Core Runnerも用意していたため、1 Core Runnerでもパフォーマンス比較を始めました。

2 Coreのパフォーマンス比較

まずは、2 Core環境での比較を行います。Self-hosted runnerは、コンテナベースで構築しており、AMD64とARM64のそれぞれで測定しました。 なお、GitHub-hosted runnerにおけるarmは、自分たちでlabelを作成する必要があり、下記に記載するubuntu-24.04-arm-2xはこちらで作成したlabelです。

比較対象

Runner種別 Architecture label 備考
GitHub-hosted AMD64 ubuntu-latest 環境はVM
GitHub-hosted ARM64 ubuntu-24.04-arm-2x 環境はVM
Self-hosted AMD64 Self-hosted (2Core/AMD) 環境はコンテナ、スペックはCPU: 2 , Memory 8GB、インスタンスタイプはm6id
Self-hosted ARM64 Self-hosted (2Core/ARM) 環境はコンテナ、CPU: 2 , Memory 8GB、インスタンスタイプはm8gd

比較内容

コメントの(1)〜(4)は結果の表で使用します。

- name: sysbench 1 process 2 threads # (1) 整数演算 2スレッド並列処理のパフォーマンス
  id: cpu_test_sysbench_1_process_2_threads
  run: |
    sysbench cpu --cpu-max-prime=100000000 --threads=2 run
    
- name: sysbench 2 processes 1 thread # (2) 整数演算 2コアのパフォーマンス
  id: cpu_test_sysbench_2_processes_1_thread
  run: |
    for i in $(seq 1 2); do
      (sysbench cpu --cpu-max-prime=100000000 --threads=1 run) &
    done
    wait
    
- name: sysbench 2 processes 2 threads # (3) 整数演算 2コアの並列処理のパフォーマンス
  id: cpu_test_sysbench_2_processes_2_threads
  run: |
    for i in $(seq 1 2); do
      (sysbench cpu --cpu-max-prime=100000000 --threads=2 run) &
    done
    wait
    
- name: stress-ng # (4) 行列計算
  id: cpu_test_stress-ng
  run: |
    stress-ng --matrix 2 --matrix-ops 2500000

結果

3回の平均値を記載しています。

項目 ubuntu-latest ubuntu-24.04-arm-2x Self-hosted (2Core/AMD) Self-hosted (2Core/ARM)
総実行時間 24m 19s 12m 28s 14m 48s 14m 8s
(1) 3m 23s 2m 7s 2m 14s 2m 34s
(2) 3m 23s 2m 7s 2m 14s 2m 34s
(3) 6m 46s 4m 14s 4m 29s 5m 7s
(4) 10m 23s 3m 28s 5m 36s 3m 37s

簡単な考察

  • ubuntu-latestはどの処理もあまり早くない
    • 特にmatrixのパフォーマンスが顕著に悪い
  • ubuntu-24.04-arm-2xはパフォーマンスに優れている
  • Self-hosted runnerはどちらのアーキテクチャも比較的パフォーマンスが良い
  • armはmatrixのパフォーマンスが良い

1 Coreのパフォーマンス比較

比較対象

Runner種別 Architecture label 備考
GitHub-hosted AMD64 ubuntu-slim 環境はコンテナ
Self-hosted AMD64 Self-hosted (1Core/AMD) 環境はコンテナ、スペックはCPU: 1, Memory 4GB、インスタンスタイプはm6id
Self-hosted ARM64 Self-hosted (1Core/ARM) 環境はコンテナ、スペックはCPU: 1, Memory 4GB、インスタンスタイプはm8gd

比較内容

ubuntu-slimは15分の実行制限があり、あまり長いジョブを実行することができないため、2 Coreのパフォーマンス試験と一部異なるジョブを実行しています。

コメントの(1)〜(3)は上記と同様に結果の表で使用します。

- name: sysbench 1 threads # (1) 整数演算 1コア単体のパフォーマンス
  id: cpu_test_sysbench1
  run: |
    sysbench cpu --cpu-max-prime=100000000 --threads=1 run

- name: sysbench 2 threads # (2) 整数演算 1コアの並列処理のパフォーマンス
  id: cpu_test_sysbench2
  run: |
    sysbench cpu --cpu-max-prime=100000000 --threads=2 run

- name: stress-ng # (3) 行列計算
  id: cpu_test_stress-ng
  run: |
    stress-ng --matrix 1 --matrix-ops 500000

結果

3回の平均値を記載しています。

項目 ubuntu-slim Self-hosted (1Core/AMD) Self-hosted (1Core/ARM)
総実行時間 13m 9s 9m 22s 9m 34s
(1) 2m 3s 2m 15s 2m 34s
(2) 7m 1s 4m 39s 5m 8s
(3) 3m 46s 2m 15s 1m 27s

簡単な考察

ほぼ2 Coreと同じような内容ですが、下記のようなことが言えます。

  • ubuntu-slimは1コア1スレッドのパフォーマンスはよいが、並列処理になるとパフォーマンスが劣化する
    • CPUのスペック(後述)を見る限りでは、ubuntu-latestと同じマシンに載っているようだが、単純計算が比較的早い
    • 相当に単純なジョブであれば使用に問題はなさそう
  • Self-hosted runnerはコア数とスレッド数が比例して性能が出るのに対し、GitHub-hosted Runnerでは挙動が異なる
  • 2コアのubuntu-latestで2 threadsのパフォーマンスと、1コアのubuntu-slimで1 threadのパフォーマンスが比例しない
  • Self-hosted runnerはどちらのアーキテクチャも比較的パフォーマンスが良い
  • armはmatrixのパフォーマンスが良い

まとめ

このブログでは、GitHub ActionsのRunnerにおける、CPUのパフォーマンス比較を行いました。CPUは処理内容によって差が大きいため、実際のジョブでは今回の結果ほどの差が出ないこともありますが、ジョブのパフォーマンスアップを考えたときにどこにボトルネックがあるのかの比較になれば幸いです。

すぐにSelf-hosted runnersを準備するのは難しいかもしれませんが、GitHub-hostedのArm runnerであればすでにGAとなっており利用可能です。対応できる部分からArmへ移行していくことが、ジョブの高速化への近道となりそうです。

パフォーマンス試験を行うきっかけとなったDisk I/Oに関しては、また別のブログで記載しますので、お待ち下さい。

おまけ

2025/11/25時点のubuntu-latestにおいてlscpuを実行すると、下記のようになっており、2 CoreというよりHyper-Threadingによる論理的な2 Coreであることがわかります。

Architecture:                         x86_64
CPU op-mode(s):                       32-bit, 64-bit
Address sizes:                        48 bits physical, 48 bits virtual
Byte Order:                           Little Endian
CPU(s):                               2
On-line CPU(s) list:                  0,1
Vendor ID:                            AuthenticAMD
Model name:                           AMD EPYC 7763 64-Core Processor
CPU family:                           25
Model:                                1
Thread(s) per core:                   2
Core(s) per socket:                   1
Socket(s):                            1
Stepping:                             1

上記の"簡単な考察"のところでubuntu-latest,ubuntu-slimはともにマルチスレッドがかなり遅くなることを記載しましたが、このlscpuの結果が示す通り、物理コアではなくHyper-Threadingによる論理コアが割り当てられているためだと考えられます。

2 Coreの(3)の結果で時間がきれいに2倍(3m23s -> 6m46s)になっているのは、ubuntu-latestのパフォーマンスが維持されているというよりは、(1)や(2)の時点ですでに物理コアの演算能力が飽和しており、(3)では単純に処理待ちの行列が2倍になったためと考えられます。sysbenchのようなメモリ競合の少ないタスクでは、OSのスケジューリングによるオーバーヘッドが少ないため、こうしたきれいな線形の結果になりやすいようです。

ubuntu-24.04-arm-2xにおいてlscpuを実行すると、こちらは2 Coreになっていることがわかります。

Architecture:                            aarch64
CPU op-mode(s):                          32-bit, 64-bit
Byte Order:                              Little Endian
CPU(s):                                  2
On-line CPU(s) list:                     0,1
Vendor ID:                               ARM
Model name:                              Neoverse-N2
Model:                                   0
Thread(s) per core:                      1
Core(s) per socket:                      2
Socket(s):                               1