AWS Lambdaで外部ライブラリをimportするのに詰まったお話と解決策
みなさん、こんにちは せしょうです!
今回は、AWS Lambda(ラムダ)を使って遊んでみたら、色々と落とし穴があったというお話です。
事の発端は、私がAWS Lambdaを使って遊ぶ際にLayerなるものを使いたくなったことが始まりです。
LayerをAWS Lambdaの関数に追加することが出来るらしい。
⇨ ライブラリをLayerに入れれば、使いまわせて便利!!
と思ったわけで、とりあえずLayerを追加したんですが、
- そんなライブラリ、パッケージは存在しないよ!!
- OSが違うから使えないよ !
AWS Lambdaとは?
AWS Lambdaは、サーバーレスのサービスです。中でもAWS Lambdaは GCPのCloud Functionsと同様に常にインスタンスが立ち上がっているわけではなく、何かしら実行するためのトリガーが起動したときにのみ、動くため コスト的にも優しいものとなっています。
しかし実行時間 などに制限があるため、簡単なツールなどに向いています。
例) Amazon S3(Amazon Simple Storage Service)に画像をアップロードした際に、その画像のサイズをリサイズする
目標
AWS lambdaでOS依存のパッケージをLayerにアップロードしライブラリを使えるようにするための環境を作成し、AWS Lambdaのレイヤーにアップロードする。
パッケージの中には(Pillow、 MeCab等)、OS依存のパッケージがある.
それらを,AWS LambdaのLayerにアップロードして、AWS Lambdaの関数でライブラリをimportすることを目標とする.
目次
- ディレクトリ構造
- Dockerfile, docker-compose.ymlの中身
- requirement.txtにインストールしたいライブラリ名を記述する
- コンテナを立ち上げて実行する
- AWS Lambdaのレイヤーにzip化したファイルをアップロードする
- AWS Lambdaの関数を作成
- AWS Lambdaの関数で追加したレイヤーのライブラリをimportする方法
- まとめ
ディレクトリ構造
python-package-aws-lambda ├── Dockerfile ├── layers │ └─- file.zip ⇦ コンテナを立ち上げることで作成される(今回の目的) │ └── requirements.txt └── docker-compose.yml |
dockerfile、docker-compose.ymlの中身
今回はコンテナを立ち上げることによって、必要なライブラリのインストールとそのインストールしたライブラリを zipファイルに圧縮するような動きをしています。
ポイントとしては、2点あります。
-
requirements.txtに指定したライブラリは、pythonディレクトリ配下にインストールされる
-
Dockerfileの元のイメージが amazonlinux:2であるということ
requirements.txtに指定したライブラリは、pythonディレクトリ配下にインストールされる
AWS Lambdaで、ライブラリをimport するとき、 /python配下にライブラリがないとパスが通っておらず、importできないと言われるため それも対応できるようにしました。
(毎回、関数側で パスを通すという作業するのも面倒くさいので)
※公式ドキュメント:Lambdaレイヤーの作成と共有(ライブラリの依存関係をレイヤーに含める)を参照
Dockerfileの元のイメージが amazonlinux:2であるということ
ライブラリの中には、OSに依存したものがある。
そのため、AWS Lambdaの関数内と同じ環境で、ライブラリをインストールする必要がある。
AWS Lambdaの関数で使用されているOSは amazonlinux2と同様の環境であるため、Dockerfileでは
FROM amazonlinux:latest
をしています。
※公式ドキュメント:Lambdaランタイムを参照
Dockerfile
FROM amazonlinux:latest
RUN yum install python3.8 -y zip
RUN mkdir /home/layers
RUN mkdir /home/python
|
docker-compose.yml
version: '3'
services:
aws-lambda-layers:
build: .
volumes:
- './layers:/home/layers'
working_dir: '/home/'
command: sh -c "python3 -m pip install -r layers/requirements.txt -t python/ && zip -r layers/file.zip python/"
|
requirement.txtにインストールしたいライブラリ名を記述する
例1) 自然言語処理をしたい人の例
boto3==version
mecab-python3==version
ipadic==version
|
例2) 画像処理をしたい人の例
boto3==version
Pillow==version
|
※ ==version : 使いたいライブラリのバージョンを指定
コンテナを立ち上げて実行する
$ docker-compose up --build |
⇨ zipファイルが作成される
zipファイルの中身。 python配下に作成されている。
※公式ドキュメント:Lambdaレイヤーの作成と共有(ライブラリの依存関係をレイヤーに含める)を参照
python/boto3/dynamodb/__init__.py
python/boto3/s3/
python/boto3/s3/inject.py
python/boto3/s3/__pycache__/
python/boto3/s3/__pycache__/__init__.cpython-37.pyc
python/boto3/s3/__pycache__/transfer.cpython-37.pyc
python/boto3/s3/__pycache__/inject.cpython-37.pyc
|
目標のディレクトリ構造になっている
python-package-aws-lambda ├── Dockerfile ├── layers │ └─- file.zip ⇦ コンテナを立ち上げることで作成される(今回の目的) │ └── requirements.txt └── docker-compose.yml |
AWS Lambdaのレイヤーにzip化したファイルをアップロードする
1. AWS Lambdaを開く
2. 下記のイメージのように「レイヤー」を選択する
3. 下記の画像のように、「レイヤーの作成」を選択する
4. 下記のオプションを参考にレイヤーを作成する
・名前(必須)
・説明-オプション(任意)
・zip ファイルをアップロード
アップロード(5.で作成したzipファイルを選択する.)
・ランタイム
以下のURLを参考にして,使用するランタイムを設定する.
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html
ここでは,python3.8をランタイムにする.
|
AWS Lambdaの関数を作成
1. 下記の画像のように、「関数の作成」を選択する
2. 下記のオプションを参考に関数を作成する
・名前(必須)
・説明-オプション(任意)
・zip ファイルをアップロード
アップロード(5.で作成したzipファイルを選択する.)
・ランタイム(必須)
以下のURLを参考にして,使用するランタイムを設定する.
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html
ここでは,python3.8をランタイムにする.
|
3. 作成すると、以下の画像のように作成した関数が開く
4. 上記のサイトを下にスクロールしていくと、レイヤーの追加が出来るカラムが出てくる
5. 下記のオプションを参考にレイヤーを追加する
・レイヤーソース:カスタムレイヤー
・カスタムレイヤー: 先ほど作成したレイヤーを選択する
ここでは、function-package を選択
・バージョン : 1 (レイヤーを初めて作成した場合は、バージョン1のみ存在する)
|
AWS Lambdaの関数で追加したレイヤーのライブラリをimportする方法
通常の使い方と同じ
例1) Mecabを使用するとき
import MeCab |
例2) PILを使用するとき
from PIL import Image |
まとめ
本日は、AWS Lambdaに触って遊んでみたら、色々と詰まってしまった部分があったので、その解消方法について書かせていただきました。
- /python ディレクトリ配下でないといけない
- ライブラリがOSに依存する
など詰まる部分がいくつもあったので、ただ遊ぶだけでも仕様を理解する必要があるんだなと痛感しました。 この記事が誰かの学びの一助になると嬉しいです。
ここまで読んでいただき、ありがとうございます!
また、次回の記事でお会いしましょう。