GitHub Actions上でARMを利用するDockerを使った方法
#GitHub_Actions
やりたいこと
GitHub Actions上でARMを使いたい。ARM向けの動作確認やARM向けのバイナリを生成するためにGitHub Actionsを使いたい。そこでDockerのdocker run -it arm32v7/ubuntu:18.04やarm64v8/ubuntu:18.04によってARM向けのイメージが使えることを利用する。
やりかた
やり方はdocker runする前に以下のdocker/setup-qemu-actionをするだけ。
code:yml
...
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- run: |
docker run --rm -i -v $PWD:/ws arm32v7/ubuntu:18.04 bash <<'EOF'
set -xeu
cd /ws
uname -a
apt update
EOF
参考:
https://github.com/docker/setup-qemu-action
https://github.com/crazy-max/ghaction-docker-buildx
https://medium.com/swlh/using-github-actions-to-build-arm-based-docker-images-413a8d498ee
docker runについて
docker run以降にARM上で動かしたい処理を書いている。
docker run --rm -i -v $PWD:/ws arm32v7/ubuntu:18.04 bash <<'EOF'は、複数行を実行するために<<'EOF'をしている。シングルクォート'にする理由は内部の文字列に$MY_ENVのような文字列があったときにコンテナ外部のホスト環境の環境変数を取り込まないようにするため。そういう意図はあっても良いが行数が増えると保守しづらくなる。ホスト環境の環境変数を渡したい時はdocker runの-eで明示的に渡す。
またカレントディレクトリをコンテナ内で利用するために-v $PWD:/wsにして、EOF内でcd /wsしている。
set -xeuはなくても好みでつけておりなくても良い。オプションの説明としては-xで実行するコマンドの表示、-eはexit codeが0ではない時に終了させるため、-uは未定義の環境変数を利用したときにエラーさせる。
実際のログ
以下が実際のGitHub Actionsのログだが、uname -aのところで「... armv7l armv7l armv7l ...」と表示されていることが確認できる。
https://scrapbox.io/files/616b7a44d2b72e001d1bd668.png
arm64v8/ubuntu:18.04も動くことを確認した。
実際のworkflow
実際のGitHub Actionsのworkflowは以下にある。
https://github.com/nwtgck/github-actions-arm-with-docker-prac/blob/8ad49d25a85b61afa23e4b17a627a22126d10b34/.github/workflows/ci.yml
おまけ: 詳細
上記まででやり方の説明は完了。もう少し詳細の説明。
ARM向けのDockerイメージに関しては、以下のDocker公式にあるように、https://hub.docker.com/u/arm32v6/、arm32v7/、arm64v8/は公式がサポートしている。
Architectures other than amd64?
仮にdocker/setup-qemu-actionをしない場合はdocker run実行時に「 standard_init_linux.go:228: exec user process caused: exec format error」というエラーが出てdocker runが実行できた。
docker runの複数行に関しては「docker runするときに複数行のShellをファイルを使わずに実行させたい - ヒアドキュメントを使う」で触れた。
以下はDocker for Macの説明ではあるが、qemu-staticでamd64 (x64)でもARM向けのDockerイメージを実行することができる。
Docker for Mac 仮想マシン が qemu-static を使うので、コンテナ内で特別な設定は不要です。これにより、 busybox イメージの arm32v7 や ppc64le に対応した ARM コンテナを実行可能です。
マルチ CPU アーキテクチャのサポートを活用 — Docker-docs-ja 19.03 ドキュメント
Dockerイメージarm32v7/ubuntu:18.04を使う意外の方法として、
docker run --platform linux/arm/v7 ...のように--platformを指定することが出来る。つまり以下のように実行できる。
code:yml
- run: |
docker run --platform linux/arm/v7 -i -v $PWD:/ws ubuntu:18.04 bash << EOF
...
EOF
おそらく、上記の--platformは、Docker HubのTagsの「OS/ARCH」と対応しているのだと思う。
https://scrapbox.io/files/616b7f10b52058001de2ab42.png
上記画像はUbuntuの例: https://hub.docker.com/_/ubuntu/?tab=tags
おまけ: 経緯
GitHub ActionsでARMの環境が欲しくなった経緯について。
Piping Serverのワンバイナリを提供するために、Next.jsで有名なVercelが作っているpkgを利用している。このvercel/pkgを使えばNode.jsのプロジェクトをワンバイナリ化できる。つまりNode.jsがインストールされていない環境でも実行できるバイナリになる。
https://github.com/nwtgck/piping-server-pkg
Piping ServerのポータブルなARMのバイナリも自動化してGitHub Releasesで提供したくなり、CI上にARM環境が必要になった。arm32v7/node:14というNode.jsのARMのDockerイメージがあるのでそれを利用した。
以下がARMバイナリを生成するための実際のコミット:
https://github.com/nwtgck/piping-server-pkg/commit/c401b38ea3f1b7ff28a6ae99f73dba682782b833
vercel/pkgでARM対応するにはarm64を指定するが、arm64でもarm32v7/ubuntu:18.04のようなarm32で動くのはどういうことなのかまだ不明。
piping-serverの選択肢はRustもある: https://github.com/nwtgck/piping-server-rust