AWS SAMとServerless Frameworkから学ぶAPI Gatewayリソースの分割手法
最近、次男の体重
が 長男の体重
を超え2台目の電動アシストサイクルを
買い足しました。 やっさん
でございます。
今回は、 CloudFormation
における API Gateway
の定義方法を、
AWS SAM
と Serverless Framework
の事例から理解し、
API Gateway
リソースの分割方法について模索してみます。
API Gateway HTTPエンドポイントの定義方法について
API Gateway HTTPエンドポイントは、 2種類の定義方法
があります。
それぞれを見ていきます。
その1:「AWS::ApiGateway::RestApi」のBodyに記述
Body定義に、全てのエンドポイントを記述します。
一度に全てのエンドポイントを記述でき、
複数のリソースに分割しないため内容を理解しやすいです。
外部のswaggerファイルを参照することで、記述内容をより簡潔に出来ます。
AWS SAM
はこの記述方法を採用しており、
Bodyの定義を省略した場合にも、AWS SAM
が自動生成します。
サンプル例:
"ApiGatewayApi1": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Body": {
"info": {
"version": "1.0",
"title": {
"Ref": "AWS::StackName"
}
},
"paths": {
"/v1/test1": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${api1.Arn}/invocations"
}
},
"responses": {}
}
}
},
"swagger": "2.0"
},
"Name": "api1"
}
},
その2:複数のリソースに定義
前述のBody定義は利用せず、複数のCloudFormationリソースに分割して定義します。
下記のリソースが登場します。
リソース名 | 役割 |
---|---|
AWS::ApiGateway::RestApi | REST API が作成されます |
AWS::ApiGateway::Resource | API にリソースを作成します |
AWS::ApiGateway::Method | リクエストを送信する必要があるパラメータと本文を定義する |
AWS::ApiGateway::Deployment | API Gateway RestApi リソースをステージにデプロイ |
AWS::ApiGateway::Stage | デプロイするためのステージを作成します |
リレーション的な関係は以下のようになります。 |
AWS::ApiGateway::RestApi
├ AWS::ApiGateway::Resource
│ └ AWS::ApiGateway::Method
└ AWS::ApiGateway::Deployment
└ AWS::ApiGateway::Stage
Serverless Framework
はこの定義方法を採用しており、
RestApiの論理ID
を参照すれば Resource
や Method
を複数のスタックに容易に分割可能です。
本題:API Gatewayリソースの分割方法
AWS SAM
および、 Serverless Framework
API Gateway
のリソース例から、
リソース分割方法を模索しました。
必ず突き当たる、CloudFormationのリソース数制限200の壁について
CloudFormation
は一つのテンプレートに含めることができるリソース数の上限を
200
としており、これは 上限解放申請をすることが出来ない
制限 となります。
AWS SAM
および、 Serverless Framework
でリソース制限に引っかかる
主な理由は、 API Gateway
のHTTPエンドポイントが増えることにあります。
AWS SAMの場合
AWS SAM
は、AWS::ApiGateway::RestApi
のBodyに
全てのエンドポイントを記述しますので、
リソース数的には余裕があるように一見すると見えます。
しかし 2019年9月15日
時点での仕様として、
API Gateway
のリソース と 関連する Lambdaファンクション
は同じスタックに
記述しないとデプロイに成功しません。エラーが出力されます。
つまり、単一の API Gateway
と 関連する Lambda
を含めたリソース数は 200が限界です
(2019年9月15日時点) 。
この限界は意外にすぐにやってきます。
なぜなら、 AWS SAM
は Lambda
毎に最低2つのPermissionリソースを作成するため、
Lambda
が増えれば増えるほど、Permissionが増え、
リソースの大半を占めるようになります。
AWS SAM
はこれについていくつかの Issue が発行されており議論されています。
Serverless Frameworkの場合
Serverless Framework
は、Permissionの数は Lambda
と 1:1
であるため、
Permissionの数がリソースの大半を占めるようなことはありません。
しかしながら、 API Gateway
関連の複数のリソースが作成されるため、
場合によっては AWS SAM
よりもリソース数を早く消費します。
特に、HTTPエンドポイントが多い大規模なAPIシステムの場合、
Serverless Framework
のほうがリソース数の限界 200
に
すぐに達してしまうでしょう。
しかしながら、 Serverless Framework
の場合は AWS SAM
と比較して
容易に スタック分割
できるため、実際には AWS SAM
よりも
多くのHTTPエンドポイントを含めることが出来ます。これについては後述します。
それぞれのデプロイフレームワークにおける解決策を探る
それでは、それぞれのデプロイフレームワークにおける
解決策を模索していきましょう。
AWS SAM : ベースパスマッピングによる複数のAPI Gatewayリソースの統合
API Gatewayにはベースパスマッピングが利用できます。
これにより、複数のAPI Gatewayリソースを一つのドメインに集約することが出来き、
API Gatewayの標準のURLよりも簡潔で分かりやすくなります。
ただし、注意点があります。
ベースパスマッピングは複数の階層を含めることができません。
例えば、下記のように分割することはできます。
パスマッピング | リソース名:ステージ名 |
---|---|
user | user-api:dev |
company | company-api:dev |
この場合、https://example.co.jp/user/
や
https://example.co.jp/company
のエンドポイントを利用してアクセスできます。
下記のように分割することは できません。
パスマッピング | リソース名:ステージ名 |
---|---|
v1/user | user-api:dev |
v1/company | company-api:dev |
パスマッピングは /
を許可しません。つまり、エンドポイントの設計によっては、
ベースパスマッピングだけでは実現できない場合があります。
Nested Applicationsによる、複数のAPI Gatewayリソースの作成サンプルはこちらです。
aws-sam-nested-application
Serverless Framework : split-stacksを用いたネストされたテンプレートへの分割
Serverless Framework
は split-stacks
プラグインを用いて、
ネストされたスタックを作成することが出来ます。
これにより、複数のAPI Gatewayリソースを作る必要がなく、
Lambda
と API Gateway
リソースを別々のスタックに分割できます。
分割方法は現在、下記の選択肢があります。
- perFunction:Lambdaの単位で分割する
- perType:リソースのタイプで分割する
- perGroupFunction:最大スタック数からLambdaをグループに振り分けて分割する
例えば、下記のように perGroupFunction
を指定し、最大スタック数を 20
とし、 API Gateway
に関連する 3つのLambda
をデプロイしてみます。
設定値:
custom:
splitStacks:
perFunction: false
perType: false
perGroupFunction: true
nestedStackCount: 20
この場合リソース分割は下記のような結果になり、Rootが最も少ないリソース数になり適切に分割されているのが分かります。
分割結果:
- (root): 9
- 11NestedStack: 15
- 15NestedStack: 13
- 4NestedStack: 3
- 6NestedStack: 13
一つ注意点として、 一度分割方法を設定したあとは、分割方法を変更することが出来ません。
ネストされるテンプレートの計画を変更したい場合は一度リソースを再作成する必要があります。
split-stacks
による、スタックの分割のサンプルはこちらです。
aws-sls-split-stacks
総評:サーバレスのデプロイフレームワークをより理解し、最適な利用方法を模索しよう
AWS SAM
と Serverless Framework
で比較しましたが、
どちらがよいという話はしません。
それぞれの特徴を把握し、
最適な利用方法を模索していくことがもっとも大事です。
サーバーレスの、酸いも甘いも嚙み分けていきましょう!
以上です!
MMMは、会社としてもAWS Lambdaに力を入れています。ぜひ以下のページもご覧ください。