AWS Lambda Layersの作り方

Yuya Sugano
12 min readNov 28, 2020

--

AWS Lambda Layersは2018年に発表された機能です。Lambda関数間で共通したライブラリやコンポーネントをZipファイルにまとめ他のLambdaから呼び出して使うことができるようになります。特にこれまで1つのLambda関数ではデプロイメントパッケージのサイズに上限があり、巨大なサイズのライブラリをLambdaへ持ち込むことが出来ませんでした。Lambda Layersによって必要なライブラリを細切れにしてLambda関数で使用することができます。この記事はAWS Lambda Layersに関する個人的な備忘録とPandasのライブラリを載せたレイヤーの作成方法を書いています。ちなみにデフォルトではNumpy/Scipyがパッケージされているレイヤーのみ提供されています。[1]

Lambda Layers Quota
  • 共通のロジックを切り出して別管理できる、オーバーヘッドの縮小
  • 各Lambda関数のコードが小さくなる、デプロイメントが早くなる

次に注意点です。ZIP化されたレイヤーの場合は最大50Mまで許容されるのでランタイムも含めたLambda関数のトータルサイズは250Mまでとなります。またレイヤーの順序も重要であると記載されています。理由はレイヤーはランタイム実行環境の同じパスに上書きされるからです。最初のレイヤーがランタイム環境であるとすると、次のレイヤーに存在する同じファイル名のファイルやライブラリは最初のレイヤーのファイルを上書いてしまいます。

  • ランタイムも含め最大で5つまでのレイヤーを構成できる
  • 各レイヤーもデプロイメントパッケージのサイズ制限を受ける
  • ランタイムに合わせてレイヤーを作成する必要がある

レイヤーはランタイム実行環境の /opt 以下に配置されます。pythonを使用する場合はpythonのランタイム実行環境に合わせて /opt/python のディレクトリ構成でレイヤーをアップロードする必要があります。次にレイヤーの利用方法ですが2通りです。

  1. 公開されているレイヤーを読み込む
  2. レイヤーを自作する

公開されているレイヤーを読み込む

作り方と題しておきながらまずは作らない方法のご紹介です 笑。一般に存在するレイヤーを使用することができます。公開されているレイヤーにはAWS公式のものと市井の人が公開しているものがありますが、前述のとおりpythonのランタイムのAWS公式レイヤーは1つしかありません。Lambdaにないライブラリをデプロイメントパッケージに含めたくない、サイズ的にデプロイメントパッケージに入らないという場合にはこの方法が最も簡単に目的を実現できるでしょう。

※scipy-1.5.1, numpy-1.19.0のレイヤー1つしかないと思ってましたが少し増えていました

次に市井の人のレイヤーを使用する方法です。pythonランタイム限定となってしまいますが様々なライブラリをデプロイしたレイヤーを公開している奇特な方がいます。先に注意点ですがこのKlayersのレイヤーのデプロイメント自体が自動化されており、Layer Expiryによって削除される可能性があります。AWSに公式にサポートされているものではないため使用は自己責任になります(というかAWSが公式に主要なライブラリのレイヤーは提供してもよいのでは?という疑問)[3]

使い方は非常に簡単です。提供されるarnをLambda関数のレイヤーとして指定する、S3からダウンロードしてくる、SAM(Serverless Application Model)で使用するなど、自作のものを使う場合と違いはありません。この記事執筆時点で81個のライブラリがレイヤーとして提供されています。このcsvファイルにライブラリの一覧が載っています。[4]

arnの見つけ方ですがこちらもcsvファイルで提供されています。csvファイルは各リージョンやランタイムバージョン(ここではpython3.7とpython3.8系)にファイルが分かれておりgithub上で簡単に見つけられます。以下はpython3.8ランタイムのap-northeast-1(東京リージョン)のarnのcsvファイルです。[5]

Klayers python3.8 ap-northeast-1

レイヤーを自作する

レイヤーの使用目的がライブラリの追加ではなく特定の処理の共有化であったり、パブリックなレイヤーを使用したくない場合にはレイヤーを自作するしかありません。またKlayersはpythonランタイムのみで3.7と3.8のレイヤーしかないのでpython以外のランタイムを使用する場合は自作一択となるでしょう。混同しがちですがレイヤーは単一のLambda関数の処理単位における層(レイヤー)の追加であり処理を分割する用途で使用してはいけません。順列のある処理を分割したりフローが必要な場合にはAWS Step Functionsが適切なサービスとなります。

