注目イベント!
アドベントカレンダー2024開催します(12/1~12/25)!
一年を締めくくる特別なイベント、アドベントカレンダーを今年も開催します!
初心者からベテランまで楽しめる内容で、毎日新しい技術トピックをお届けします。
詳細はこちらから!
event banner

CodeBuild + ECR + AWS BatchでAWS Lambda Pythonレイヤー作成

| 18 min read
Author: yuji-kurabayashi yuji-kurabayashiの画像

背景

#

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レイヤーを作成および登録する手順は以下の通りです。

  1. Pythonライブラリインストールコマンドを実行します
  2. レイヤー(zipファイル)を作成します
  3. レイヤー(zipファイル)をS3にアップロードします
    • AWS CLIだとs3 cp
    • AWSマネジメントコンソール操作ではレイヤー作成時に直接レイヤーのzipファイルをアップロードできますが、10MBを超える場合はS3に置いてアップロードする必要があります
  4. Lambdaレイヤーを登録します

レイヤー作成シェルではこれらを一気通貫で実施します。なお、Python自作モジュールも併せて含めたLambdaレイヤーの作成には対応していません。

作成したLambdaレイヤーアップロード先のS3バケット名を指定しない場合はレイヤー作成までを行います。実行している環境からはS3に接続できないことが予めわかっている、といった場合でもレイヤー作成までは利用できるようにするためです。レイヤー(zipファイル)さえ作成できてファイルが手元にあれば、あとは手作業でなんとか対応できますよね。

また、普通にPythonが利用できる環境であれば、レイヤー作成シェルのみを直接利用してレイヤーを作成できます。

レイヤー作成シェルの使い方の詳細は以下のようなコマンドで確認できます。

./PublishPythonLambdaLayer.sh -h

Dockerfile

#
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 [ "" ]
  1. ベースイメージ
    • amazon/aws-lambda-pythonを利用します。AWS Lambda Pythonの実行環境そのものなのでレイヤーを作成するには最適な環境です。
  2. ベースイメージタグ
    • docker build時にベースイメージのタグを--build-arg BASE_IMAGE_TAG=<tag>で指定できます。利用したいCPUアーキテクチャやPythonバージョンに見合った環境を柔軟に選択できます。例えば3.113.12を指定できます。しかし、Amazon Linux 2ベースのPython3.11ではyum、Amazon Linux 2023ベースのPython3.12ではdnfしか使えず、互換性がありませんでした。そこで、dnfコマンドが通るかどうかをチェックして、dnfとyumの使い分けをするようにして対応しました。
  3. インストールなどの初期化処理
    • ヒアドキュメントで書いています。コマンドを頑張って&& \で数珠繋ぎしなくて済むので複雑な処理が書きやすくなり、その結果dockerイメージのレイヤ数も減らしやすくなるのでイメージのサイズを小さくできます。
  4. その他
    • AWS CLIのファイル解凍やインストールのログが大量に出て煩わしく感じたのでカットしています。
    • レイヤー作成シェルのオプションは実行時にCMDで上書きできるようにしてあります。

レイヤー作成ツールインフラ構成図

#

ビルド環境

#
  1. S3にソース(レイヤー作成ツール)を置いて
  2. CodeBuildでdockerイメージを作成し
  3. ECRにpushします

ビルド環境のインフラ構成図

実行環境

#
  1. AWS BatchでECRからdockerイメージをpullして
  2. AWS Batchでコンテナを実行してレイヤーを作成し
  3. S3にアップロードして
  4. Lambdaにレイヤーを登録します

実行環境のインフラ構成図

レイヤー作成ツール環境構築および実行方法

#

AWS公式ではLambdaをはじめとするコンピューティングリソースのCPUアーキテクチャにarm64を利用することを強く推しているので、環境作成用のCloudFormationテンプレートのデフォルト値はarm64向けにしてあります。

AWS公式ではコンピューティングリソースは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バケットおよびフォルダを用意して、レイヤー作成ツールソースコード(DockerfilePublishPythonLambdaLayer.sh)を同一階層に格納します。後で利用するrequirements.txtはついでに同じ場所に置いただけですので、他のバケットに置いても構いません。
例として、s3://publish-lambda-layer-tool-pcjkn63zhk/python/に用意しました。
なお、S3バケット作成時の設定「パブリックアクセスをすべて ブロック」はチェックを付けておくことが望ましいです。

レイヤー作成ツールソースコード格納用S3バケット

(3)Lambdaレイヤー格納用S3バケットの作成

#

