使用来自共享资源的 api-gatewayv2 时未绑定 aws cdk lambda

Posted

技术标签:

【中文标题】使用来自共享资源的 api-gatewayv2 时未绑定 aws cdk lambda【英文标题】:aws cdk lambda is not bound when an api-gatewayv2 from a shared resource is used 【发布时间】:2022-01-17 16:05:10 【问题描述】:

我正在使用 AWS CDK 并创建了以下场景:2 个具有共享资源的堆栈,然后是其他使用共享资源的堆栈。

这是 VPC 的共享堆栈:

import * as cdk from "@aws-cdk/core";
import * as ec2 from "@aws-cdk/aws-ec2";

export class VpcStack extends cdk.Stack 
  public readonly vpc: ec2.Vpc;
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) 
    super(scope, id, props);

    // assign a VPC to the class property SharedInfraStack
    this.vpc = new ec2.Vpc(this, 'my-vpc', 
      cidr: '10.0.0.0/16',
      natGateways: 1,
      maxAzs: 3,
      subnetConfiguration: [
        
          name: 'private-subnet-1',
          subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
          cidrMask: 20,
        ,
        
          name: 'public-subnet-1',
          subnetType: ec2.SubnetType.PUBLIC,
          cidrMask: 20,
        ,
        
          name: 'isolated-subnet-1',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
          cidrMask: 20,
        ,
      ],
    );
    
  

这适用于 API Gateway v2:

import CorsHttpMethod, HttpApi  from '@aws-cdk/aws-apigatewayv2';
import * as cdk from '@aws-cdk/core';

export class ApiGatewayStack extends cdk.Stack 
  public apigw: HttpApi;

  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) 
    super(scope, id, props);

    this.apigw = new HttpApi(this, 'my-http-api', 
      corsPreflight: 
        allowHeaders: [
          'Content-Type',
          'X-Amz-Date',
          'Authorization',
          'X-Api-Key',
        ],
        allowMethods: [
          CorsHttpMethod.OPTIONS,
          CorsHttpMethod.GET,
          CorsHttpMethod.POST,
          CorsHttpMethod.PUT,
          CorsHttpMethod.PATCH,
          CorsHttpMethod.DELETE,
        ],
        allowCredentials: true,
        allowOrigins: [
          'https://example.com:3000',
      ],
      ,
    );

    new cdk.CfnOutput(this, 'apiUrl', 
      value: this.apigw.url!,
    );

  

我还创建了一个接口,以便在我想在其他堆栈中使用这两个共享资源时使用:

import * as cdk from '@aws-cdk/core';
import * as ec2 from "@aws-cdk/aws-ec2";
import  HttpApi  from '@aws-cdk/aws-apigatewayv2';

export interface FunctionProps extends cdk.StackProps 
    vpc: ec2.Vpc;
    apigw: HttpApi;

之后,我创建了一个简单的堆栈,其中定义了一个 lambda 函数,并且应该使用 props 中提供的 VPC 和 APIGW:

import HttpMethod from '@aws-cdk/aws-apigatewayv2';
import LambdaProxyIntegration from '@aws-cdk/aws-apigatewayv2-integrations';
import * as lambda from '@aws-cdk/aws-lambda';
import * as cdk from '@aws-cdk/core';
import * as ec2 from "@aws-cdk/aws-ec2";
import * as path from 'path';

import FunctionProps from './props';


export class UserStack extends cdk.Stack 
  constructor(scope: cdk.App, id: string, props?: FunctionProps) 
    super(scope, id, props);

    const whoAmILambda = new lambda.Function(this, 'who-am-i', 
        runtime: lambda.Runtime.NODEJS_14_X,
        handler: 'index.main',
        code: lambda.Code.fromAsset(path.join(__dirname, 'path/to/function')),
        vpc: props?.vpc,
        vpcSubnets: 
            subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        
      );
      props?.apigw.addRoutes(
        path: '/whoami',
        methods: [HttpMethod.GET],
        integration: new LambdaProxyIntegration(
          handler: whoAmILambda,
        ),
      );
  

