CodeBuild + ECR + AWS BatchでAWS Lambda Pythonレイヤー作成
背景
#AWS Lambdaの対応言語の中でもPythonはコード実行までの手間と学習コスト的にもお手軽で利用率が高いようです。私の主要言語はJavaなのですが、手っ取り早くLambdaを使いたいときは不慣れであってもお手軽なPythonを使いたくなります。
そして、Lambdaで外部ライブラリの力を借りたくなった時はレイヤーというものを用意する必要があります。AWSが予め用意してくれているレイヤーで事足りればよいのですが、そうではない場合は自前でレイヤーを用意しなければなりません。しかし、実際に手を動かしてみるとPythonの環境構築(OpenSSL絡み)でハマってしまい大変でした。そこで、大変なPython環境構築には手を出したくないのでdockerを使い、面倒なコマンド作業をシェルにして実行できたらいいなと思い、レイヤー作成ツールを作ってみました。
レイヤー作成ツールのdockerコンテナをどこで実行するべきなのかについては、紆余曲折を経てAWS Batchで実行することにしました。イメージのビルドにはCodeBuildを用います。そしてCodeBuildとAWS Batch環境構築用にCloudFormationテンプレートを用意しました。
コンテナ実行環境にAWS Batchを採用した背景
#本稿のAWS Batchを試す前に以下を全て試しましたが、そもそも無理だったり、出来たとしても納得ができるものではなかったので断念しました。
試行その1 - Lambda
#LambdaのレイヤーをLambdaで作成出来たら便利で面白いなと思って試してみました。
Lambdaをコンテナで実行しているときは/tmp
ディレクトリにしか書き込みができません。pip install
でインストール先を/tmp
にしましたが、結局インストールの管理情報の書き込みが/tmp
以外のディレクトリに対して行われるのでエラーになってしまい断念しました。
参考までに、コンテナ開発者向けの AWS Lambdaの「コンテナの制約」に以下の記載があります。
コンテナは読み取り専用のルートファイルシステムで実行されます( /tmp は書き込み可能な唯一のパスです)
試行その2 - CloudShell
#標準でdockerが使えて無料なのでいいなと思って試してみました。
CloudShell自体のCPUアーキテクチャーがx86_64だけしかなさそうで、Amazonが推しているarm64で作成したイメージのコンテナ実行ができなかったため断念しました。docker用クロスプラットフォームエミュレーターを入れてみても上手くいきませんでした。
試行その3 - EC2
#arm64のインスタンスを用意したので、当然arm64で作成したイメージのコンテナ実行はできました。しかし、都度利用するには手順が多くて、インスタンス稼働時間も純粋にコンテナ実行時間のみにはできずコストが勿体ないので、AWS Batchがよさそうだと思いました。
レイヤー作成ツール
#レイヤー作成ツールを作ってみました。とにかくdockerさえ利用できればどこでも利用可能です。ローカル開発環境でも利用できます。
レイヤー作成シェル
#一般的にPythonのLambdaレイヤーを作成および登録する手順は以下の通りです。
- Pythonライブラリインストールコマンドを実行します
- レイヤー(zipファイル)を作成します
- 定められたディレクトリ構成で用意してzipファイルに圧縮しなければなりません
- python
- python/lib/python3.x/site-packages (サイトディレクトリ)
- 定められたディレクトリ構成で用意してzipファイルに圧縮しなければなりません
- レイヤー(zipファイル)をS3にアップロードします
- AWS CLIだと
s3 cp
- AWSマネジメントコンソール操作ではレイヤー作成時に直接レイヤーのzipファイルをアップロードできますが、10MBを超える場合はS3に置いてアップロードする必要があります
- AWS CLIだと
- Lambdaレイヤーを登録します
- AWS CLIだと
publish-layer-version
- AWS CLIだと
レイヤー作成シェルではこれらを一気通貫で実施します。なお、Python自作モジュールも併せて含めたLambdaレイヤーの作成には対応していません。
作成したLambdaレイヤーアップロード先のS3バケット名を指定しない場合はレイヤー作成までを行います。実行している環境からはS3に接続できないことが予めわかっている、といった場合でもレイヤー作成までは利用できるようにするためです。レイヤー(zipファイル)さえ作成できてファイルが手元にあれば、あとは手作業でなんとか対応できますよね。
また、普通にPythonが利用できる環境であれば、レイヤー作成シェルのみを直接利用してレイヤーを作成できます。
レイヤー作成シェルの使い方の詳細は以下のようなコマンドで確認できます。
./PublishPythonLambdaLayer.sh -h
Dockerfile
## see https://hub.docker.com/r/amazon/aws-lambda-python/
ARG BASE_IMAGE_TAG=latest
FROM amazon/aws-lambda-python:${BASE_IMAGE_TAG?}
COPY ./PublishPythonLambdaLayer.sh .
RUN <<EOF
chmod +x ./PublishPythonLambdaLayer.sh
# for Amazon Linux 2023 (for python 3.12)
if (type dnf > /dev/null 2>&1); then
# see https://docs.aws.amazon.com/ja_jp/linux/al2023/ug/deterministic-upgrades-usage.html
# dnf update -y
dnf upgrade -y --releasever=latest
dnf install -y zip unzip
dnf clean all
rm -rf /var/cache/dnf/*
# for Amazon Linux 2 (for python 3.11)
elif (type yum > /dev/null 2>&1); then
yum update -y
yum install -y zip unzip
yum clean all
rm -rf /var/cache/yum/*
else
echo update failed. unsupported package management tool.
exit 1
fi
# see https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html
if !(type aws > /dev/null 2>&1); then
CPU_ARCHITECTURE=$(uname -m)
if [ "$CPU_ARCHITECTURE" = "x86_64" ]; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
elif [ "$CPU_ARCHITECTURE" = "aarch64" ]; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" -o "awscliv2.zip"
else
echo aws cli install failed. unsupported cpu architecture.
exit 1
fi
unzip -qq awscliv2.zip
./aws/install > /dev/null 2>&1
rm -f awscliv2.zip
fi
EOF
ENTRYPOINT [ "bash", "./PublishPythonLambdaLayer.sh" ]
CMD [ "" ]
- ベースイメージ
- amazon/aws-lambda-pythonを利用します。AWS Lambda Pythonの実行環境そのものなのでレイヤーを作成するには最適な環境です。
- ベースイメージタグ
- docker build時にベースイメージのタグを
--build-arg BASE_IMAGE_TAG=<tag>
で指定できます。利用したいCPUアーキテクチャやPythonバージョンに見合った環境を柔軟に選択できます。例えば3.11
や3.12
を指定できます。しかし、Amazon Linux 2ベースのPython3.11ではyum
、Amazon Linux 2023ベースのPython3.12ではdnf
しか使えず、互換性がありませんでした。そこで、dnfコマンドが通るかどうかをチェックして、dnfとyumの使い分けをするようにして対応しました。
- docker build時にベースイメージのタグを
- インストールなどの初期化処理
- ヒアドキュメントで書いています。コマンドを頑張って
&& \
で数珠繋ぎしなくて済むので複雑な処理が書きやすくなり、その結果dockerイメージのレイヤ数も減らしやすくなるのでイメージのサイズを小さくできます。
- ヒアドキュメントで書いています。コマンドを頑張って
- その他
- AWS CLIのファイル解凍やインストールのログが大量に出て煩わしく感じたのでカットしています。
- レイヤー作成シェルのオプションは実行時にCMDで上書きできるようにしてあります。
レイヤー作成ツールインフラ構成図
#ビルド環境
#- S3にソース(レイヤー作成ツール)を置いて
- CodeBuildでdockerイメージを作成し
- ECRにpushします
実行環境
#- AWS BatchでECRからdockerイメージをpullして
- AWS Batchでコンテナを実行してレイヤーを作成し
- S3にアップロードして
- Lambdaにレイヤーを登録します
レイヤー作成ツール環境構築および実行方法
#AWS公式ではLambdaをはじめとするコンピューティングリソースのCPUアーキテクチャにarm64を利用することを強く推しているので、環境作成用のCloudFormationテンプレートのデフォルト値はarm64向けにしてあります。
AWS公式ではLambdaはarm64を強く推しているようです。arm64への移行まで言及していますね。Lambdaの料金をx86_64とarm64で比較してみると、arm64のほうがおよそ20%安いです。そして性能比較でも明らかにarm64に軍配が上がります。以下、引用です。
arm64 アーキテクチャ (AWS Graviton2 プロセッサ) を使用するLambda 関数は、x86_64 アーキテクチャで実行される同等の関数よりも大幅に優れた料金とパフォーマンスを実現します。高性能コンピューティング、ビデオエンコーディング、シミュレーションワークロードなど、コンピュータ集約型のアプリケーションに arm64 を使用することを検討してください。
ちなみにFargate料金でx86_64とarm64を比較した場合でも、CPUとメモリどちらもarm64のほうがおよそ20%安いです。
(1)ネットワーク構築
#AWS Batchの環境を作成するための、以下のネットワーク要件を全て満たすサブネットを用意します。
私が以前執筆した「AWS CloudFormationでやさしくネットワーク構築 - IPv6対応、NATゲートウェイ設置切替作業も易しくてお財布にも優しい!」という記事のCloudFormationテンプレートを使うと簡単に用意できます。
- S3に接続可能
- 外部アクセス不能なS3バケットに接続する場合はプライベートリンクで接続する(Gateway型VPCエンドポイントを用意してルーティングする)必要があります
- IPv4でインターネット接続可能
(2)レイヤー作成ツールソースコード格納用S3バケット作成
#CodeBuildではS3からソースコードを参照するようにしたので、レイヤー作成ツールソースコードを格納するS3バケットおよびフォルダを用意して、レイヤー作成ツールソースコード(DockerfileとPublishPythonLambdaLayer.sh)を同一階層に格納します。後で利用するrequirements.txtはついでに同じ場所に置いただけですので、他のバケットに置いても構いません。
例として、s3://publish-lambda-layer-tool-pcjkn63zhk/python/
に用意しました。
なお、S3バケット作成時の設定「パブリックアクセスをすべて ブロック」はチェックを付けておくことが望ましいです。
(3)Lambdaレイヤー格納用S3バケットの作成
#作成したLambdaレイヤーをアップロードするS3バケットを用意します。
例として、s3://lambda-layer-pcjkn63zhk/
を用意しました。
なお、S3バケット作成時の設定「パブリックアクセスをすべて ブロック」はチェックを付けておくことが望ましいです。
(4)CodeBuildプロジェクトおよびECRリポジトリ作成
#CodeBuildプロジェクトおよびECRリポジトリを作成するCloudFormationテンプレートを用意しました。これを用いてリソースを作成します。
以下、arm64向けのパラメータ設定例です。
パラメータ項目名 | 値(arm64向け) | コメント |
---|---|---|
スタック名 | publish-python-lambda-layer-tool-build-project-arm64 | |
CodeBuildProjectName | publish-python-lambda-layer-tool-arm64 | |
BuildProjectDescription | (任意) | |
BuildEnvironmentOSContainer | ARM_CONTAINER | |
BuildEnvironmentComputeSpec | BUILD_GENERAL1_SMALL | |
BuildEnvironmentImage | aws/codebuild/amazonlinux2-aarch64-standard:3.0 | こちらからaarch64のものを選んで設定します。 |
SourceLocation | publish-lambda-layer-tool-pcjkn63zhk/python/ | 「(2)レイヤー作成ツールソースコード格納用S3バケット作成」の格納パスを指定します。s3:// は取り除きます。 |
RepositoryName | publish-python-lambda-layer-tool-arm64 |
もちろんx86_64向けも用意できます。以下、パラメータ設定例です。
パラメータ項目名 | 値(x86_64向け) | コメント |
---|---|---|
スタック名 | publish-python-lambda-layer-tool-build-project-x86-64 | |
CodeBuildProjectName | publish-python-lambda-layer-tool-x86-64 | |
BuildProjectDescription | (任意) | |
BuildEnvironmentOSContainer | LINUX_CONTAINER | |
BuildEnvironmentComputeSpec | BUILD_GENERAL1_SMALL | |
BuildEnvironmentImage | aws/codebuild/amazonlinux2-x86_64-standard:5.0 | こちらからx86_64のものを選んで設定します。 |
SourceLocation | publish-lambda-layer-tool-pcjkn63zhk/python/ | 「(2)レイヤー作成ツールソースコード格納用S3バケット作成」の格納パスを指定します。s3:// は取り除きます。 |
RepositoryName | publish-python-lambda-layer-tool-x86-64 |
(5)レイヤー作成ツールdockerイメージ作成
#作成したCodeBuildプロジェクトにてビルドを実行します。
dockerイメージを作成し、ECRリポジトリにpushする処理を書いたbuildspec、およびbuildspec内で参照する環境変数はCloudFormationでプロジェクトを作成した際に既に用意されています。
実行時に設定する環境変数を設定するだけでビルドができます。
version: 0.2
phases:
pre_build:
commands:
- |
export AWS_ECR_REGISTRY_URL=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.$AWS_URL_SUFFIX
export DOCKER_IMAGE_REPO_NAME_AND_TAG=$IMAGE_REPO_NAME:$IMAGE_TAG
echo "AWS_ECR_REGISTRY_URL="$AWS_ECR_REGISTRY_URL
echo "DOCKER_IMAGE_REPO_NAME_AND_TAG="$DOCKER_IMAGE_REPO_NAME_AND_TAG
- echo "----- login to Amazon ECR Repository -----"
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ECR_REGISTRY_URL
- |
if [ -n "$DOCKER_USER" ] && [ -n "$DOCKER_TOKEN" ]; then
echo "----- login to docker hub -----"
echo $DOCKER_TOKEN | docker login -u $DOCKER_USER --password-stdin
fi
build:
commands:
- echo "----- build docker image -----"
- echo Build started on `date`
- docker build -t $DOCKER_IMAGE_REPO_NAME_AND_TAG $DOCKER_BUILD_OPTIONS .
- echo Build completed on `date`
post_build:
commands:
- echo "----- add docker image tag -----"
- docker tag $DOCKER_IMAGE_REPO_NAME_AND_TAG $AWS_ECR_REGISTRY_URL/$DOCKER_IMAGE_REPO_NAME_AND_TAG
- echo "----- push docker image to Amazon ECR Repository -----"
- docker push $AWS_ECR_REGISTRY_URL/$DOCKER_IMAGE_REPO_NAME_AND_TAG
環境変数設定
#CodeBuildプロジェクトの「編集」->「環境」->「追加設定」->「環境変数」にて設定します。
設定が終わったら「プロジェクトを更新する」を押下します。
以下、arm64向けのパラメータ設定例です。
環境変数名 | 値(arm64向け) | コメント |
---|---|---|
IMAGE_TAG | latest | CodeBuildで作成したdockerイメージに付与するタグです。DOCKER_BUILD_OPTIONS の--build-arg BASE_IMAGE_TAG に設定するものと同じものを設定して識別できるようにするのもありです。 |
DOCKER_BUILD_OPTIONS | --build-arg BASE_IMAGE_TAG=3.12.2024.10.15.10 | ベースイメージのタグを指定します。ここから目的のPythonバージョンかつOS/ARCHがarm64のものを探します。 |
以下、x86_64向けのパラメータ設定例です。
環境変数名 | 値(x86_64向け) | コメント |
---|---|---|
IMAGE_TAG | latest | CodeBuildで作成したdockerイメージに付与するタグです。DOCKER_BUILD_OPTIONS の--build-arg BASE_IMAGE_TAG に設定するものと同じものを設定して識別できるようにするのもありです。 |
DOCKER_BUILD_OPTIONS | --build-arg BASE_IMAGE_TAG=3.12.2024.10.16.13 | ベースイメージのタグを指定します。ここから目的のPythonバージョンかつOS/ARCHがamd64のものを探します。 |
DOCKER_BUILD_OPTIONS
で--build-arg BASE_IMAGE_TAG
を指定しない場合はlatest
が適用されます。ちなみにlatest
でdocker buildしていると、ある日突然ベースイメージで使われる内部のバージョンが上がってしまい、その結果動作に影響が出てしまって突然動かなくなってしまうというリスクがあります。よって一般的にはバージョンが固定されるタグを明示的に指定することが望ましいです。ちなみにamazon/aws-lambda-pythonでは、latest
の他に3.11
や3.12
などでも内部でバージョンが上がってしまうので注意します。
ビルド実行
#「ビルドを開始」を押下します。
成功したことを確認します。
イメージがECRリポジトリにpushされていることを確認します。
ビルド実行が失敗してしまう時は
#docker buildコマンドを実行している際にベースイメージのプルが「Too Many Requests.(リクエストが多すぎます)」という全く心当たりのない謎のエラーメッセージでビルドが失敗することがあります(原因は後述します)。この場合はビルドを再実行すれば成功する可能性があります。もし再実行しても失敗が続く場合、あるいはビルドを安定して成功させたい場合は、自分の docker hub ユーザを用意して、CodeBuildの環境変数DOCKER_USER
とDOCKER_TOKEN
を設定します。これらの認証情報は環境変数にプレーンテキストで直接設定せずに、パラメータストアまたはシークレットマネージャーに登録して参照することが望ましいです。
パラメータストア設定例
シークレットマネージャー設定例
CodeBuildの環境変数の設定例
- パラメータストアを参照する場合
- 値を「マイパラメータの名前」、タイプを「パラメータ」に設定します。
- 値の設定例:
DOCKER_USER
- 値の設定例:
- 値を「マイパラメータの名前」、タイプを「パラメータ」に設定します。
- シークレットマネージャーを参照する場合
- 値を「シークレットの名前:シークレットキー」、タイプを「Secrets Manager」に設定します。
- 値の設定例:
MyDockerHubAccount:DOCKER_TOKEN
- 値の設定例:
- 値を「シークレットの名前:シークレットキー」、タイプを「Secrets Manager」に設定します。
docker buildコマンドを実行している際にベースイメージのプルが「Too Many Requests.(リクエストが多すぎます)」という全く心当たりのない謎のエラーメッセージでビルドが失敗してしまう原因ですが、現在のAWSリージョンにいる全てのCodeBuildユーザが、そのリージョンのCodeBuildのグローバルIPアドレスを共有しており、おそらくそのうちの多くのユーザが匿名ユーザとして docker hub にアクセスしていることが想定されるため、割り当てられたCodeBuildのグローバルIPアドレスの運が悪いとAnonymous users(匿名ユーザ)の流量制限「100 pulls per 6 hours per IP address(1IPアドレスあたり6時間あたり100プル)」に引っかかってしまうからです。そこで、環境変数「DOCKER_USER」と「DOCKER_TOKEN」を設定して docker hub へログインするようにします。そうするとAuthenticated users(認証ユーザ)としての流量制限「200 pulls per 6 hour period(1ユーザあたり6時間あたり200プル)」が適用されるため、そのユーザで過剰にイメージのプルを行っていなければ成功します。
ちなみに、こちらからAWS IPアドレスの範囲のjsonをダウンロードして確認してみると、本稿執筆時点では東京リージョンのCodeBuildのIPアドレスは 8 + 8 = 16個 確保されているようです。つまり、CodeBuildにて匿名ユーザでdocker buildする都度、最大で16個のIPアドレスの中からビルド成否の運試しをすることになりますね。
{
"ip_prefix": "13.112.191.184/29",
"region": "ap-northeast-1",
"service": "CODEBUILD",
"network_border_group": "ap-northeast-1"
},
{
"ip_prefix": "35.75.131.80/29",
"region": "ap-northeast-1",
"service": "CODEBUILD",
"network_border_group": "ap-northeast-1"
},
(6)AWS Batch環境作成
#AWS Batch環境を作成するCloudFormationテンプレートを用意しました。これを用いてリソースを作成します。
以下、arm64向けのパラメータ設定例です。
パラメータ項目名 | 値(arm64向け) | コメント |
---|---|---|
スタック名 | publish-python-lambda-layer-tool-aws-batch-arm64 | |
prefix | publish-python-lambda-layer-tool-arm64 | |
AwsBatchVpcId | 指定したAwsBatchSubnetIdsが属するVPC | |
AwsBatchSubnetIds | IPv4が利用できるサブネット | インターネット接続可能な状態にしておきます。 |
ComputeResourcesType | FARGATE | 現状AWS Batchではarm64でFargate Spotは使えません。 |
AssignPublicIp | (ネットワーク次第) | AwsBatchSubnetIdsでパブリックサブネットを選択した場合はENABLED |
CpuArchitecture | ARM64 | |
AwsBatchVCPU | (任意) | |
AwsBatchMemory | (任意) | |
AllowActions | s3:GetObject,s3:ListBucket,s3:PutObject,lambda:PublishLayerVersion | レイヤー作成ツールで必要な権限です。 |
EcrRepositoryName | publish-python-lambda-layer-tool-arm64 | pushしたECRリポジトリ |
DockerImageTag | latest | pushしたECRリポジトリのイメージタグ |
Fargate Spotはタスクが中断されるリスクは伴うものの、Fargateよりも70%オフで利用できます。レイヤー作成ツールは仮にタスクが中断されたらまた実行すればよいだけであまりデメリットにはならないので積極的に利用したいです。ECSではarm64でFargate Spotが使えるにもかかわらず、残念なことに本稿執筆時点でAWS Batchではarm64でFargate Spotが使えないです。実際にCloudFormationでarm64でFargate Spotを指定してみたところ、コンピューティング環境等のリソースは作成できますが、ジョブを実行してもステータスがRunnableのままいつまで経っても変化せず、実行を止められてしまっている感じでした。AWS Batch内部でECS Fargateを使っていそうなのに解せないですね。ちなみにx86_64では使えます。是非ともarm64でも使えるようにしてほしいですね。
以下、x86_64向けのパラメータ設定例です。
パラメータ項目名 | 値(x86_64向け) | コメント |
---|---|---|
スタック名 | publish-python-lambda-layer-tool-aws-batch-x86-64 | |
prefix | publish-python-lambda-layer-tool-x86-64 | |
AwsBatchVpcId | 指定したAwsBatchSubnetIdsが属するVPC | |
AwsBatchSubnetIds | IPv4が利用できるサブネット | インターネット接続可能な状態にしておきます。 |
ComputeResourcesType | FARGATE_SPOT | x86_64ではFargate Spotが利用できます。 |
AssignPublicIp | (ネットワーク次第) | AwsBatchSubnetIdsでパブリックサブネットを選択した場合はENABLED |
CpuArchitecture | X86_64 | |
AwsBatchVCPU | (任意) | |
AwsBatchMemory | (任意) | |
AllowActions | s3:GetObject,s3:ListBucket,s3:PutObject,lambda:PublishLayerVersion | レイヤー作成ツールで必要な権限です。 |
EcrRepositoryName | publish-python-lambda-layer-tool-x86-64 | pushしたECRリポジトリ |
DockerImageTag | latest | pushしたECRリポジトリのイメージタグ |
(7)レイヤー作成実施
#作成したAWS Batch環境にてジョブを作成してLambdaレイヤーを作成します。
AWS Batchの「ジョブ」にて「新しいジョブを送信」ボタンを押下します。
全般設定
#以下を選択します。
- ジョブ定義
- CloudFormationのパラメータ「prefix」値-job-definition
- ジョブキュー
- CloudFormationのパラメータ「prefix」値-job-queue
コンテナの上書き コマンド - オプション
#以下はarm64向けの必要最低限のパラメータ設定例です。
DockerfileのCMD [ "" ]
を上書きしてレイヤー作成シェルのオプションを設定します。
[ "-p s3://publish-lambda-layer-tool-pcjkn63zhk/python/requirements.txt", "-n http_request_lib_test_python_3_12_arm64", "-s lambda-layer-pcjkn63zhk" ]
レイヤー作成シェルのオプション
オプション | 必須or任意 | 説明 |
---|---|---|
-p | 「-r」と「-p」のどちらかが必須 | requirements.txtのパスを指定します。S3 URLもしくはローカルファイルパスを指定します。 |
-r | 「-r」と「-p」のどちらかが必須 | requirements.txtの内容を指定します。requirements.txtの中身の改行を「|」で置換したものを指定します。 |
-n | 必須 | レイヤー名を指定します。 |
-s | (レイヤーをS3にアップロードする前提なので)必須 | レイヤー格納S3バケット名を指定します。「(3)Lambdaレイヤー格納用S3バケットの作成」で作成したバケット名を指定します。シェルとしてはこのオプションは必須ではないですが、AWS Batchで動かす場合は作成したレイヤーzipファイルを取得する術がないのでS3アップロードは実質上必須です。 |
-k | 任意 | レイヤー格納S3キー(デフォルトは「python」)を変更できます。 |
-l | 任意 | レイヤーのライセンス情報を指定します。 |
例として、s3://publish-lambda-layer-tool-pcjkn63zhk/python/
にrequirements.txt
を用意しました。
その内容は以下の通りです。
requests == 2.32.3
httpx == 0.27.2
「-p」オプションを使わずrequirements.txt
ファイルを用意せずに「-r」オプションを使うこともできます。
[ "-r requests == 2.32.3|httpx == 0.27.2", "-n http_request_lib_test_python_3_12_arm64", "-s lambda-layer-pcjkn63zhk" ]
以下はx86_64向けの必要最低限のパラメータ設定例です。
[ "-p s3://publish-lambda-layer-tool-pcjkn63zhk/python/requirements.txt", "-n http_request_lib_test_python_3_12_x86_64", "-s lambda-layer-pcjkn63zhk" ]
ジョブの送信
#ステータスがSucceededになれば成功です。
S3にレイヤーのzipファイルが格納されます。
レイヤーのzipファイルのメタデータにはレイヤーの各種情報が設定されます。
Lambdaレイヤーにも登録されています。
(8)実際にレイヤーを利用してみる
#関数作成
#目的のランタイムとアーキテクチャを指定して関数を作成します。
レイヤー追加
#関数にレイヤーを追加します。
一般設定 - タイムアウト時間
#Lambdaはタイムアウト時間がデフォルトで3秒なので、念のためこれを1分ぐらいに変更しておきます。
ソースコード
#レイヤーで取り込んだモジュール(requests, httpx)を利用してみます。
ついでにplatform.python_version()
で、実際に動作しているPythonのバージョンを取得してみます。
import platform
import httpx
import requests
def lambda_handler(event, context):
python_version = platform.python_version()
print('[lambda python runtime version] ' + python_version)
url = 'https://aws.amazon.com/'
httpx_response = httpx.get(url)
print('[httpx response]')
print(httpx_response)
requests_response = requests.get(url)
print('[requests response]')
print(requests_response)
return python_version
実行結果
#HTTPリクエストが通っており、動作しているPythonバージョンが返されて成功しているのでレイヤーが利用できています。
レイヤー作成のベースイメージ(3.12.7)がリリースされて間もなかったので、実際のLambda(3.12.5)がまだ追い付いていなかったようです。もしPythonのバージョンが違っている状態でうまく動かなかったときは、Pythonバージョンが一致するようにベースイメージを選定し直してレイヤーを作り直してみるとよいかもしれません。
最後に
#今回はPythonで実現しましたが、レイヤー作成ツールの中身(Dockerfileとシェルのみ)を差し替えれば他のLambda対応言語もこの方式で簡単にレイヤー作成できるのではないかと思います。
そして、イメージ作成環境のCodeBuildおよびコンテナ実行環境のAWS BatchのCloudFormationテンプレートは、レイヤー作成ツールには特化せず汎用的に利用できるように作ったので、これを用いて自由な言語で自由にツールやアプリケーションを用意できると思います。