GitHub ActionsでUbicloudのARM64ランナーを使用してDockerビルドを高速化する

ARMContainerSoftware

はじめに

GitHub Actionsを使ってマルチアーキテクチャ(x86_64とarm64)のDockerコンテナイメージをビルドする際、無料枠のGitHubランナーだけでは効率的に処理できない問題に直面しました。特にARM64向けのビルドが大きなボトルネックとなっていましたが、Ubicloudの自前ランナーを導入することで劇的に改善できたので、その方法を共有します。

問題: QEMUを使ったクロスビルドの限界

これまで私は、matrixを用いて並行ビルドを実施していました。GitHub Actionsの無料枠では x86_64(amd64)のランナーしか提供されていないため、arm64向けのDockerイメージビルドには QEMU を使ったクロスビルドを行っていました。

しかし、ISC Keaのイメージをビルドする場合、amd64は20分程度で完了する一方、arm64は2時間以上かかってしまい、GitHub Actionsのランナー無料枠を急速に消費してしまう状況でした(もちろん私のDockerfileに改善の余地があるかもしれません)。

解決策: Ubicloudの自前ランナーを導入

そこで、GitHub Actionsの無料枠に頼らず、自前のランナーを用意してamd64とarm64のDockerイメージを効率的に作成することにしました。AWS CodeBuildやBuildjetなどのサービスも検討しましたが、価格面で優位だったUbicloudを採用することにしました。

Ubicloudとは?

Ubicloudは「オープンで自由、ポータブルなクラウド」を標榜するサービスです。公式サイトには以下のように説明されています:

※なお、本記事ではUbicloudの登録作業やGitHub Actionsとの連携設定などの基本セットアップについては割愛します。詳細は公式ドキュメントをご参照ください。

Ubicloudは、オープンで自由、そしてポータブルなクラウドです。Linux が独自OSに対するオルタナティブであるように、パブリッククラウドプロバイダーに対するオルタナティブと考えてください。

UbicloudはHetzner、Leaseweb、Latitude.shなどのベアメタルインスタンスをリースするプロバイダー上でインフラストラクチャー・アズ・ア・サービス(IaaS)機能を提供します。マネージドサービスとしても利用可能です。

マネージドサービスで使用するベアメタルインスタンスの低コストにより、私たちはその低価格をお客様に還元し、クラウドコストを3〜10倍削減できます。

重要なポイントとして、Ubicloudは GitHub Actions との連携もサポートしています。詳細は公式ドキュメントで確認できます。

Ubicloudの料金体系

Ubicloudの料金体系は以下の通りです:

Linux x64

YAML runner tagvCPUMemoryPrice
ubicloud-standard-228GB$0.0008/min
ubicloud-standard-4416GB$0.0016/min
ubicloud-standard-8832GB$0.0032/min
ubicloud-standard-161664GB$0.0064/min
ubicloud-standard-3030120GB$0.0120/min

Linux arm64

YAML runner tagvCPUMemoryPrice
ubicloud-standard-2-arm26GB$0.0008/min
ubicloud-standard-4-arm412GB$0.0016/min
ubicloud-standard-8-arm824GB$0.0032/min
ubicloud-standard-16-arm1648GB$0.0064/min
ubicloud-standard-30-arm3090GB$0.0120/min

今回のarm64ビルド用に、デフォルトの ubicloud-standard-2-arm を選択しました。

GitHub Actionsワークフローの変更点

ワークフローファイルの主な変更点は以下の2つです:

  1. ランナーの条件分岐:
    runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || 'ubicloud-standard-2-arm' }}
    • matrix.platformが linux/amd64 の場合は ubuntu-latest を使用
    • それ以外(arm64の場合)は ubicloud-standard-2-arm を使用
  2. QEMUセットアップの条件付き実行:
    - name: Set up QEMU if: matrix.platform == 'linux/arm64' && runner.arch == 'X64' uses: docker/[email protected]
    • amd64ランナーでarm64イメージをビルドする場合にのみQEMUをセットアップ
    • Ubicloudの ARM runnerを使う場合は、ネイティブarm64環境なのでQEMUは不要
  3. - uses: docker/build-push-action@v6 のキャッシュ部分を公式ドキュメント通りに修正:

