M1 Macが普及してきて、手元はarm64なのにサーバーはx86_64、という状況が増えてきました。docker pullしたイメージがアーキテクチャ不一致で動かないのが地味にストレスだったので、GitHub Actionsでマルチアーキテクチャビルドを組んでみました。
この記事は2022年11月時点の構成です。2024年9月にGitHub Actionsのarm64ネイティブrunnerがGAとなり、2025年以降はPublic/Privateリポジトリでも利用可能になっています。QEMUエミュレーションなしでネイティブビルドができるため、ビルド時間の問題は解消できるようです(私自身は未検証)。各Actionのメジャーバージョンも当時から上がっているので、最新版は各リポジトリで確認してください。
構成の全体像
ワークフローの流れです。
- tagのpushをトリガーに自動実行(
workflow_dispatchで手動実行も可能) docker/metadata-actionでsemverパターンに基づくタグ名を自動生成- QEMU + Docker Buildxでマルチプラットフォームビルド環境をセットアップ
docker/build-push-actionでビルド & Docker Hubへpush
使っているActionsはこのあたりです。
- actions/checkout — コードのチェックアウト
- docker/metadata-action — タグ命名の自動化
- docker/login-action — Docker Hubへのログイン
- docker/setup-qemu-action — マルチアーキテクチャ用エミュレーション
- docker/setup-buildx-action — Buildxのセットアップ
- docker/build-push-action — ビルド & プッシュ
CI設定は個々のstepを調べながら書くと迷子になりやすいので、先に全体の流れを掴んでから各stepの詳細に入るようにしていました。
cache type=gha
ビルドキャッシュは type=gha を使いました。2022年11月時点ではExperimentalでしたが、設定がシンプルなので採用しています。
cache-from: type=gha
cache-to: type=gha,mode=max
arm64を追加するとビルドが遅くなる
amd64だけなら2分で終わっていたビルドが、arm64を追加すると15分くらいまで膨らみました。QEMUのエミュレーションが入るので仕方ないところです。tagをpushしたときだけの実行なので日常的には困りませんでしたが、featureブランチごとに回す運用だったら厳しそうです。
実行結果はこんな感じで、1回のビルドでlatestとsemverタグにamd64/arm64の両方が並びます。
Docker Hub Access Token
Docker HubのログインにはパスワードではなくAccess Tokenを使います。
GitHubリポジトリのSettings > Secrets and variablesに DOCKERHUB_USERNAME と DOCKERHUB_TOKEN を登録しておけば、ワークフロー内で secrets.DOCKERHUB_USERNAME として参照できます。スコープを絞れますし、漏洩時もトークンだけ無効化すればいいので安心です。
一度組んでしまえば、あとはtag pushだけで両アーキテクチャのイメージがレジストリに並びます。
![Notion を Hugo のヘッドレスCMSとして利用する方法 [Notion Hugo Exporter]](/tcard/notion-hugo-exporter-getting-started/2022-12-03-notion-hugo-exporter-getting-started.webp)

