LambdaでGoを使ったAPIを作成したときの話
あるサービスでGoを採用し、Lambda上でapiを作成することになった、最初は小規模の認識で開発を行っていたが、仕様がどんどん膨らみ気づいた時にはエンドポイントが150を超え、そしてやってきたリソース制限
Template format error: Number of resources, 206, is greater than maximum allowed, 200
ネストさせることで回避できることを知り、ネストするもsam build
できず、結局ネストされた各アプリケションを個別にビルドし、マージするシェルを書いて運用していた。
苦労した話を書こうと思い調べていると、いつの間にかネストされたアプリケーションのビルドができるようになっていた!!!
https://github.com/aws/aws-sam-cli/issues/1470
前段の話が長くなりましたが、Lambdaでネストされたアプリケーションを簡単に構築できる話です
構築
2つのアプリケーションにネストさせる例です
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
lambda-go
Sample SAM Template for lambda-go
Parameters:
Region:
Type: String
Default: ap-northeast-1
Stage:
Type: String
Default: Dev
ApiDomainName:
Type: String
Default: api.example.com
Resources:
# Lambda Application
App1Application:
Type: AWS::Serverless::Application
Properties:
Location: app1.yaml
Parameters:
Region: !Ref Region
Stage: !Ref Stage
ApiDomainName: !Ref ApiDomainName
App2Application:
Type: AWS::Serverless::Application
Properties:
Location: app2.yaml
Parameters:
Region: !Ref Region
Stage: !Ref Stage
ApiDomainName: !Ref ApiDomainName
アプリケーション1
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
lambda-go
Sample SAM Template for lambda-go
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 10
Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
Variables:
REGION: !Ref Region
Parameters:
Stage:
Type: String
Region:
Type: String
ApiDomainName:
Type: String
Resources:
# ロール
App1Role:
Type: AWS::IAM::Role
Properties:
RoleName: app1-role
Policies:
- PolicyName: app1-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ec2:CreateNetworkInterface
- ec2:DescribeNetworkInterfaces
- ec2:DetachNetworkInterface
- ec2:DeleteNetworkInterface
Resource: '*'
AssumeRolePolicyDocument: {
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Principal: {
Service: [
"lambda.amazonaws.com"
]
},
Action: [
"sts:AssumeRole"
]
}
]
}
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Path: /
# Api Gateway
ApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: !Ref Stage
# Base path mapping
ApiGatewayBasePathMapping:
Type: AWS::ApiGateway::BasePathMapping
Properties:
DomainName: !Ref ApiDomainName
RestApiId: !Ref ApiGateway
BasePath: app1
Stage: !Ref ApiGateway.Stage
# Lambda Function
Test1Function:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: ../../test1/
Handler: test1
Runtime: go1.x
Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html
Role: !GetAtt App1Role.Arn
Events:
GET:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
RestApiId: !Ref ApiGateway
Path: /test1
Method: GET
Test2Function:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: ../../test2/
Handler: test2
Runtime: go1.x
Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html
Role: !GetAtt App1Role.Arn
Events:
GET:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
RestApiId: !Ref ApiGateway
Path: /test2
Method: GET
Test3Function:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: ../../test3/
Handler: test3
Runtime: go1.x
Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html
Role: !GetAtt App1Role.Arn
Events:
GET:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
RestApiId: !Ref ApiGateway
Path: /test3
Method: GET
アプリケーション2
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
lambda-go
Sample SAM Template for lambda-go
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 10
Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
Variables:
REGION: !Ref Region
Parameters:
Stage:
Type: String
Region:
Type: String
ApiDomainName:
Type: String
Resources:
# ロール
App2Role:
Type: AWS::IAM::Role
Properties:
RoleName: app2-role
Policies:
- PolicyName: app2-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ec2:CreateNetworkInterface
- ec2:DescribeNetworkInterfaces
- ec2:DetachNetworkInterface
- ec2:DeleteNetworkInterface
Resource: '*'
AssumeRolePolicyDocument: {
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Principal: {
Service: [
"lambda.amazonaws.com"
]
},
Action: [
"sts:AssumeRole"
]
}
]
}
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Path: /
# Api Gateway
ApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: !Ref Stage
# Base path mapping
ApiGatewayBasePathMapping:
Type: AWS::ApiGateway::BasePathMapping
Properties:
DomainName: !Ref ApiDomainName
RestApiId: !Ref ApiGateway
BasePath: app2
Stage: !Ref ApiGateway.Stage
# Lambda Function
Test10Function:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: ../../test10/
Handler: test10
Runtime: go1.x
Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html
Role: !GetAtt App2Role.Arn
Events:
GET:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
RestApiId: !Ref ApiGateway
Path: /test10
Method: GET
Test11Function:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: ../../test11/
Handler: test11
Runtime: go1.x
Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html
Role: !GetAtt App2Role.Arn
Events:
GET:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
RestApiId: !Ref ApiGateway
Path: /test11
Method: GET
Test12Function:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: ../../test12/
Handler: test12
Runtime: go1.x
Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html
Role: !GetAtt App2Role.Arn
Events:
GET:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
RestApiId: !Ref ApiGateway
Path: /test12
Method: GET
ネスト以外のポイントとして、API GatewayのAPI マッピングを使ってネストされたアプリケーションをマッピングしています。
ApiGatewayBasePathMapping:
Type: AWS::ApiGateway::BasePathMapping
Properties:
DomainName: !Ref ApiDomainName
RestApiId: !Ref ApiGateway
BasePath: app2
Stage: !Ref ApiGateway.Stage
これをすると、template.yaml
で指定している、ApiDomainName
(api.example.com)で各ネストされたアプリケーションにアクセスできるようになる
例えば、https://api.example.com/app1/test1 とか https://api.example.com/app2/test10 など
*実際に試して頂く場合はApiDomainName
を変更して頂く必要があります
デプロイ
デプロイ時にはcapabilities
にCAPABILITY_AUTO_EXPAND
を指定しデプロイをおこないます、成功するとCloudFormationでネストされたアプリケーションが表示されます
ソース
参考までにソースをあげておきました。