Windows　PythonのライブラリをLambdaで使おうとしたときにハマったこと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111652/9501c880-81c0-407d-a889-097be1159537.png)


## LambdaでPythonライブラリを使うには
PythonのプログラムをLambdaに移行する機会があったのですが、その際に色々と手こずったので、誰かの助けに慣れればと思い記事を書きます。

Lambdaは、AWSが提供するサーバーレスコンピューティングサービスで、SESなどのサービスと掛け合わせたりととても便利なサービスです。

Pythonはとても強力なライブラリがたくさんありますが、Lambdaは通常のPythonプログラムのように`pip install ライブラリ名`でNumpyやPandasなどのライブラリを入れることができません。

レイヤーという機能で標準ライブラリ以外のライブラリを使用することができます。

---

### レイヤーの特徴
- ライブラリと関数を分離することができ、他の関数にも使用できる
- 関数のデプロイパッケージのサイズを小さくできる
- S3のファイル、zipファイル、ARNから作成することができる
- zipファイルのサイズは50MBを超えてはいけない
- 最大５つのレイヤーをLambda関数につけることができる
- その合計は展開後のサイズで250MB以下にしないといけない
- バージョン管理できるので、問題があればすぐに戻すことができる

便利な機能ではありますが、少しクセがあります。

---

### Lambdaでライブラリを使う方法３選
他にもライブラリを入れる方法はあるかと思いますが、３つの方法をご紹介します。

:::note info
1. ローカルでインストールしてからzipファイルに圧縮する
1. Klayersのレイヤーを利用する
1. DockerイメージをECRにプッシュしてアタッチ
:::

他にAWSが用意してくれているレイヤーを使うことも可能です。(Pandasもあるので、これだけで事足りることもありそうです）しかし、試していないので今回は除きます。
気になる方はこちらが参考になると思います。
https://dev.classmethod.jp/articles/check-lambda-python-runtime-packages/

それでは順番にご紹介していきます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111652/0dac0bc1-aa15-4f7f-913e-17d0cdd65fee.png)


### ローカルでインストール
一番基本的な方法になるかと思います。
しかし、Windowsでやる場合、うまくいかないことが多いため簡単な説明とさせていただきます。（Numpyなどはこの方法では無理でした）


#### 手順
1. Lambdaのランタイムと同じPythonをインストールし、pythonというフォルダに各ライブラリをインストールします。
1. pythonフォルダをzipファイルに加工します。
1. Lambdaのレイヤーの追加にてzipファイルをアップロードします。
1. Lambda関数でそのレイヤーをアタッチしてください。

:::note warn
Lambdaの仕様上、解凍後のフォルダは「python」となるようにする必要があります。
:::

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

このレイヤーはLambda関数とは分離されているため、他の関数にアタッチすることも可能です。

#### Windows環境でのレイヤーの問題点
まずは容量の問題があります。
zipファイルの容量は最大50MBとなっており、容量の大きいPandasなどを使用する場合、かなり厳しいです。削ろうにも多くの場合、Pythonのライブラリはさまざまなライブラリと依存関係にあります。そのため、削減することは困難です。

もう一つはLambdaはLinux環境であり、Windows環境下でインストールしたライブラリではうまく動かない場合があります。

そのため、Windows環境でインストールしたものでも問題なく軽いライブラリを使用するときのみzipファイルでのレイヤーが使えるということになります。

### Klayersというレイヤーを使う
そんな状況を助けてくれるサービスがKlayersです。
Keith's Layers (Klayers)は全てのライブラリがあるわけではありませんが一般的によく使うであろうPythonライブラリのレイヤーを公開しているGitHubリポジトリです。

https://github.com/keithrozario/Klayers

Klayersを利用する場合、50MBの制限を気にする必要はありません。多くのライブラリが利用できるため困ることはないと思います。

　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111652/d8d1bd9d-e900-4f31-8610-c82ea835be33.png)

#### 手順
1. Klayersのリポジトリページにアクセスします。
1. List of ARNsにあるランタイムと同じPythonのリンクをクリック。
1. Lambdaがあるリージョンを探して、htmlをクリックます。
1. ライブラリのリストが表示されるのでARNをコピーします。
1. Lambda関数に移動してレイヤーを追加をクリック。
1. ARNを指定を選択して、コピーしたARNを貼り付けます。
　

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111652/1c5d295b-e9ed-4219-bbc8-e4ef3f4628b2.png)