main.ts 文件如下:

import * as cdk from "@aws-cdk/core";
import  ApiGatewayStack  from "./src/api-gateway/api-gateway";
import  UserStack  from "./src/functions/user";
import  VpcStack  from "./src/vpc/vpc-stack";

const env = 
    account: process.env.ACCOUNT_NUMBER,
    region: process.env.AWS_REGION

const app = new cdk.App();

const vpcStack = new VpcStack(app, 'VpcStack', env);
const apigwStack = new ApiGatewayStack(app, 'ApiGatewayStack', env);

new UserStack(app, 'UserStack', 
    env,
    vpc: vpcStack.vpc,
    apigw: apigwStack.apigw,
)

我按以下顺序部署堆栈:

cdk deploy VpcStack
cdk deploy ApiGatewayStack
cdk deploy UserStack

一切正常,VPC 已创建,APIGW 也已创建,问题出在 lambda 函数中。

该函数具有 VPC 的预期配置,但 api-gateway 没有触发器。查看 API Gateway 仪表板控制台中的资源,没有创建任何内容。但是,如果我重新运行命令 cdk deploy ApiGatewayStack,则会创建资源 whoami,我可以使用 curl 发出 HTTP GET 请求来检索 lambda 函数中生成的值。

此解决方法的问题在于,每当我想添加另一个使用 APIGW 的堆栈时,我都必须多次运行 cdk deploy ApiGatewayStack,从而增加部署时间。我有什么办法可以在 lambda 堆栈中使用和创建 HTTP 端点,以不依赖 cdk deploy ApiGatewayStack 命令来部署新端点?

【问题讨论】:

初始部署后cdk diff ApiGatewayStack的输出是什么? 【参考方案1】:

发生这种情况的原因是 CloudFormation 不允许修改导入的资源(在堆栈之外创建)。由于您的网关是在您的 lambda 堆栈之外创建的,因此无法对其进行修改。

CDK 解决此问题的方法是返回并更改 ApiGatewayStack 的模板以应用所需的更改,即使更改是在另一个堆栈中实现的。

这是 CloudFormation 的限制。我建议不要单独部署你的堆栈以​​避免这个问题,使用cdk deploy --all 部署它们。应该不会花费更长的时间,因为 CloudFormation 只会部署差异,不会重新部署整个 ApiGatewayStack

【讨论】:

使用一个堆栈的问题是由于您被限制为200个资源硬限制。一个堆栈非常适合小堆栈,但我的用例不适合一个堆栈。如果您想整合我使用并解决了我的问题的来自 github github.com/aws/aws-cdk/issues/12337#issuecomment-991092668) 的答案,我很乐意接受您的答案 我没有说一个堆栈 - 你可以有多个堆栈,只需使用 cdk deploy --all 来合成并部署它们。 关于 github 评论 - 我宁愿将答案概括化,以解释为什么跨堆栈修改会导致这种行为。如果它解决了您的问题,您可以自己发布针对您的特定问题的解决方法作为答案,并且您可以接受它。 编辑了答案以澄清我说的是同时部署所有堆栈。

以上是关于使用来自共享资源的 api-gatewayv2 时未绑定 aws cdk lambda的主要内容,如果未能解决你的问题,请参考以下文章

来自资源的CRichEditCtrl加载1.0而不是2.0

来自后台堆栈的片段 onResume

如何修复“访问令牌来自错误的受众或资源。”尝试使用 MSAL 令牌访问 Azure 的 REST api 时

当资源不足时,火花作业将等待来自纱线的资源多长时间?

在 pyodbc 中执行 SELECT 查询时,来自 ODBC MS Access 驱动程序的“系统资源超出”错误

当另一个库具有相同的符号时,gdb 不显示来自共享库的符号