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

aws cdk lambda is not bound when an api-gatewayv2 from a shared resource is used

我正在玩 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 网关 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 函数,应该使用道具中提供的 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-网关。查看 API 网关仪表板控制台中的资源,未创建任何内容。但是如果我重新 运行 命令 cdk deploy ApiGatewayStack 创建了资源 whoami 并且我可以使用 curl 发出 HTTP GET 请求来检索在 lambda 函数中生成的值。

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

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

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

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