作成したLambdaレイヤーをアップロードするS3バケットを用意します。
例として、s3://lambda-layer-pcjkn63zhk/を用意しました。
なお、S3バケット作成時の設定「パブリックアクセスをすべて ブロック」はチェックを付けておくことが望ましいです。

Lambdaレイヤー格納用S3バケット

(4)CodeBuildプロジェクトおよびECRリポジトリ作成

#

CodeBuildプロジェクトおよびECRリポジトリを作成するCloudFormationテンプレートを用意しました。これを用いてリソースを作成します。

cfn_codebuildパラメータ設定例

以下、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でプロジェクトを作成した際に既に用意されています。
実行時に設定する環境変数を設定するだけでビルドができます。

buildspec.yml
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プロジェクトの「編集」->「環境」->「追加設定」->「環境変数」にて設定します。
設定が終わったら「プロジェクトを更新する」を押下します。

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.113.12などでも内部でバージョンが上がってしまうので注意します。

ビルド実行

#

「ビルドを開始」を押下します。

CodeBuildプロジェクト環境変数

成功したことを確認します。

CodeBuildビルド成功

イメージがECRリポジトリにpushされていることを確認します。

ECRリポジトリ

ビルド実行が失敗してしまう時は

#

docker buildコマンドを実行している際にベースイメージのプルが「Too Many Requests.(リクエストが多すぎます)」という全く心当たりのない謎のエラーメッセージでビルドが失敗することがあります(原因は後述します)。この場合はビルドを再実行すれば成功する可能性があります。もし再実行しても失敗が続く場合、あるいはビルドを安定して成功させたい場合は、自分の docker hub ユーザを用意して、CodeBuildの環境変数DOCKER_USERDOCKER_TOKENを設定します。これらの認証情報は環境変数にプレーンテキストで直接設定せずに、パラメータストアまたはシークレットマネージャーに登録して参照することが望ましいです。

パラメータストア設定例

パラメータストア設定例

シークレットマネージャー設定例

シークレットマネージャー設定例

CodeBuildの環境変数の設定例

  • パラメータストアを参照する場合
    • 値を「マイパラメータの名前」、タイプを「パラメータ」に設定します。
      • 値の設定例:DOCKER_USER
  • シークレットマネージャーを参照する場合
    • 値を「シークレットの名前:シークレットキー」、タイプを「Secrets Manager」に設定します。
      • 値の設定例:MyDockerHubAccount:DOCKER_TOKEN
DockerHubアカウント環境変数の設定例
CodeBuildでdocker buildが失敗する原因について

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テンプレートを用意しました。これを用いてリソースを作成します。

cfn_aws_batchパラメータ設定例

以下、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リポジトリのイメージタグ
AWS Batchではarm64でFargate Spotはサポートしていません

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ファイルが格納されます。

S3レイヤーzip

レイヤーのzipファイルのメタデータにはレイヤーの各種情報が設定されます。

S3レイヤーzipメタデータ

Lambdaレイヤーにも登録されています。

Lambdaレイヤー
Lambdaレイヤー詳細

(8)実際にレイヤーを利用してみる

#

関数作成

#

目的のランタイムとアーキテクチャを指定して関数を作成します。

関数作成

レイヤー追加

#

関数にレイヤーを追加します。

レイヤー追加

一般設定 - タイムアウト時間

#

Lambdaはタイムアウト時間がデフォルトで3秒なので、念のためこれを1分ぐらいに変更しておきます。

ソースコード

#

レイヤーで取り込んだモジュール(requests, httpx)を利用してみます。
ついでにplatform.python_version()で、実際に動作しているPythonのバージョンを取得してみます。

lambda_function.py
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バージョンが返されて成功しているのでレイヤーが利用できています。

Lambda実行結果

レイヤー作成のベースイメージ(3.12.7)がリリースされて間もなかったので、実際のLambda(3.12.5)がまだ追い付いていなかったようです。もしPythonのバージョンが違っている状態でうまく動かなかったときは、Pythonバージョンが一致するようにベースイメージを選定し直してレイヤーを作り直してみるとよいかもしれません。

最後に

#

今回はPythonで実現しましたが、レイヤー作成ツールの中身(Dockerfileとシェルのみ)を差し替えれば他のLambda対応言語もこの方式で簡単にレイヤー作成できるのではないかと思います。
そして、イメージ作成環境のCodeBuildおよびコンテナ実行環境のAWS BatchのCloudFormationテンプレートは、レイヤー作成ツールには特化せず汎用的に利用できるように作ったので、これを用いて自由な言語で自由にツールやアプリケーションを用意できると思います。

豆蔵では共に高め合う仲間を募集しています!

recruit

具体的な採用情報はこちらからご覧いただけます。