背景・目的
- Graviton2プロセッサを搭載したAWS Lambdaだと、パフォーマンス上のメリットがある
- numpyなど、プラットフォーム専用にビルドが必要なライブラリを使う場合に、arm64用のnumpyを用意する必要があった
- これを解決するために、結構苦戦したので、備忘しておく
問題
- Github Actionsだとamd64(x86_64)のCPUアーキテクチャのマシンで実行される
- Github Actions上でarm64のdocker イメージを実行すると、
exec /usr/bin/bash: exec format error
のようなエラーが発生する - arm64のためのパッケージを作れなかった・・
解決策
- https://github.com/docker/setup-qemu-action のステップをdockerコマンドの実行前に組み込むことで、arm64のdocker imageをarm64のプロセッサで起動することができる
jobs:
qemu:
runs-on: ubuntu-latest
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: linux/arm64
- arm64のdocker imageを使ってコンテナを起動し、その中でビルドを行うことでarm64用のnumpy込みのパッケージを作ることができた
arm64って何?
AArch64またはARM64は、ARMアーキテクチャの64ビット命令セットである。 (ウィキペディア)
CPUアーキテクチャの1種で、CPUがプログラムを処理するときの命令セット
-
関係性
-
例
CPU アーキテクチャ Intel x86_64 AMD amd64(x86_64) Apple M1 arm64
QEMUって何?
QEMU (クイック エミュレーターの略) は、ハードウェア仮想化を実行する無料のオープン ソース エミュレーターです。動的バイナリ変換によってマシンのプロセッサをエミュレートし、マシンにさまざまなハードウェアとデバイス モデルのセットを提供して、さまざまなゲスト オペレーティング システムを実行できるようにします。(参考)
-
- フルシステムエミュレーション
- 別アーキテクチャのOSを丸ごと実行できる
- ユーザーモードエミュレーション
- 別アーキテクチャのプログラム実行を可能にする
- フルシステムエミュレーション
-
基本的な使い方(ユーザーモードエミュレーション)
qemu-<arch>[-static] <binary>
qemu-arm64-staticなどのコマンドをインストールしておけば、別アーキテクチャのバイナリファイルを実行できる
-
Docker上での使われ方(Linuxの場合)
- Linuxには
binfmt_misc
という機能があり、任意の実行可能ファイル形式を透過的に認識して、特定のアプリケーションに渡すことができる - QUSを使うと、おそらく、docker imageがどの命令セットで動作するのか?の情報に基づいて、適切な命令セットで実行できるようにしてくれる
- どうやってdocker imageのアーキテクチャ情報を知っているのか?と、どのようにQEMUに渡しているのか?までは追えず・・。
- Linuxには
-
Docker上での使われ方(Mac, Windows)
- Docker Desktopの場合、QEMU がインストールされ、デフォルトで有効になっているとのこと
-
ユーザーモードエミュレーションの 3 つの主な注意事項(参考)
- ユーザー モード エミュレーションは、フル システム エミュレーションよりも洗練されていないように見えるため、サポートされていない機能を使用するとクラッシュする可能性がある
- 基盤となるマシンがホストであるため、エミュレートされたカーネルはなく、ターゲット デバイス/システムに固有のハードウェア リソースは利用できない (フル機能の VM とは異なる)
- プログラムとホストが分離されていないため、悪意のあるプログラムが特権を取得する可能性がある
まとめ
- 別のCPUアーキテクチャのプログラムを実行するときにはQEMUというOSSが活用されているということがわかった
- ユーザーモードでのエミュレーションはセキュリティ上のリスクもあるため、CI/CDのワークフローで使われることが多いらしい
- github actionsにおいては、ステップを一つ追加するだけで、dockerが別アーキテクチャのイメージを起動してくれることが分かった
- (今回は、cdk経由でdockerを起動していたので、もしかしたら、素のdockerコマンドを使う場合は
buildx
コマンドなどを使ったり、platformオプションを指定したりが必要かもしれないが、今回は調査しきれず、また時間があるときに調べます・・)
- (今回は、cdk経由でdockerを起動していたので、もしかしたら、素のdockerコマンドを使う場合は