x64アーキテクチャのWindows環境で、arm64アーキテクチャのAWS Lambdaレイヤーを作成する方法を紹介します。
背景:なぜ作ってみるのか
当社では、自作の業績データ取得ツールを活用して、上場企業の業績データを収集しています。詳細は、こちらの記事で紹介しています。
ツールの中核となるLambda関数は、適時開示情報閲覧サービス(TDnet)からデータを取得・解析してDynamoDBなどに格納していますが、決算発表のピーク日に処理時間が長くなりがちです。実装自体を見直す必要もありそうですが、ひとまずCPUアーキテクチャをx64からarm64に変更してみることにしました。AWS Lambdaは、2021年秋よりarm64アーキテクチャをサポートしています。同社のGravitonプロセッサー上で動作し、時間当たりの単価はarm64の方が安価です。そのため、処理時間の短縮に加え、低コスト化も期待できるかもしれません。
この関数はPythonの標準ライブラリー以外のモジュールを使っており、Lambdaレイヤーに格納しています。このレイヤーもarm64版に差し替えとなり、arm64版レイヤーを作成するにはarm64の環境が必要です。GravitonプロセッサーのEC2インスタンスを一時的に活用するという手もありますが、どうせなら使い慣れたPCで作業してみたいところです。
ということで、x64アーキテクチャのWindows PCを使って、arm64アーキテクチャのLambdaレイヤーを作成してみます。
作成手順
ここでは、Python 3.12のLambdaレイヤーを作っていくことにします。使用するマシンは、x64のCPUでOSがWindows 10のPCです。Windows Subsystem for Linux 2(WSL2)とUbuntuがインストール済で、さらにUbuntu上ではDockerがインストール済です。
arm64アーキテクチャ向けDockerイメージを動くように設定
arm64アーキテクチャのDockerイメージを動作可能にするには、QEMUの一部であるQEMU User Static ⧉のDockerイメージを利用します。
WSL2上のUbuntuで、以下のコマンドを実行します。
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
動作を確かめるために、以下のコマンドを実行し、aarch64
と出力されることを確認します。
$ docker run --rm -t arm64v8/ubuntu uname -m
(出力例)
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64/v3) and no specific platform was requested
aarch64
ホストOSとDockerでプラットフォーム(CPUアーキテクチャ)が異なる旨のWARNINGメッセージが表示されますが、意図して行っているため問題ありません。
Lambdaコンテナーイメージの入手・起動
レイヤーに格納するモジュールを作るにあたって、Lambdaが稼動するOS・アーキテクチャの環境と揃えたいので、AWS Lambda Base Container Images ⧉(Lambdaコンテナーイメージ)を使用します。Lambdaコンテナーの入手に必要なファイル一式はGitHubに公開されており、ローカルにクローンして利用します。ランタイム識別子を付されたブランチ ⧉(python3.12など)でチェックアウトして、Dockerイメージをビルドしていきます。
Dockerイメージの起動に必要なファイルをダウンロードできるようにするため、Git Large File Storage (LFS) ⧉をインストールします。
$ sudo apt install git-lfs
$ git lfs install
Lambdaコンテナーイメージをビルドして、コンテナーを稼動させます。
# 任意のディレクトリーで作業
$ git clone https://github.com/aws/aws-lambda-base-images
$ cd aws-lambda-base-images/
# 使用のPythonバージョンと同じものを指定してチェックアウト
$ git checkout python3.12
# arm64とx64に分かれているため、arm64に移動
$ cd arm64/
# Dockerイメージをビルド
$ docker build -t python3.12_arm64:local -f Dockerfile.python3.12 .
$ docker create -it --entrypoint /bin/bash python3.12_arm64:local
(ContainerIDが表示されます)
# ビルドしたDockerイメージを起動
$ docker start -i 【ContainerID】
bash-5.2#
# コンテナーの中にbashでログインした状態になります
なお、ベースイメージはアップデート頻度が高いので、コンテナーイメージやレイヤーの開発を継続的に実施する場合は、最新のブランチを取得してビルドし直すとよいかもしれません。
レイヤーに必要なライブラリー群の作成
コンテナーの中にログインした状態で、以下を入力します。
$ pip install --upgrade pip
$ mkdir python
$ cd python
# インストールしたいパッケージ名を列挙
$ pip install boto3 beautifulsoup4 html5lib pandas requests -t .
インストールするディレクトリー名は「python」にする必要があります。なお、「pip install」コマンドでインストールするパッケージは、業績データ取得ツールで使用している、Python標準ライブラリー以外のパッケージです。
この時点で、Lambdaコンテナーの中の「python」ディレクトリーには、レイヤーに格納したいパッケージが入ります。
レイヤーの容量削減
上記の「python」ディレクトリーをzipで固めるとLambdaレイヤーとして登録できますが、その前にできるだけ容量を削減します。zip圧縮前で250MB以下、zip圧縮後で50MB以下のサイズなら、Amazon S3を経由せずマネジメントコンソール上で登録できます。
Pythonの場合、以下のようにキャッシュを削除するのが効果的なようです。
# 【WSL2のUbuntuでコマンドを実行】コンテナー内のpythonディレクトリーをUbuntu内にコピー
$ mkdir python_for_awslayer
$ cd python_for_awslayer/
$ docker cp 【LambdaコンテナーのContainerID】:/var/task/python/ .
# レイヤーに不要な__pycache__ディレクトリーを削除
$ find ./python -type d -name "__pycache__" -prune -exec rm -rf {} \;
# 圧縮率最高でzip圧縮
$ zip -r -9 python python
# サイズ確認
$ du -h ./python
(個々のディレクトリー・ファイルの表示は略)
143M ./python
# 250MB以下であることを確認
$ du -h ./python.zip
44M ./python.zip
# 50MB以下であることを確認
最終的にできたzipファイルは、WSL2のUbuntu内にあります。Windowsのエクスプローラーのアドレスバーに\\wsl$
と入力すると、Ubuntu内に直接アクセスできるため、zipファイルの取り出しも容易です。
AWS Lambdaへレイヤーのzipファイルを登録
zipファイルを作成したら、Lambdaのレイヤーに登録します。WebブラウザーでAWSマネジメントコンソールのLambda管理画面に移動して、左サイドバーにある「レイヤー」をクリックすると、レイヤーの管理画面が表示されます。この画面からレイヤーの登録が可能です。登録方法の詳細は、公式ドキュメントをご参照ください。
おわりに
x64アーキテクチャのWindows上で、arm64アーキテクチャのLambdaレイヤーを作成する方法を紹介しました。異なるCPUアーキテクチャ向けのイメージやレイヤーの作成がDocker上でできるのは、便利です。
なお、今回試しにarm64に変更したLambda関数は、さほど処理時間が改善しなかったので実装自体を見直すことになりました。これも、異なるアーキテクチャでの動作を簡単に確認できたからこその結果ではあります。アーキテクチャの変更は改善の決め手ではありませんでしたが、効率的なアプローチを模索するキッカケにはなったということで、ご参考まで。