【AWS】Lambda ~ Python / 外部モジュール追加 ~

■ はじめに

https://dk521123.hatenablog.com/entry/2024/05/23/162229

の続き。

Upload機能を実装しようと思ったが、ファイル指定する場合は
以下※1で、標準ライブラリではなく、
Requestsライブラリを考えてみては?的なことが
書かれていたのだが、Lambdaだとデフォルトだと入っていない。

そこで、AWS Lambdaにおいて、Python の外部モジュールを
追加する方法について、調べてみた

※1
https://stackoverflow.com/questions/27050399/make-an-http-post-request-to-upload-a-file-using-python-urllib-urllib2

Personally I think you should consider the requests library to post files.

url = 'http://jigsaw.w3.org/css-validator/validator'
files = {'file': open('style.css')}
response = requests.post(url, files=files)

目次

【1】AWS Lambda に外部モジュールを追加するには
【2】Lambda レイヤー
 1)Lambda レイヤーの使用制限
【3】組み込み手順例
 0)開発環境
 1)Lambda レイヤーファイルの作成
 2)Lambda レイアー作成
 3)Lambda 関数にLambda レイアーを適用
【4】Lambda レイヤーあれこれ
 1)Lambda レイヤーを更新したい場合
【5】トラブルシュート
 1)実行したら「[ERROR] No module named '<lib_name>'」が表示される

【1】AWS Lambda に外部モジュールを追加するには

外部モジュールを レイヤーファイル (zip) として固めて
Lambdaにアップロードする

【2】Lambda レイヤー

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/chapter-layers.html

より抜粋 (一部、簡略化)
~~~~~~~~
Lambda レイヤーは、補助的なコードやデータを含む .zip ファイルアーカイブです。

レイヤーの使用を検討する理由は複数あります。

[1] デプロイパッケージのサイズを小さくするため。
[2] コア関数ロジックを依存関係から分離するため。
[3] 複数の関数間で依存関係を共有するため。
[4] Lambda コンソールのコードエディターを使用するため。
~~~~~~~~

1)Lambda レイヤーの使用制限

[1] 圧縮後のサイズは50MBまでにすること
[2] レイヤー数は5つまでにすること

【3】組み込み手順例

0)開発環境

* OS : Linux環境(WSL2など含む)
* Python: Lambdaと同じバージョンのPython(なければ、pyenv などで設定)

仮想環境 ~ pyenv ~
https://dk521123.hatenablog.com/entry/2022/02/13/000000
仮想環境 ~ virtualenv / venv / pipenv ~
https://dk521123.hatenablog.com/entry/2020/02/11/141852

1)Lambda レイヤーファイルの作成

# ★重要★ この「python」は変えない方がいい
#  => 詳細は「【5】トラブルシュート」の「1)」を参照
mkdir python/ 
cd python

# requests をpythonフォルダ直下にインストール
pip install requests -t ./

cd python
cd ..

# ZIPに固める
zip -r RequestsLayer.zip python/

2)Lambda レイアー作成

 AWS Lambda レイアーを作成し、
「1)Lambda レイヤーファイルの作成」したものを追加する

前準備

* S3バケットに、作成したLambda レイヤーファイルを置いておく
 => AWS Management コンソール上から直接上げることもできるけど、
  ファイルサイズが大きい(10MB以上)場合、この方法がよさげ

手順
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/creating-deleting-layers.html#layers-create

[0] AWS Management コンソールにログインし、Lambda ページを開く
[1] Lambda コンソールの左ペインにある [Layers (レイヤー)] を選択
[2] [Create layer] (レイヤーの作成) を選択
[3] [ レイヤー設定 ] の [ 名前 ] に、レイヤーの名前を入力
 => 今回は「demo-layer」とする
[4] (オプション) [Description] (説明) で、レイヤーの説明を入力
 => 今回は「For Demo」とする
[5] レイヤーコードをアップロードするには、
 Amazon S3 からファイルをアップロードするには、
 [Upload a file from Amazon S3] (Amazon S3 からファイルをアップロードする) を選択
 その後、[Amazon S3 link URL] (Amazon S3 のリンク URL) で、ファイルへのリンクを入力
[6] (オプション) [互換性のあるアーキテクチャ] では、1 つまたは両方の値を選択
 => 今回は、特に選択せず
[7] (オプション) [互換性のあるランタイム] では、お使いのレイヤーと互換性のあるランタイムを選択
 => 今回は、「Python3.12」を選択
