背景
LambdaとAPI Gatewayをセットで使う場合、両サービスはそれぞれに状態を持っている(LambdaはVersionとAlias、API GatewayはDeployment Stage)為、それらの関連性を管理する必要があります。
具体的には、API Gatewayのdevステージでは、Lambda functionのdevエイリアスを使うなど、自分たちである程度ルールを作り運用することができれば、開発が捗りそうです
そんな時は、API Gatewayの${stageVariables}
を使って、両者の関係を紐付けることができます。
やってみる
Lambda
まずはサンプルのLambdaを作ります。このLambdaはバージョン管理し、それぞれにdev
とprod
というエイリアスを付けてあります。
バージョン管理されたLambdaでは、$LATEST
のlambda functionしか修正できません。そのため、古いバージョンをprod
に、$LATESTをdev
にしてあります。
functionの中身は、以下のようにシンプルなものです。
-
dev
エイリアス : {Message
:Hello World!
} を出力する -
prod
エイリアス : contextオブジェクトを出力する
これで、同名のLambdaを別エイリアスで呼び出す準備ができました。
API Gateway
次に、API Gatewayを作ります。
Resource
ResourceにGETを追加し、Integration type
にLambda Functionを選択します。Lambda Function
の名前にstageVariablesを使うのが今回のポイントです。
具体的には、<Lambda Function>:${stageVariables.alias}
を設定しています。
権限設定
前述のResource作成時に、Lambda Function
名を決定すると、以下のようなモダルが表示されたと思います。これは、API Gatewayがlambdaを実行する為の許可設定をawscli経由で行うことを教えてくれています。
このコマンドはそのまま実行すれば良いのではなく、自分で${stageVariables.alias}
を置き換えて実行する必要があります。(そのまま実行するとbad substitutionのエラーが返ってきます)
今回は、エイリアスにdevとprodを用意したので、--function-name
オプションに arn:aws:lambda:ap-northeast-1:*****:function:myLambda:dev
もしくは、 arn:aws:lambda:ap-northeast-1:*****:function:myLambda:prod
に変えて実行した感じです。
$ aws lambda add-permission --function-name arn:aws:lambda:ap-northeast-1:*****:function:myLambda:dev --source-arn arn:aws:execute-api:ap-northeast-1:*****:hykf0+++++/*/GET/ --principal apigateway.amazonaws.com --statement-id 481173e7-a50b-4f48-a527-2137ddf13fe4 --action lambda:InvokeFunction
{
"Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:ap-northeast-1:*****:hykf0+++++/*/GET/\"}},\"Action\":[\"lambda:InvokeFunction\"],\"Resource\":\"arn:aws:lambda:ap-northeast-1:*****:function:myLambda:dev\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Sid\":\"481173e7-a50b-4f48-a527-2137ddf13fe4\"}"
}
$ aws lambda add-permission --function-name arn:aws:lambda:ap-northeast-1:******:function:myLambda:prod --source-arn arn:aws:execute-api:ap-northeast-1:******:hykf+++++/*/GET/ --principal apigateway.amazonaws.com --statement-id 481173e7-a50b-4f48-a527-2137ddf13fe4 --action lambda:InvokeFunction
{
"Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:ap-northeast-1:******:hykf+++++/*/GET/\"}},\"Action\":[\"lambda:InvokeFunction\"],\"Resource\":\"arn:aws:lambda:ap-northeast-1:******:function:myLambda:prod\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Sid\":\"481173e7-a50b-4f48-a527-2137ddf13fe4\"}"
}
これで、lambdaを呼び出す権限設定ができました。
stageVariables
最後に、stageVariablesを設定します。API Gatewayの各Stageで設定できます。
Resourcesの"Deploy API"ボタンから、devとprodのステージを作成します。
dev、prodそれぞれのステージで、"Stage Variables"カラム を開き、stageVariablesを設定します。Nameがaliasで、Valueは各環境に合わせます。
これで一通り完成です。
確認する
ResourcesのMethod Test画面を開くと、Stage Variablesを入力する欄が出てきます。そこに、devやprodなど入れてテストしてみましょう。
ちゃんとlambdaのエイリアスに紐付いて実行されています。
各ステージごとのAPIを叩いても、同様の結果が返ってきました。
大丈夫そうですね
$ curl -s https://hykf0*****.execute-api.ap-northeast-1.amazonaws.com/dev/ | jq
{
"Message": "Hello World!"
}
$ curl -s https://hykf*****.execute-api.ap-northeast-1.amazonaws.com/prod/ | jq
{
"awsRequestId": "f9ecaed0-ca15-11e5-86c6-41208cf01644",
"invokeid": "f9ecaed0-ca15-11e5-86c6-41208cf01644",
"logGroupName": "/aws/lambda/myLambda",
"logStreamName": "2016/02/03/[4]092d13ef1c93490b832d36f3a6fa3eec",
"functionName": "myLambda",
"memoryLimitInMB": "128",
"functionVersion": "4",
"invokedFunctionArn": "arn:aws:lambda:ap-northeast-1:*****:function:myLambda:prod"
}
まとめ
API GatewayのstageVariablesを使って、LambdaのAliasと連携させる話でした。
stageVariablesを使うと、ステージごとにURIを変更したり様々な要件に対応できそうです。積極的に使っていきたいところですね。
[参考]
https://aws.amazon.com/jp/about-aws/whats-new/2015/11/amazon-api-gateway-supports-stage-variables/
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/amazon-api-gateway-using-stage-variables.html
https://aws.amazon.com/jp/blogs/compute/using-api-gateway-stage-variables-to-manage-lambda-functions/