これは、なにをしたくて書いたもの?
AWS Lambdaを動かすのに、以前LocalStackを使ってNode.jsで作成した関数を動かしてみました。
LocalStackを使って、AWS Lambdaを試してみる - CLOVER🍀
今回は、ちょっとPythonで作成してみたいと思います。
お題
お題も前のエントリと似たようなもので、ペイロードで与えられたパラメーターを含めて、メッセージを返却する関数を作成します。
pipでインストールするパッケージも利用します。
環境
LocalStackは、Docker Composeで起動。LocalStackは、「192.168.0.3」というホストで動作しているものとします。
docker-compose.yml
version: "3" services: localstack: image: localstack/localstack:0.9.1 ports: - "4567-4593:4567-4593" - "8080:8080" environment: - SERVICES=${SERVICES- } - DEBUG=${DEBUG- } - DATA_DIR=${DATA_DIR- } - PORT_WEB_UI=${PORT_WEB_UI- } - LAMBDA_EXECUTOR=docker-reuse - KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- } - DOCKER_HOST=unix:///var/run/docker.sock volumes: - "/var/run/docker.sock:/var/run/docker.sock"
AWS Lambdaの実行は、「docker-reuse」にしてコンテナを使いまわすようにしています。
- LAMBDA_EXECUTOR=docker-reuse
これを、単に「docker」にするとコンテナが増え続けていきます…。
コードは、以下の環境で作成。
$ python3 -V Python 3.6.7
Lambda関数を作成する
では、Lambda関数を作成しましょう。
AWS Lambdaで利用可能なPythonのバージョン一覧は以下ですが、今回はローカルに合わせてPython 3.6を使うことにしましょう。
Python による Lambda 関数のビルド - AWS Lambda
ライブラリの利用には、仮想環境を使用します。
$ python3 -m venv venv $ . venv/bin/activate
ライブラリには、PyYAMLを使用しました。
$ pip3 install pyyaml
バージョン。
$ pip3 freeze ... PyYAML==5.1
用途に特に意味はないのですが…。
で、こちらのドキュメントを見ながら、関数を作成。
Python の Lambda 関数ハンドラー - AWS Lambda
my-lambda-function.py
import yaml def my_handler(event, context): print('event = {}'.format(event)) print('context = {}'.format(context)) return yaml.dump({ 'word': event['word'] })
これを、zipファイルにパッケージングします。
.zip ファイルアーカイブで Python Lambda 関数をデプロイする - AWS Lambda
今回は、こんなコマンドで作成しました。
$ cd venv/lib/python3.6/site-packages && \ zip -r ../../../../function.zip . && \ cd ../../../../ && \ zip -g function.zip my-lambda-function.py
Lambda関数のデプロイ
では、Lambda関数をデプロイしましょう。
$ aws configure AWS Access Key ID [None]: my-access-key AWS Secret Access Key [None]: my-secret-access-key Default region name [None]: us-east-1 Default output format [None]:
作成したパッケージをデプロイ。作成したLambdaの関数名は、「--handler」オプションで「ファイル名(拡張子なし):関数名」で
登録するようです。
$ aws --endpoint-url http://192.168.0.3:4574 lambda create-function \ --function-name my-lambda \ --runtime python3.6 \ --handler my-lambda-function.my_handler \ --role test-role \ --zip-file fileb://function.zip { "FunctionName": "my-lambda", "FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:my-lambda", "Runtime": "python3.6", "Role": "test-role", "Handler": "my-lambda-function.my_handler", "VpcConfig": { "SubnetIds": [ null ], "SecurityGroupIds": [ null ] }, "Environment": { "Variables": {}, "Error": {} }, "TracingConfig": {} }
LocalStackに登録するので、「--endpoint-url」での指定が必要です。
$ aws --endpoint-url http://192.168.0.3:4574 lambda create-function \
登録した関数の一覧。
$ aws --endpoint-url http://192.168.0.3:4574 lambda list-functions { "Functions": [ { "FunctionName": "my-lambda", "FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:my-lambda", "Runtime": "python3.6", "Handler": "my-lambda-function.my_handler", "CodeSize": 50, "Version": "$LATEST", "Environment": { "Variables": {} } } ] }
Lambdaの呼び出し。結果は、引数で指定したファイルに出力されます。
$ aws --endpoint-url http://192.168.0.3:4574 lambda invoke --function-name my-lambda --payload '{"word": "Hello Lambda"}' result.log { "StatusCode": 200 }
確認。とりあえず改行は気にしない…。
$ cat result.log "word: Hello Lambda\n"
ここで、ちょっと関数の定義を変更してみます。
def my_handler(event, context): print('event = {}'.format(event)) print('context = {}'.format(context)) return yaml.dump({ 'word': event['word'], 'foo': 'bar' })
更新には、「update-function-code」を使用。
$ aws --endpoint-url http://192.168.0.3:4574 lambda update-function-code --function-name my-lambda --zip-file fileb://function.zip { "FunctionName": "my-lambda" }
再度呼び出し。
$ aws --endpoint-url http://192.168.0.3:4574 lambda invoke --function-name my-lambda --payload '{"word": "Hello Lambda"}' result.log { "StatusCode": 200 }
確認。
$ cat result.log "foo: bar\nword: Hello Lambda\n"
ちゃんと、結果が反映されましたね。
最後に、関数を削除しておしまい。
$ aws --endpoint-url http://192.168.0.3:4574 lambda delete-function --function-name my-lambda
確認。
$ aws --endpoint-url http://192.168.0.3:4574 lambda list-functions { "Functions": [] }
ログを確認したい
「docker container logs」で確認したい…ところですが、Lambdaの実行が「docker-reuse」だとログが残らず…。
- LAMBDA_EXECUTOR=docker-reuse
これを「docker」にするとログが残るのですが、代わりにLambdaの実行とともに終了したコンテナが増えていく…。
- LAMBDA_EXECUTOR=docker
うーん…。