レイヤーの自作はただパッケージをまとめたZIPファイルを作るだけで、とても簡単なはずなのですが個人的にはまってしまいました。レイヤーのデプロイメントパッケージを作るにはまずランタイムの実行環境について理解しておく必要があります。ランタイムのOS基盤ですが全ての言語のランタイムにおいてAmazon LinuxかAmazon Linux 2のいずれかが使用されています。確実に動作するレイヤーを作成するには使用する言語とそのランタイムからイメージを特定し、対象のAmazon Linuxイメージでデプロイメントパッケージを作る、が正解となります。[6]

AWS Lambda ランタイム

今回はpython 3.7でPandasのレイヤーを作ってみたいと思うのでPythonランタイムの情報を確認します。OSはAmazon Linuxとあるので上記のAWS Lambda ランタイムのテーブルから使用されているAMIはamzn-ami-hvm-2018.03.0.20181129-x86_64-gp2と分かります。このイメージのサーバを立ちあげます。python 3.8などAmazon Linux 2についてはイメージがカスタムとなっており詳細わかりませんが普通にインスタンスのAMIの選択でAmazon Linux 2を選べば間違いないでしょう。

あとはそこでパッケージ作成しる!ってかんじなのですがサーバたててpython環境用意してとかは正直しんどいと思いました。時間泥棒です。そこでDockerを使います。Lambda実行環境を再現するDockerイメージがあるのでそのコンテナを立ち上げ、そのコンテナ内でデプロイメントパッケージを作成します。作成したパッケージをローカルでZIP圧縮してアップロードするだけです。簡単ですね。以下よりこのDockerを使用したレイヤーのデプロイメントパッケージの作成方法を記載していきます。[7]

docker-lambda

まずはコンテナ内でインストールするパッケージを requirements.txt に書きましょう。今回必要なライブラリはPandasですがAWSのscipy/numpyライブラリ以外に依存のある pytz も含めます。Pandasのバージョンは1.1.2とします。最終的にAWSのレイヤーと作成するPandasのレイヤーを追加することでLambda関数内でPandasを呼び出せるようにします。

次にpythonのパッケージをインストールしてLambda実行環境に合わせたデプロイメントパッケージを作成します。 /opt 配下にレイヤーが展開されますが、pythonランタイムの場合は /opt/python というパスにする必要があります。ランタイムによって異なるため事前に確認が必要です。[8]

lambci/lambda:build-python3.7 のコンテナイメージを使ってビルドします。Lambda関数のコードは /var/task にレイヤーのコードは /opt にマウントすることでコンテナ内でLambda関数を実行することが可能です。今回はコンテナを立ち上げて pip コマンドでPandasをインストールするだけです。

docker run --rm \
-v <code_dir>:/var/task:ro,delegated \
[-v <layer_dir>:/opt:ro,delegated] \
lambci/lambda:<runtime> \
[<handler>] [<event>]

python というディレクトリを作成してその中に requirements.txt で指定したライブラリをインストールするシェルスクリプトを書きました。シェルスクリプトに実行権限を付けて実行します。その後に python ディレクトリを含める形でZIP化します。このZIPファイルをデプロイメントパッケージとしてレイヤー登録します。

$ chmod +x package-layer.sh
$ ./package-layer.sh
Installing collected packages: pandas, pytz
Successfully installed pandas-1.1.2 pytz-2020.1

$ zip -r my-Python37-Pandas112.zip .

端末上から aws cli でレイヤーを登録しました。同じ名前でレイヤーを登録すると昇順でバージョン数が増えていきます。バージョン番号はarnの末尾にも反映されていきます。SAM(Serverless Application Model)のテンプレートへ書くときにはバージョン番号も含め間違いがないことを確認します。

$ aws lambda publish-layer-version --layer-name my-Python37-Pandas112 --zip-file fileb://my-Python37-Pandas112.zip --compatible-runtimes python3.7
Layers

作成したレイヤーを使って以下のコードが問題なく動作することが確認できました。

まとめ

  • AWS Lambda LayersはLambda関数のコード共通化やライブラリによるLambda関数のオーバーヘッド縮小を実現できる
  • LayersにはLambdaと共通のパッケージサイズの制限やLambdaと合わせたデプロイメントパッケージサイズの制限などがある
  • AWSが公式に提供するレイヤーのほかKlayersなどインターネット上に公開されているレイヤーが存在する
  • レイヤーを作成するには実際のランタイム環境に使用されているOS環境で行う他にLambdaの環境を再現するDockerイメージを使用して必要なコードをパッケージ化する方法がある

--

--

Yuya Sugano

Cloud Architect and Blockchain Enthusiast, techflare.blog, Vinyl DJ, Backpacker. ブロックチェーン・クラウド(AWS/Azure)関連の記事をパブリッシュ。バックパッカーとしてユーラシア大陸を陸路横断するなど旅が趣味。