[8] (オプション) [License] (ライセンス) で、必要なライセンス情報を入力
 => 今回は、特に選択せず
[9] [作成 (Create)] を選択

3)Lambda 関数にLambda レイアーを適用

「2)Lambda レイアー作成」を対象の3)Lambda 関数にアタッチする

手順例

[0] AWS Management コンソールにログインし、Lambda ページを開く
[1] Lambda コンソールの左ペインにある [Functions] を選択
[2] Lambda関数から対象の関数を選択
[3] Lambda関数アイコンの下にある「Layers (0)」を選択
[4] 「Add a layer」ボタン押下
[5] 「Choose a layer」欄で「Custom layers」を選択し
  「2)Lambda レイアー作成」したレイアー(今回の場合「demo-layer」)
  を選択する
[6] 「Add」ボタン押下

参考文献

https://qiita.com/hirai-11/items/d99cc0097a4ef4f24d73
https://qiita.com/afukuma/items/b7191025700a7829967c
Lambda レイヤー
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/chapter-layers.html

【4】Lambda レイヤーあれこれ

1)Lambda レイヤーを更新したい場合

* Lambda レイヤーファイルを作成し直したら、行うことは2点。
~~~~~
[a] Lambda レイヤーのバージョン新規作成
[b] Lambda 関数のバージョンを上げる
~~~~~

[a] Lambda レイヤーのバージョン新規作成

[0] AWS Management コンソールにログインし、Lambda ページを開く
[1] Lambda コンソールの左ペインにある [Layers (レイヤー)] を選択
[2] 更新したLambda レイヤーを選択
[3] 「Create version」ボタン押下
 => 後は、「2)Lambda レイアー作成」の時と同じ感じでできる
 => 入力したら「Create」ボタン押下

[b] Lambda 関数のバージョンを上げる

[0] AWS Management コンソールにログインし、Lambda ページを開く
[1] Lambda コンソールの左ペインにある [Functions] を選択
[2] Lambda関数から対象の関数を選択
[3] Lambda関数アイコンの下にある「Layers (1)」を選択
[4] Layers 欄の「Edit」ボタン押下
[5] 対象レイアーを選択し、「Layer version」をあげる(e.g. 1 -> 2)
[6] 「Save」ボタン押下

【5】トラブルシュート

1)実行したら「[ERROR] No module named '<lib_name>'」が表示される

実行したら、以下のエラー内容になった

エラー内容

[ERROR] Runtime.ImportModuleError:
Unable to import module 'lambda_function':
No module named '<lib_name>'

※ 今回の場合、<lib_name>は「requests」

原因

* Lambda レイヤーファイルの作成不備

=> 今回の場合「1)Lambda レイヤーファイルの作成」において
~~~
mkdir python-libs/ <= ってして作ってた 
~~~

解決案

ディレクトリを「python-libs」から「python」にリネームして
Lambda レイヤーファイルの作成し直した
~~~
# ★重要★ この「python」は変えない方がいい
mkdir python/ 
~~~

関連記事

Lambda ~ 基礎知識編 ~
https://dk521123.hatenablog.com/entry/2017/04/05/235618
Lambda ~ Python / 入門編 ~
https://dk521123.hatenablog.com/entry/2021/10/07/103317
Lambda ~ Python / S3トリガー ~
https://dk521123.hatenablog.com/entry/2024/05/23/162229
Lambda のトラブルシュート
https://dk521123.hatenablog.com/entry/2017/12/16/231714
Serverless Framework ~ 環境設定編 ~
https://dk521123.hatenablog.com/entry/2023/11/02/000200
Serverless Framework ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/11/03/234825
Serverless Framework ~ offline ~
https://dk521123.hatenablog.com/entry/2023/11/09/004458
Python ~ 基本編 / urllib ~
https://dk521123.hatenablog.com/entry/2022/08/05/000000
Python ~ Requestsライブラリ ~
https://dk521123.hatenablog.com/entry/2024/05/23/162229
Python ~ 基本編 / bool ~
https://dk521123.hatenablog.com/entry/2021/10/02/000000
仮想環境 ~ pyenv ~
https://dk521123.hatenablog.com/entry/2022/02/13/000000
仮想環境 ~ virtualenv / venv / pipenv ~
https://dk521123.hatenablog.com/entry/2020/02/11/141852