変更差分

diff -ur .github/workflows/docker-build.yml.20250326 .github/workflows/docker-build.yml
--- .github/workflows/docker-build.yml.20250326 2025-03-27 21:48:36.859477231 +0900
+++ .github/workflows/docker-build.yml  2025-03-27 22:56:05.274661165 +0900
@@ -63,12 +63,12 @@
   build:
     needs: prepare
     if: needs.prepare.outputs.directories != '[]'
-    runs-on: ubuntu-latest
     strategy:
       fail-fast: false
       matrix:
         platform: [linux/amd64, linux/arm64]
         directory: ${{ fromJson(needs.prepare.outputs.directories) }}
+    runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || 'ubicloud-standard-2-arm' }}
 
     steps:
       - name: Checkout repository
@@ -103,7 +103,10 @@
             echo "suffix=arm64" >> $GITHUB_OUTPUT
           fi
 
+      # QEMU setup is only needed for AMD64 runners building ARM64 images
+      # For native ARM64 runners, we can skip this step
       - name: Set up QEMU
+        if: matrix.platform == 'linux/arm64' && runner.arch == 'X64'
         uses: docker/[email protected]
         with:
           image: tonistiigi/binfmt:qemu-v8.1.5
@@ -133,7 +136,7 @@
           build-args: |
             VERSION=${{ steps.set-version.outputs.release_version }}
           cache-from: type=gha
-          cache-to: type=gha,mode=max
+          cache-to: type=gha
           outputs: type=image,name=${{ secrets.DOCKER_USERNAME }}/${{ steps.image-name.outputs.image_name }},push-by-digest=true,name-canonical=true
 
       - name: Export digest

なお、QEMU関連の設定はやや冗長なので、より単純化することも可能です。

ubicloudにてrunnerが起動したことを確認

結果と費用対効果

実際に実行してみた結果:

  • QEMUでのクロスビルド: 2時間以上
  • Ubicloudネイティブランナー: 約40分

大幅な時間短縮に成功しました!

費用面では、80分ほど利用して(1回目の実行が失敗したのは内緒です)約0.07ドル(日本円で約10円)の支出でした。GitHub Actionsの無料枠の消費を抑えつつ、ビルド時間も短縮できるため、非常に費用対効果が高いと言えます。

まとめ

GitHub ActionsでマルチアーキテクチャのDockerイメージをビルドする際、特にarm64向けビルドではUbicloudの自前ランナーを活用することで、ビルド時間を大幅に短縮でき、かつコストも抑えられることがわかりました。

私個人のISC Keaのイメージビルドでは、2時間以上かかっていた処理が40分程度に短縮され、費用も非常に安価で済みました。GitHub Actionsでコンテナイメージのクロスビルドをする際、特にarm64のビルド時間が長くなりがちな場合に、GitHub Actionsの無料枠を使い切ってしまう前に自前ランナーに切り替えることで、ビルド時間を大幅に短縮しつつ、課金額も最小限に抑えられるため、ビルドの高速化と費用のバランスを取りたい方には特におすすめの方法です。

追記:2025/04/01

今更ながら2025年1月16日に組織以外で、パブリックなレポジトリであれば使用できるarm64なrunnerがGithubから出ていたみたいです。

この記事を書いた人

kometchtech

うつ病を患いながら、IT業界の末席にいるおっさんエンジニア。科学計算をしたことがないのに、HPC分野にお邪魔している。興味のある分野で学習したことをblogにまとめつつ、うつ病の経過症状のメモも置いておく日々。じつはRouterboard User Group JPの中の人でもある。 Amazon欲しいものリスト / Arm板を恵んでくれる人募集中

kometchtechをフォローする
タイトルとURLをコピーしました