![image (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111652/8d4ce2c2-feb6-40e3-8a67-442dc15b1a47.png)

![image (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111652/535eecb9-eca0-4639-a41e-a9f140f7decd.png)

#### Klayersを使っておきた問題
Klayersが問題があるというよりも、レイヤーをつかうときに気を付けなければいけないことがあります。

大きな問題がレイヤーにはあります。
それは一つのLambda関数で使用できるレイヤーは展開後のサイズが250MB以内ということ。これはKlayersのARNを使用しても適用されるようです。

Pythonのライブラリを扱ったことがあるかたはお分かりかと思いますが、複雑な計算をするライブラリは結構容量が大きいです。

3,4つと組み合わせるLambda関数を実行する場合その制限に引っ掛かってしまうんですよね。。
Lambda関数をわけることもできますが、それはそれで面倒。。。
　

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111652/80b00104-64a2-47e8-98a6-f825374da001.png)

### DockerイメージでLambda関数をつくる
そこで色々と調べていると、DockerイメージをECRにアップしてそれを使ってLambda関数を作るとほぼ容量制限なく使えることがわかりました。

この方法はレイヤーを利用するのではなく、Dockerfileを作り、通常のPythonファイルのようにライブラリをインストールします。
そのため、AWS CLIやDocker Desktopをインストールしていない場合はインストールしてください。

#### 手順
1. ECR(Elastic Container Registry)にリポジトリを作成する
1. Dockerfileを作る
1. Dockerfileを元にビルドする
1. ECRにログインする
1. Dockerイメージをタグ付けする
1. Dockerイメージをプッシュする
1. Lambda関数をつくる際にそのDockerイメージをアタッチする


まず、Dockerfileですが、こんな感じで必要なライブラリを記述し作成してください。Lambdaで使用できるPythonは下記のリンクから探してみてください。

https://gallery.ecr.aws/lambda/python

```Dockerfile:Dockerfile
FROM public.ecr.aws/lambda/python:3.12

RUN pip install --upgrade pip
RUN pip install numpy
RUN pip install pillow
RUN pip install pandas


COPY lambda_function.py ${LAMBDA_TASK_ROOT}}

CMD ["lambda_function.lambda_handler"]
```
ライブラリのインストールコマンドがわからんって方は下記リンクからどうぞ！

https://pypi.org/

Dockerfileができたら、ECR(Elastic Container Registry)にアクセスしてDockerイメージをプッシュするためのリポジトリを作成してください。(ちなみになぜかECRと検索しても出てきません。）
　

#### ビルドするときの注意ポイント

リポジトリを作ったらあとはビルドしてプッシュしていきます。
便利なことにECRのリポジトリページにプッシュするまでのコマンドが丁寧に書かれています。
　
![ae4417c4e05c69ca4d641e13b78c58c4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111652/a5ec3ffb-1d06-4b10-9a85-76225dda8f8e.png)

基本的にそれに従っていけばいいのですが、一つ気をつけたいポイントがあります。
Dockerfileからイメージをビルドするのですが、その際のコマンドは
```bash:ターミナル
PS C:\Users\Administrator\qiita> docker build --platform linux/amd64 --provenance=false -t ECRリポジトリ名 .
```
としてください。

LambdaはLinux環境のためWindows環境でビルドするとうまくいきませんので、`--platform`オプションをつけます。

`--provenance=false`オプションをつけないとイメージ以外のインデックスファイルが作成されてしまうため、必ずつけてビルドしましょう。（インデックスファイルが作成されると非常にわかりづらくなります。）

Dockerイメージをプッシュしたら、あとはLambda関数を作成する際にそのDockerイメージを使うだけです。これでレイヤーの容量を気にせずLambdaを利用することができます。

## 終わりに
Lambdaの経験がほぼなかったので、色々とつまづきました。
1つのLambda関数自体に複数の処理をさせるのは、良くないのかとは思いますが画像を加工したりと情報の受け渡しをするには一つのLambda関数でやりたいところ。。。

他にSAMを使ってLambda関数を作成する方法もありますが、管理はしやすくなり、いいなとは思いますが結構複雑でなかなか手が出ませんでした。

 コンテナ、ECRを利用してのLambda関数の作成は慣れてしまえば簡単です。
 誰かのお役に立てたら嬉しいです。

  ありがとうございました。

### 参考記事
  https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/chapter-layers.html

  https://qiita.com/__DASHi__/items/b03d3efd401260d8add4
  
  https://zenn.dev/ndjndj/articles/2533d854d86902

  https://zenn.dev/445/articles/29aff4c8ce2e01

  https://reffect.co.jp/aws/lambda_docker