AWS SAMで複数lambdaを作成する
やりたいこと
AWS SAMで複数のlambdaをコンテナイメージから作成&管理したい。
また、親labmdaから子lambdaをinvokeしたい。
動機
処理の都合上、lambdaが複数必要だった。 こういう場合、STEP FUNCTIONSでやるべきでは?とは思っているが、 とりあえずLAMBDAでやってみる。
ディレクトリ構成
各lambdaのdockerfileやapp.pyを各ディレクトリで管理しているだけ。
. ├── README.md ├── __init__.py ├── events │ └── event.json ├── hello_world │ ├── Dockerfile │ ├── __init__.py │ ├── app.py │ └── requirements.txt ├── hello_world_child │ ├── Dockerfile │ ├── __init__.py │ ├── app.py │ └── requirements.txt ├── local-enviroment.json ├── samconfig.toml ├── template.yaml └── tests ├── __init__.py └── unit ├── __init__.py └── test_handler.py
template.yaml
HelloWorldFunction側でHelloWorldFunctionChildのArnと名前を取得するようにしている。
また、childをinvokeするroleも設定している。
各lambdaでどのdockerfileを参照するかは、dockercontextで簡単に指定可能。
AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: > Sample SAM Template for multiple lambda Globals: Function: Timeout: 3 Environment: Variables: SAMPLACE: "AWS" Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: PackageType: Image Role: !GetAtt InvokeLambdaIamRole.Arn Environment: Variables: CHILDLAMBDAARN: !GetAtt HelloWorldFunctionChild.Arn CHILDLAMBDANAME: !Ref HelloWorldFunctionChild Metadata: Dockerfile: Dockerfile DockerContext: ./hello_world DockerTag: python3.8-v1 HelloWorldFunctionChild: Type: AWS::Serverless::Function Properties: PackageType: Image FunctionName: "HelloWorldFunctionChild" Metadata: Dockerfile: Dockerfile DockerContext: ./hello_world_child DockerTag: python3.6-v1 InvokeLambdaIamRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: "sts:AssumeRole" Policies: - PolicyName: "invoke_lambda" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: "lambda:InvokeFunction" Resource: !GetAtt HelloWorldFunctionChild.Arn Outputs: HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionChild: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunctionChild.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt InvokeLambdaIamRole.Arn HelloWorldFunctionChildIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionChildRole.Arn
local-enviroment.json
これは、sam local invoke --env-vars local-enviroment.json
として与える設定ファイル。
これを元にlambda呼び出しのlocal invoke
を実行したかったが、よくわからなかった。
CHILDLAMBDANAMEもそのために環境変数として設定下が、結局使っていない。
mockでやるしかないかな。
{ "Parameters": { "SAMPLACE": "LOCAL" } }
lambda
dockerfileはほとんどsam init
そのままなので割愛。
一応、pythonのversionをかえてみたりしているが、問題はない。
hello_world
app.py
import json import os import boto3 place = os.environ["SAMPLACE"] child_lambda_arn = os.environ['CHILDLAMBDAARN'] child_lambda_name = os.environ['CHILDLAMBDANAME'] print('place is:', place) print('child lambda arn is:', child_lambda_arn) print('child lambda name is:', child_lambda_name) if place == "AWS": lambda_client = boto3.client('lambda') else: # mock client for local test lambda_client = boto3.client('lambda') def lambda_handler(event, context): input_event = { "param1": 1, "param2": 2, "param3": 3 } Payload = json.dumps(input_event) res = lambda_client.invoke( FunctionName=child_lambda_arn, InvocationType='RequestResponse', Payload=Payload ) print("---02: response:", res) body = json.loads(res['Payload'].read()) print("---03: body:", body) return { "statusCode": 200, "body": json.dumps( { "message": "hello world", } ), }
hello_world_child
app.py
import json def lambda_handler(event, context): return { "statusCode": 200, "body": json.dumps( { "message": "hello world from child", } ), }
build
sam build
local invoke
sam local invoke HelloWorldFunction
sam local invoke HelloWorldFunctionChild
が、親の方はlocalでlambda実行できない問題のためエラーが出る。
deploy
sam deploy
最初だけは
sam deploy --guided
この時、ECRのリポジトリはちゃんと個別に入力しないといけない。親切。
できなかったこと
親lambdaのlocal invoke
ができない。
mockじゃなくて直接invokeしたいけど、正直よくわからない。
参考
AWS LambdaからLambdaを非同期で呼び出す(Python) - Qiita
【AWS SAM 入門⑥】IAM ロールの作成と Lambda Function への割り当て - log4ketancho
AWS SAMでローカル環境でS3とDynamoDBを扱うLambdaを実行する - Qiita
python - How to invoke AWS lambda from another lambda within SAM local? - Stack Overflow