背景・目的
AWSのLambdaをPythonで利用するとき、外部ライブラリをパッケージにまとめてデプロイするのが一般的かと思います。
その場合、パッケージのバージョンは固定されることになるのですが、あるとき、実行時にS3に配置したPythonファイルを実行時に読み込むというケースがあったので、その実現方法について備忘します。
システム構成
例
S3にアップロードするファイル
下記の内容をs3://some-bucket-name/uploaded_script.py
というパスにアップロードすると仮定します。インポートの挙動を確認するために、少し冗長ですが、標準ライブラリであるjsonをインポートしています。
import json
def hello():
print(json.dumps({"hello": "world"}))
Lambdaのスクリプト
import_from_s3という関数でS3をインポートする例は下記のようなスクリプトになります。
import json # Lambdaのスクリプトで使っていなくても、S3側のファイルで必要なのでインポートが必要
import boto3
def split_s3_path(s3_path):
"""
s3://bucket_name/some/path
を
bucket_name, some/path
に分割する
"""
parts = s3_path.split("/")
assert len(parts) >= 4, "S3のパスのパーツがあっていません"
bucket = parts[2]
key = "/".join(parts[3:])
return bucket, key
def get_python_script(s3_client, s3_path):
bucket, key = split_s3_path(s3_path)
return s3_client.get_object(Bucket=bucket, Key=key)["Body"].read().decode("utf-8")
def import_from_s3(s3_client, s3_path, module_name):
"""
S3上にあるpythonファイルからインポートする
"""
exec(get_python_script(s3_client, s3_path))
return locals()[module_name]
def handler(event, context):
s3_client = boto3.client('s3')
hello_func = import_from_s3(s3_client, "s3://some-bucket-name/uploaded_script.py", "hello")
hello_func()
これを実行すると、S3側のファイルの関数を実行することができます。
まとめ
今回は、結構レアなケースかと思うのですが、S3上のPythonファイルをインポートできる方法について書きました。
実際に利用される際には、Lambdaのセキュリティ面で穴を一つ増やしてしまうことになるので、ご注意ください。