【VueSlsApp】LambdaでPYTHONPATHを指定して外部ライブラリをシンプルに使う
こんにちは。てぃろです。
今回は、LambdaでPythonライブラリを使うときのちょっとしたテクニックを紹介したいと思います。これをVueSlsAppに組み込みました。見た目などは何も変わらないですが、ソースがシンプルになるのでオススメです。
VueSlsAppのことをご存じない方は、以下の紹介記事とマガジンからどうぞ。
デプロイしてあるものは、以下から実際に触ってみてもらえます。
https://vueslsapp.thiroyoshi.com/
VusSlsAppのリポジトリは以下です。
LambdaでPythonライブラリを使う場合、ライブラリもまとめて上げる問題…よりも深刻なパス通らない問題
LambdaでPythonを使うときに誰もが直面する問題が、ライブラリをまとめて上げましょうって話なんですが、今はツールがいろいろあって比較的簡単に上げられます。
VueSlsAppでも使っているServerless Frameworkもディレクトリ内にあるものを自動でまとめて上げてくれるので、なにも困りません。
一番困るのは、実行時にパスが通ってなくてライブラリが見つけられず実行できないことです。これはServerless Frameworkを使っているからと言ってもどうにもなりません…。
当然ですがPythonの実行環境が入っているLambdaは、何も設定していなければ、こちらが勝手に追加したライブラリのパスなんかしったこっちゃないわけですね。
だったら、パスを通せばいいのです。
PTHONPATHにパスを追加すれば、Pythonが参照できるようになる
PythonにはPYTHONPATHというソースを探索するためのパスを設定する環境変数が存在します。公式の解説は以下をご覧下さい。
以下の記事には、LambdaでのPYTHONPATHの通し方やそこに至るまでの調査内容はすべて書いてあります。勉強になります。
重要なポイントは以下です。
・/var/runtime も指定しておくこと
Lambda上では、デフォルトでPythonのruntimeもPYTHONPATHで指定しているようです。つまり、自分でPYTHONPATHをすべて上書きしてしまうとそもそもPythonが実行できなくなります。
VueSlsAppでは、pylibsというディレクトリにライブラリを集めていますので、具体的には以下のように設定しました。
・serverless.yml(一部抜粋)
PYTHONPATH: /var/runtime:/var/task/pylibs
結果的に、外部ライブラリの参照は以下のように修正されます。
・functions/repository/messages_repository.py(修正前)
import json
import random
import hashlib
from decimal import Decimal
from functions.common import initializer
initializer.add_path()
from pylibs import boto3
from pylibs.boto3.dynamodb.conditions import Key
from functions.common.decimal_encoder import DecimalEncoder
・functions/repository/messages_repository.py(修正後)
import json
import random
import hashlib
from decimal import Decimal
from pylibs import boto3
from pylibs.boto3.dynamodb.conditions import Key
from functions.common.decimal_encoder import DecimalEncoder
修正したこととしては、initializer.add_path()という外部ライブラリのパスを動的に追加していたコードが不要になったということです。
かっこ悪いしパフォーマンスも落ちるので、このやり方をどうやってやめようかと思ってました…。やっとやめられてうれしかったです!(歓喜
環境依存なライブラリがあったら、この方法はよくないかも
上記の方法は、ライブラリそのものが実行環境に合わせてビルドしなおす必要がある場合には向きません。
今回の方法はあくまで、pip installをしたOS上で動作するライブラリを使う場合です。Windowsでpip installすればWindows上で動作するライブラリをまとめて上げることになります。
つまり、環境依存が激しく、Lambda上で実行する場合(=Amazon Linux上で実行する場合)に合わせてライブラリのビルド環境を変える必要がある場合には、この方法は向きません。
そういった場合は、以下の方法があるかと思います。(試してないですが)
・PYTHONPATHを使うが、CI/CD環境をAmazon Linuxに変える
pip installをするときの環境を変えてやればいい。つまり、CI/CD環境を実行するOSをAmazon Linuxにしてやりましょう。
ただし、CI/CDのツールやサービスによっては、OSを自由に変更できない場合もあるので、ご自身の環境でAmazon Linuxのイメージが使えるのかは慎重に確かめる必要があるのではないかと思います。
・serverless-python-requirementsを使う
Serverless Frameworkのプラグインで、Pythonのライブラリをいい感じにまとめ上げてくれるプラグインがあります。
このプラグインでは、Dockerを使って実行環境と同じ環境を活用したビルドをする、ということもやってくれます。
では、なぜ最初からこのプラグインを使わないのか?
理由は簡単で、PYTHONPATHの指定だけで事足りるからです。
私が作っているAPでは、簡単なことしかLambdaでは実行しません。つまり、ビルド環境に依存するような重厚なライブラリを使う機会などほぼないのです。しかも、プラグインを使うと、そのインストールやDockerコンテナの実行など私の開発においては不要な処理が多く、パイプラインの実行時間が増えてしまう恐れもあるのです。
最後に
今回は、LambdaでPythonのパスを通す方法をいくつか紹介しました。
結局いろんな方法がありますが、自分にとって一番コスパの高い方法を選ぶのがよいですね。便利なツールがあると言っても、盲目的にそれを信じて使うのもよくないです。
自分にとって何が必要なのか?何が不要なのか?開発の効率を下げる要因にならないか?そんな視点も持って、ツールや開発方法は見極めていきたいですね。
いつも記事を読んでいただいてありがとうございます。少しでもあなたの人生にプラスになる話ができているとうれしいです。