CDK split API Gateway stack into 2 small stacks

不问归期 提交于 2020-01-24 10:50:50

问题


I'm trying to create a CDK stack in order to create API Gateway. Everything working as excepted if I create the stack in "small pieces" (comment part of the resources), But when I'm trying to create the completed stack I'm getting this exception:

 Number of resources, 224, is greater than maximum allowed, 200

Therefore, I tried to split my big stack into 2 smaller stacks, One stack creates the resource and create half of the resources and the other one fill relevant data.

My structure is like that:

const myEnv = {
    account: 'ACCOUNT_ID',
    region: 'REGION',
  }; 

const app = new cdk.App();
// get the lambdas function
const lambdas = new LambdasStack(app, 'LambdasForAPI',{env: myEnv});
// create new APIGW stack
new ApiGwStack(app, 'ApiGwStack',lambdas,{env: myEnv});

ApiGwStack contains the apigateway.RestApi :

const api = new apigateway.RestApi(this, 'ApiGWEndPoint', {
      restApiName: 'API_NAME,
      deployOptions: {
        stageName: 'STAGE_NAME',
      },
      description: "MyDescription",
      endpointTypes: [apigateway.EndpointType.REGIONAL]
    });

I tried to create cross-stack or nested-stack and pass the API data into it, but no luck so far.

My goal is to create one stack which will contain 2 small stacks- both of them will point to the same API. Or, if it is possible, create a workaround for the resource limit.

Any help will be much appricated.


Update 1.10.2020:

Currently, there is no workaround for this issue, Ended up splitting the API Gateway Into many API Gateways.


回答1:


This is how we are doing it right now. We basically have multiple stack that share the same API Gateway class (RestApi)

class MultipleStackConstruct extends Construct {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    // Main stack with shared components
    const commonStack = new CommonStack(
      scope,
      `common-stack`
    );

    // Module 1
    const moduleOneStack = new ModulOneStack(
      scope,
      `module-one`,
      {
        apiGatewayRestApi: commonStack.apiGatewayRestApi
      }
    );

    // Module 2, 3, etc.....
  }
}

This interface is used to pass the props to module stack:

export interface CommonProps extends cdk.StackProps {
  apiGatewayRestApi: apigw.RestApi;
}

The common module will create the API Gateway object:

export class CommonStack extends cdk.Stack {
  public readonly apiGatewayRestApi: apigw.RestApi;

  constructor(scope: cdk.Construct, id: string, props?: CommonProps) {
    super(scope, id, props);

    /******** SETUP API ********/
    this.apiGatewayRestApi = new apigw.RestApi(this, "MyAPI", {
      // Options here
    });
}

So the module stack itself will be something like this:

export class ModuleOneStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: CommonProps) {
    super(scope, id, props);

    if (props && props.apiGatewayRestApi) {
      const apiGatewayRestApi = props.apiGatewayRestApi;

      // associate lambda with api gateway
    }
  }
}

In this case, we are using only one API Gateway with multiple Lambdas that are divided into multiple stack, because we've also encountered the limit problem.

There is a documentation from AWS that is doing the same thing using VPC: https://docs.aws.amazon.com/cdk/api/latest/docs/aws-ec2-readme.html#sharing-vpcs-between-stacks

Copy paste from my comment here: https://github.com/aws/aws-cdk/issues/1477#issuecomment-568652807




回答2:


I think you can achieve your goal by separating resources into smaller stacks. It doesn't seem like you need cross stack references or nested stacks.

Here is an example (in Python) with 295 resources split between two stacks.

#!/usr/bin/env python3

from aws_cdk import core

from lambda_api.lambda_api_stack import APIStack
from lambda_api.lambda_api_stack import LambdasStack


app = core.App()
lambdas_stack = LambdasStack(app, 'lambdasstack')
APIStack(app, 'apistack', lambdas=lambdas_stack.lambdas)


app.synth()
from aws_cdk import (
    aws_apigateway as apigateway,
    aws_lambda as _lambda,
    aws_s3 as s3,
    core
)


class LambdasStack(core.Stack):

    @property
    def lambdas(self):
        return self._lambdas

    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        self._lambdas = list()
        for i in range(48):
            handler = _lambda.Function(
                self, f'Handler_{i}',
                function_name=f'Handler_{i}',
                runtime=_lambda.Runtime.PYTHON_3_8,
                code=_lambda.Code.from_asset('resources'),
                handler='handler.main'
            )
            self._lambdas.append(handler)


class APIStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, lambdas: list,
            **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        api = apigateway.RestApi(
            self, 'lambdas-api',
            rest_api_name='Lambdas Service',
            description='This service serves lambdas.'
        )

        for i in range(len(lambdas)):
            get_lambda_integration = apigateway.LambdaIntegration(
                lambdas[i],
                request_templates={
                    'application/json':
                    '{ "statusCode": "200" }'
                }
            )
            model = api.root.add_resource(f'Resource_{i}')
            model.add_method('GET', get_lambda_integration)

For this example, the API resource + Lambda integrations generate the most resources. Here is an outline of the resources created.

97 resources are created in lambdasstack.

  • 1 AWS::CDK::Metadata
  • 48 x 2 resources
    • 1 AWS::Lambda::Function
    • 1 AWS::IAM::Role

198 resources are created in apistack.

  • 1 AWS::CDK::Metadata
  • 1 AWS::ApiGateway::Account
  • 1 AWS::IAM::Role
  • 1 AWS::ApiGateway::RestApi
  • 1 AWS::ApiGateway::Deployment
  • 1 AWS::ApiGateway::Stage
  • 48 x 4 resources
    • 1 AWS::ApiGateway::Resource
    • 1 AWS::ApiGateway::Method
    • 2 AWS::IAM::Role



回答3:


Just pass the data using properties.

This requires to define public properties on the stack that provides output variables, and create an interface that extends StackProperties with the required properties to pass in.

The result may look like this:

const domain = new DomainStack(app, 'domain', {
  env: env,
  domainName: domainName,
  hostedZoneId: hostedZoneId
});

new WebsiteStack(app, 'website', {
  env: env,
  domainName: domainName,
  certificate: domain.certificate,
  hostedZone: domain.hostedZone,
});


来源:https://stackoverflow.com/questions/59393111/cdk-split-api-gateway-stack-into-2-small-stacks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!