aws sam cli で ローカルの lambda から 別の ローカルの lambda を叩く
おはようございます。watura です。 最近、aws sam cli を使って遊び始めました。使った事はありますか?
aws sam cli というのは AWS SAM を build, test, debug, deploy できる cli ツールです。
このツールの導入とかは公式のドキュメントをみてほしいです。
なお、動かすのには、aws cli と Docker は必須です。
ざっくりとした仕組みですが、Docker を使って Lambda を一瞬起動するみたいなことをしています。
なので、実際の Lambda に近い動きをしてくれるので、ローカルで Lambda の開発できます。
さて、Lambda を使っていると、Lambda から別の Lambda を呼び出したいみたいなことをやりたくなります。
いい感じなサンプルが見つからなかったので作ってみました。
今回は、Golang で作ってみています。
完全に別の Lambda を呼び出すだけのサンプルです。
HelloWorldFunction から、HelloInvokedFunction を呼び出しています。
HelloInvokedFunction
簡単なほうから、説明します。HelloInvokedFunction は受け取った Input に[Invoked] って書いて返すだけの簡単なプログラムです。
package main
import (
"context"
"fmt"
"github.com/aws/aws-lambda-go/lambda"
)
// Response for Lambda
type Response struct {
Message string `json:"body"`
}
// Lambda で実行される関数
// 引数として、context と Response を受け取ります。
func handler(ctx context.Context, input Response) (Response, error) {
// input の message に [Invoked] を追加する
msg := fmt.Sprintf("[Invoked] %v", input.Message)
return Response{msg}, nil
}
func main() {
// Lambda で呼び出された時に実行される handler を登録します。
lambda.Start(handler)
}
HelloWorldFunction
では、HelloWorldFunction をみていきます。
func main() {
l.Start(handler)
}
lambda で呼び出された時に実行されるhandlerを登録します。
// Response for lambda
type Response struct {
Message string `json:"body"`
}
// こちらは、contextだけ受け取るようにしています。
// 使っていないので、あれですが。
func handler(ctx context.Context) (Response, error) {
// Local な場合はlocal用のconfigを使う
var lmd *lambda.Lambda
// SAMで実行すると、環境変数に AWS_SAM_LOCAL というのが追加されます。
// これが true だったら、ローカルで実行しているということがわかります。
if os.Getenv("AWS_SAM_LOCAL") == "true" {
// ここが重要なところです。
lmd = lambda.New(session.New(localConfig()))
} else {
lmd = lambda.New(session.New())
}
j, err := json.Marshal(Response{"Hello World"})
if err != nil {
return Response{}, err
}
// 別のlambda を呼び出す時に使う設定です。
// まだ、実際にdeployしたらどうなるかとか試していないです。
input := &lambda.InvokeInput{
// 呼び出したい関数名を指定します。
FunctionName: aws.String("HelloInvokedFunction"),
// 呼び出されるlambdaに渡すpayloadです。
Payload: j,
// デフォルトがRequestResponseなので、指定不要です
// 実際には &lambda.InvokeInput{FunctionName: aws.String("HelloInvokedFunction")} だけで十分なはずです。
InvocationType: aws.String("RequestResponse"),
}
// 別のlambdaを上で作った設定で呼び出します。
resp, err := lmd.Invoke(input)
if err != nil {
return Response{}, err
}
var r Response
// HelloInvokeのresponseのpayloadをUnmarshalして、使えるようにします。
err = json.Unmarshal(resp.Payload, &r)
if err != nil {
return Response{}, err
}
return Response{r.Message}, nil
}
func localConfig() *aws.Config {
c := aws.NewConfig()
// ここ重要
c.Endpoint = aws.String("host.docker.internal:3001")
// ここも重要
c.DisableSSL = aws.Bool(true)
return c
}
Lambda は docker で実行されます。なので、endpoint として、 localhost とか 127.0.0.1 を指定しても動きません。
Docker の Client 自身が呼び出されてしまいます。なので、 host.docker.internal を呼び出す必要があります。
また、ローカルで動かすときは、sslを使っていないので、オフにします。
動かす
sample プロジェクトでは、
make start
make run
で、試せるようになっています。
run した結果は、out.txt に書き込まれるので、
{"body":"[Invoked] Hello World"}
と表示されていたら、成功です。
この時実行しているコマンドは、
build:
GOOS=linux GOARCH=amd64 go build -o hello-world/hello-world ./hello-world
GOOS=linux GOARCH=amd64 go build -o hello-invoked/hello-invoked ./hello-invoked
start:
sam local start-lambda
run: build
aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "http://127.0.0.1:3001" --no-verify-ssl out.txt
hello-world と hello-invoked をビルドしたり、aws lambda invoke を呼び出すようにしています。
以上で、ざっくりですが aws sam cli で Lambda から Lambda を呼び出す手順です。
noteでコード書いた時にハイライトさせるのどうやるんだろう。