Lambda (Python) をローカル環境で実行できる python-lambda-local を試した - kakakakakku blog

kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Lambda (Python) をローカル環境で実行できる python-lambda-local を試した

Lambda (Python) のローカル環境を整えるため,python-lambda-local を試した.python-lambda-local を使うと,Python コードを Lambda にデプロイすることなく動作確認ができるようになる.Apex を使っていれば apex invoke でお手軽に実行することもできるけど,やはり Lambda に依存せず,単独で実行したいという要件はある.Lambda のローカル環境は誰に聞いても困っている印象がある.

github.com

前提

インストールは pip を実行するだけで良い.また,今回紹介するディレクトリ構成は Apex で Lambda をデプロイする前提にしている.

$ pip install python-lambda-local

BluePrint : hello-world-python

まずは AWS に依存せず,Python ライブラリにも依存せず,単体で実行できるコードとして,BluePrint の hello-world-python を試した.ディレクトリ構成は以下のようになっている.

.
├── event.json
├── functions
│   └── myfunc
│       └── main.py
└── project.json

myfunc/main.py は以下のようなコードにした.シンプルにイベントを受けて,表示するだけの実装にしている.

import json

print('Loading function')

def lambda_handler(event, context):
    print("function = myfunc, value1 = " + event['key1'])
    print("function = myfunc, value2 = " + event['key2'])
    print("function = myfunc, value3 = " + event['key3'])

ここで python-lambda-local で実行すると以下のようになる.オプションとしては --function でハンドラを指定して,-t でタイムアウトを指定する.あとは Python コードとイベントを指定する.

$ python-lambda-local --function lambda_handler --timeout 5 functions/myfunc/main.py event.json
Loading function
[root - INFO - 2017-07-30 16:16:36,272] Event: {u'key3': u'value3', u'key2': u'value2', u'key1': u'value1'}
[root - INFO - 2017-07-30 16:16:36,273] START RequestId: 9e683e91-821f-4680-b8e2-bcf37c7eb44f
function = myfunc, value1 = value1
function = myfunc, value2 = value2
function = myfunc, value3 = value3
[root - INFO - 2017-07-30 16:16:36,273] END RequestId: 9e683e91-821f-4680-b8e2-bcf37c7eb44f
[root - INFO - 2017-07-30 16:16:36,274] RESULT:
None
[root - INFO - 2017-07-30 16:16:36,274] REPORT RequestId: 9e683e91-821f-4680-b8e2-bcf37c7eb44f    Duration: 0.38 ms

簡単に動いた!

BluePrint : s3-get-object-python

次は AWS に依存していて,Python ライブラリにも依存するコードとして,BluePrint の s3-get-object-python を試した.ディレクトリ構成は以下のようになっている.

.
├── event.json
├── functions
│   └── myfunc
│       ├── main.py
│       ├── requirements.txt
│       └── (ライブラリいろいろ)
└── project.json

myfunc/main.py は以下のようなコードにした.S3 Put のイベントを受けて,Put されたファイルの Content-Type を表示している.なお,S3 Put のイベントは量が多いため,割愛するが,公式ドキュメントにちゃんと載っている.

docs.aws.amazon.com

from __future__ import print_function

import json
import urllib
import boto3

print('Loading function')

s3 = boto3.client('s3')

def lambda_handler(event, context):

    # Get the object from the event and show its content type
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key'].encode('utf8'))
    try:
        response = s3.get_object(Bucket=bucket, Key=key)
        print("CONTENT TYPE: " + response['ContentType'])
        return response['ContentType']
    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e

ここで python-lambda-local で実行すると以下のようになる.

$ python-lambda-local --function lambda_handler --library functions/myfunc --timeout 5 functions/myfunc/main.py event.json

[root - INFO - 2017-07-30 23:14:18,203] START RequestId: 07669e19-37af-4640-ae65-859dadd758ed
[botocore.vendored.requests.packages.urllib3.connectionpool - INFO - 2017-07-30 23:14:18,214] Starting new HTTPS connection (1): s3-ap-northeast-1.amazonaws.com
CONTENT TYPE: text/plain
[root - INFO - 2017-07-30 23:14:18,721] END RequestId: 07669e19-37af-4640-ae65-859dadd758ed
[root - INFO - 2017-07-30 23:14:18,722] RESULT:
text/plain
[root - INFO - 2017-07-30 23:14:18,722] REPORT RequestId: 07669e19-37af-4640-ae65-859dadd758ed    Duration: 517.71 ms

問題なく動いた!

気を付けるポイント

python-lambda-local を使ってみて,数点気を付けるポイントがあった.

1. /lib ではなくルートディレクトリにライブラリをインストールする

公式ドキュメントにも書いてある通り,pip で Python ライブラリをインストールする場合,Lambda の場合はルートディレクトリに配置する必要がある.よって,python-lambda-local のドキュメントにあるような /lib ディレクトリを用意するのではなく,main.py と同じルートディレクトリにそのままインストールする必要がある.具体的には以下のようなコマンドになる.

$ pip install --requirement functions/myfunc/requirements.txt --target functions/myfunc

docs.aws.amazon.com

2. requirements.txtboto3 を明示する必要がある

次も公式ドキュメントに書いてある内容だが,Lambda にはデフォルトで Boto 3 がインストールされているため,わざわざ requirements.txt に書く必要がないようになっている.ただし,ローカル環境で実行する場合には必要なので,結果的に書く必要があった.今回は以下のファイルを用意した.

urllib
boto3

まとめ

  • Lambda (Python) のローカル環境を整えるために python-lambda-local を試してみた
  • 簡単に使えたし AWS サービスとの接続もできたため一般的なユースケースは網羅できそう
  • ライブラリのインストールディレクトリなど少し気を付けるポイントはある

関連記事

Apex を使って複数環境にデプロイする方法は前にまとめてある.Apex ユーザーには参考になる内容だと思う.

kakakakakku.hatenablog.com