この記事は ABEJA Platform Advent Calendar の 13 日目の記事です。
昨日までの Advent Calendar では、比較的 ABEJA Platform を利用する内容の記事が多かったので、本記事では、ABEJA Platform を開発するのにこんなことしてますよ(の一部)という内容を書きます。
以前、ABEJA Arts Blog にてJetson 上で Docker イメージをビルドするのが辛かったので EC2 上にビルド環境を作った という話を書きましたが、今回はその記事の焼き直しです。
AWS EC2 A1 インスタンスファミリー
焼き直し記事を書かざるを得なかった理由がこれです。
そう、AWS EC2 に、ARM ベースのインスタンスファミリーが登場したので、以前書いた記事は要らない子になってしまったのでした。
というわけで今回は、A1 インスタンスを使った ARM 用 Docker image 作成方法について記載することにしました。
A1インスタンスセットアップ
choose ami for arm
AMI の検索窓にarm
と入力すれば、arm用のamiを見つけられます。
arm 用の AMI を選択すると、「Choose an Amazon Machine Image」ページでも、A1インスタンスファミリーのみが選択できるようになってますね。当然といえば当然ですが、地味に便利。
起動したインスタンスのアーキテクチャを見てみると、 aarch64
となっていて、間違いなく 64bit ARM であることがわかります。
$ uname -m
aarch64
Docker CE のインストール(必要な場合)
選択した AMI によっては、 docker
がインストールされていない場合があります。 ubuntu 16.04
とか。
せっかくなので最新の docker をインストールしたくなりますが、Docker の Documentation(たとえば Ubuntu)を見ると、aarch64(arm64) について記載がなく、まさかの docker のビルドからか、、、と一気にモチベーションが下がりますが、実は download.docker.com に aarch64 用のバイナリパッケージも配置してありました。
Ubuntu 16.04 用なら、 https://download.docker.com/linux/ubuntu/dists/xenial/pool/stable/arm64/ 配下に deb パッケージがあります。
あとは、 sudo usermod -aG docker ubuntu
して logout/login すれば、 sudo
不要で ubuntu
ユーザーから docker
コマンドを利用できるようになります。
パフォーマンス比較してみる
せっかくなので、以前まで使っていた QEMU 環境とのパフォーマンス比較もしてみました。
比較環境としては、それぞれ以下のインスタンスを利用しました。
- QEMU 環境側は
c5.4xlarge
- A1 側は
a1.4xlarge
コンピュート最適化インスタンスである C5 インスタンスファミリーから、 A1 インスタンスファミリー最多 vCPU を誇る a1.4xlarge
と同じ vCPU 数の c5.4xlarge
をチョイス。
Docker image のビルド用に作った環境なので、 docker build
にかかる時間を比較します。
比較に利用する Dockerfile
は、先日業務で必要になった llvmlite
ビルド用の Dockerfile をほぼそのまま使いました。
FROM arm64v8/ubuntu:16.04 # for a1 instance
FROM multiarch/ubuntu-core:arm64-xenial # for c5 instance
WORKDIR /tmp
ARG CPU_COUNT=16
ARG LLVM_VERSION=6.0.1
ARG LLVMLITE_VERSION=0.25.0
##############################################################################
# base tools
##############################################################################
RUN apt-get update \
&& apt-get install -y --no-install-recommends software-properties-common \
unzip \
wget \
xz-utils \
g++ \
make \
cmake \
libedit-dev \
patch \
&& add-apt-repository ppa:deadsnakes/ppa \
&& apt update \
&& apt install -y --no-install-recommends \
python3.6 \
python3.6-dev \
&& wget -O ~/get-pip.py https://bootstrap.pypa.io/get-pip.py \
&& python3.6 ~/get-pip.py \
&& ln -s /usr/bin/python3.6 /usr/local/bin/python3 \
&& ln -s /usr/bin/python3.6 /usr/local/bin/python \
&& rm ~/get-pip.py \
&& python -m pip --no-cache-dir install --upgrade setuptools \
##############################################################################
# build llvm
##############################################################################
&& wget https://github.com/numba/llvmlite/archive/v${LLVMLITE_VERSION}.zip \
&& unzip v${LLVMLITE_VERSION}.zip \
&& wget http://releases.llvm.org/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz \
&& tar xf llvm-${LLVM_VERSION}.src.tar.xz \
&& cd llvm-${LLVM_VERSION}.src \
&& patch include/llvm/Analysis/CFGPrinter.h /tmp/llvmlite-${LLVMLITE_VERSION}/conda-recipes/twine_cfg_undefined_behavior.patch \
&& sed -i -e "/^# CPU_COUNT=1$/a _cmake_config\+=\(-DLLVM_TARGETS_TO_BUILD=\"ARM;X86;AArch64\"\)" /tmp/llvmlite-${LLVMLITE_VERSION}/conda-recipes/llvmdev/build.sh \
&& export CPU_COUNT=${CPU_COUNT} \
&& chmod 755 /tmp/llvmlite-${LLVMLITE_VERSION}/conda-recipes/llvmdev/build.sh \
&& /tmp/llvmlite-${LLVMLITE_VERSION}/conda-recipes/llvmdev/build.sh \
##############################################################################
# build llvmlite
##############################################################################
&& cd /tmp/llvmlite-${LLVMLITE_VERSION} \
&& python setup.py bdist_wheel
LLVM_TARGETS_TO_BUILD に X86 とか入ってますが気にしないでください。
make
じゃなくて ninja
でしょ、とか clang
使おうぜ、とかも見なかったことにしていただきたく。
あと、FROM
行を 2 行書いているのは、コメントでおわかりの通り、環境によって切り替えています。
上記 Dockerfile を、以下のコマンドで3回実行し、 real
の時間で比較します。
$ time docker build -t llvmlite:latest -f Dockerfile --no-cache .
計測結果がこちら。
instance type | 1回目 | 2回目 | 3回目 | 平均 | 時間単価(Oregon) |
---|---|---|---|---|---|
a1.4xlarge | 15m13.276s | 15m57.977s | 15m22.979s | 15m31.411s | $0.408/h |
c5.4xlarge | 58m 14.567s | 58m54.770s | 59m42.746s | 58m57.361s | $0.68/h |
なんと a1.4xlarge の方が 4倍近く速いという結果に。
それでいてお値段は 2/3 以下。
c5.18xlarge
とか使えば、単純計算では a1.4xlarge
を越えそうですが、 Dockerfile 内の処理が常にマルチコアを有効に使えるわけではないし、単価も跳ね上がるので、 64bit ARM 用の 作業をするなら A1 インスタンスファミリーが最適解かと思います。
まとめ
- 64bit ARM 向けの Docker image のビルドは A1 インスタンスファミリーを使いましょう
- でもわざわざビルドしなくても ABEJA Platform ならビルド済みのイメージがイロイロ揃ってますよ(宣伝)