API Gateway+LambdaのSlack通知APIをCloudFormationで作る
以前、三編に分けて、SlackへPostするWebAPIを、API Gateway+Lambda+node.jsで作りました。
- AWS API Gateway+LambdaでSlackにメッセージをPOSTする(前編) - 年中アイス
- AWS API Gateway+LambdaでSlackにメッセージをPOSTする(中編) - 年中アイス
- AWS API Gateway+LambdaでSlackにメッセージをPOSTする(後編) - 年中アイス
しかしその後、AWS ConsoleのLambdaのUIが変わったので、一部のキャプチャが参考になりづらくなってしまいました。キャプチャし直すのも手間なので、今度はCloudFormationを使って自動で構築します。
CloudFormationで自動構築する
CloudFormation templateを作ったのであとは実行するだけです。READMEにも書いてますが、以下3段階です。
- SlackのWebhook URLを発行
- CloudFormationを実行
- CloudFormationの結果をもとに、slackへのpostを実行
SlackのWebhook URLを発行
前編を参考に発行します。 公式のWebhookドキュメントも一応添えておきます。
発行できたら、apigateway.jsonの"SLACK_WEBHOOK_URL":"none"
を取得したURLで置き換えます。(none
を置き換えます。)
CloudFormationを実行
awsコマンドを使って、stackを作成します。stackの構築が終わるまで、数分かかります。
aws cloudformation create-stack --stack-name PostSlackCfn --template-body file://apigateway.json --region ap-northeast-1 --capabilities CAPABILITY_IAM
CloudFormationの結果をもとに、slackへのpostを実行
結果を取得します。
aws cloudformation describe-stacks --stack-name PostSlackCfn
この結果のOutputの部分のapi keyとpost urlをコピーしておきます。
API keyは別途取得する必要があり、前述のapi keyを使って取得します
aws apigateway get-api-key --api-key <your api key id> --include-value
--include-value
オプションがないと、API keyは表示されません。
curlで投げて、HiとSlackに届けばOKです。
curl -XPOST <your post url> -H "x-api-key: <your api key>" -H 'Content-Type: application/json' -d '{"message":"Hi"}'
届かない場合は、CloudWatchLogsでLambdaのログを確認したり、後編に書いているように、API Gatewayのテスト実行をやるなどで調べてみてください。
まとめ
API Gatewayは手で設定していくのは面倒なので、CloudFormationの方が向いてますね。今回、CloudFormation初めて扱いましたが、基本的な構成要素を理解するまで、作成、削除を繰り返したので時間がかかりました。
課題としては、WebHookURLみたいなリポジトリに入れたくないような値はどう扱うのがいいのか。また、もっと大きなくくりでは、CloudFormationが失敗した時に、全部消して最初からになったので、実運用で失敗した時に、うまくリカバリできるのかが不安要素。今回はそこまで調べてないです。
主にCloudFormation化について書いたので、元々の構成詳細については、三編それぞれ見てもらえればと思います。
ここからは、つまづいた点などのメモ。
最初参考にした記事
AWS CloudFormation が Amazon API Gateway をサポートしたので使ってみた | Developers.IO
ここを参考にcloudformationでAPI gatewayのサンプルを作成してみました。 APIを定義して、Resource(URL Pathになるところ)を定義して、Methodを定義する形。とりあえずすぐできました。
DeploymentとMethodで起きる順序問題も、ここにあるDependsOnで理解しました。
/に対してMethodを定義したい
参考にしたのは、Resourceを作る前提でしたが、もともと/に直接POSTで動かしていたので、どうやるのかなと。
結果Resource定義なしでMethodのResourceには、{ "Fn::GetAtt": [“PostSlackCfn”, "RootResourceId"] }
を指定すればよかったです。
Lambda関連を追加したら、create stackでエラー
An error occurred (InsufficientCapabilitiesException) when calling the CreateStack operation: Requires capabilities : [CAPABILITY_IAM]
調べると以下のようなものが出てきました。
- Serverless Application Model に入門してみた - Qiita
- AWS Identity and Access Management によるアクセスの制御 - AWS CloudFormation
IAMが絡むと必要になるようで、LambdaとそのRoleを追加したタイミングで発生したようです。
—capabilities CAPABILITY_IAM
を追加したら動くようになりました。*1
Lambdaの環境変数を定義したい
これはすぐ見つかりました。
でも秘匿情報はコミットしたくないので、どう別管理するのがいいのかは未解決。今回はサンプルで自分のローカルで変更して実行で済ませています。
Stageを定義しないとUsagePlanにStageを指定できないが、DeploymentとStageを両方書くとStageがすでにあるエラーが出る
DeploymentでStageが作られるので、それをUsagePlanに指定しようとしましたが、うまく指定の仕方がわからず。Deploymentで作成させるStageの名前を入れても、そんなものはないと怒られる始末。さらにDeploymentとStageで同じ名前にすると、すでにあるからダメと。
結局解決策わからず、Stageを定義しないと指定できないので、以下を参考に、Deploymentではダミーを作って、Stageを別定義して、それをUsagePlanに指定しました。
参考
- AWS CloudFormation が Amazon API Gateway をサポートしたので使ってみた | Developers.IO
- Serverless Application Model に入門してみた - Qiita
- api-gateway-continuous-deployment/cloudformation.template at master · matsev/api-gateway-continuous-deployment · GitHub
- AWS::ApiGateway::Method - AWS CloudFormation
- AWS Lambda 関数の環境 - AWS CloudFormation
*1:CAPABILITY_IAM、はっきり理解はできてません。権限いるから明示的に許可するってことでしょうか