使用AWS CDK整合API Gateway与Fargate服务时遇参数缺失错误
问题:公网API与私有子网Fargate服务集成时CDK合成报错
执行cdk synthesize --profile=PandaService-Alpha命令时触发以下错误:
/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/integration.ts:249 throw new Error('Either `integrationSubtype` or `integrationUri` must be specified.'); ^ Error: Either `integrationSubtype` or `integrationUri` must be specified. at new HttpIntegration (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/integration.ts:249:13) at HttpAlbIntegration._bindToRoute (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/integration.ts:317:26) at new HttpRoute (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/route.ts:191:38) at /Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/api.ts:458:14 at Array.map (<anonymous>) at HttpApi.addRoutes (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/api.ts:455:20) at ApigatewayStack.addApiRoutes (/Users/yangliu/Projects/Panda/PandaApi/lib/apigateway-stack.ts:110:22) at new ApigatewayStack (/Users/yangliu/Projects/Panda/PandaApi/lib/apigateway-stack.ts:101:10) at /Users/yangliu/Projects/Panda/PandaApi/bin/app.ts:17:3
相关代码
import * as CDK from "aws-cdk-lib"; import * as CertificateManager from "aws-cdk-lib/aws-certificatemanager"; import * as Route53 from "aws-cdk-lib/aws-route53"; import * as ApiGatewayV2Alpha from "@aws-cdk/aws-apigatewayv2-alpha"; import * as ApiGatewayV2IntegrationsAlpha from "@aws-cdk/aws-apigatewayv2-integrations-alpha"; import * as ELBv2 from "aws-cdk-lib/aws-elasticloadbalancingv2"; import { Construct } from "constructs"; import { StageInfo } from "../config/stage-config"; import * as EC2 from "aws-cdk-lib/aws-ec2"; export interface ApigatewayStackProps extends CDK.StackProps { readonly packageName: string; readonly stageInfo: StageInfo; } export class ApigatewayStack extends CDK.Stack { private readonly coreVpc: EC2.IVpc; // Prefix for CDK constrcut ID private readonly constructIdPrefix: string; private readonly pandaApi: ApiGatewayV2Alpha.HttpApi; constructor(scope: Construct, id: string, props: ApigatewayStackProps) { super(scope, id, props); this.coreVpc = EC2.Vpc.fromLookup( this, `${props.stageInfo.stageName}VpcLookupId`, { vpcName: "CoreVpc", } ); this.constructIdPrefix = `${props.packageName}-${props.stageInfo.stageName}`; const hostedZone: Route53.IHostedZone = Route53.HostedZone.fromLookup( this, `${this.constructIdPrefix}-HostedZoneLookup`, { domainName: props.stageInfo.domainName, } ); const domainCertificate = new CertificateManager.Certificate( this, `${this.constructIdPrefix}-pandaApiCertificate`, { domainName: props.stageInfo.domainName, validation: CertificateManager.CertificateValidation.fromDns(hostedZone), } ); const customDomainName = new ApiGatewayV2Alpha.DomainName( this, `${this.constructIdPrefix}-ApiGatewayDomainName`, { certificate: domainCertificate, domainName: props.stageInfo.domainName, } ); this.pandaApi = new ApiGatewayV2Alpha.HttpApi( this, `${this.constructIdPrefix}-pandaApi`, { defaultDomainMapping: { domainName: customDomainName, //mappingKey: props.pipelineStageInfo.stageName }, corsPreflight: { allowOrigins: ["*"], allowHeaders: ["*"], allowMethods: [ ApiGatewayV2Alpha.CorsHttpMethod.OPTIONS, ApiGatewayV2Alpha.CorsHttpMethod.GET, ApiGatewayV2Alpha.CorsHttpMethod.POST, ApiGatewayV2Alpha.CorsHttpMethod.PUT, ], maxAge: CDK.Duration.hours(6), }, //createDefaultStage: false, // only allow use custom domain disableExecuteApiEndpoint: true } ); this.addApiRoutes(props); } /** * Add API routes for multiple services. */ private addApiRoutes(props: ApigatewayStackProps) { const PandaServiceIntegration : ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration = this.generatePandaServiceIntegration(props); this.pandaApi.addRoutes({ path: "/products", methods: [ApiGatewayV2Alpha.HttpMethod.ANY], integration: PandaServiceIntegration, }); this.pandaApi.addRoutes({ path: "/store-categories", methods: [ApiGatewayV2Alpha.HttpMethod.ANY], integration: PandaServiceIntegration, }); this.pandaApi.addRoutes({ path: "/stores", methods: [ApiGatewayV2Alpha.HttpMethod.ANY], integration: PandaServiceIntegration, }); } /** * * @returns HttpAlbIntegration for PandaService. */ private generatePandaServiceIntegration(props: ApigatewayStackProps) { const vpcLink = new ApiGatewayV2Alpha.VpcLink( this, `${this.constructIdPrefix}-VpcLink`, { vpc: this.coreVpc, subnets: { subnetType: EC2.SubnetType.PRIVATE_ISOLATED, }, } ); const PandaServiceAlbSecurityGroup = EC2.SecurityGroup.fromLookupByName( this, `${this.constructIdPrefix}-PandaServiceAlbSecurityGroupLookup`, "PandaServiceAlbSecurityGroup", this.coreVpc ); const PandaServiceAlbListener : ELBv2.IApplicationListener = ELBv2.ApplicationListener.fromApplicationListenerAttributes(this, `${this.constructIdPrefix}-PandaServiceAlbListenerLookUp`, { listenerArn: props.stageInfo.PandaServiceAlbArn, securityGroup: PandaServiceAlbSecurityGroup, }); const PandaServiceIntegration: ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration = new ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration( `${this.constructIdPrefix}-PandaServiceIntegration`, PandaServiceAlbListener , { method: ApiGatewayV2Alpha.HttpMethod.ANY, vpcLink: vpcLink, secureServerName: props.stageInfo.domainName, parameterMapping: new ApiGatewayV2Alpha.ParameterMapping() } ); return PandaServiceIntegration; } }
解决方案
原因分析
报错是因为通过ELBv2.ApplicationListener.fromApplicationListenerAttributes获取的IApplicationListener实例,无法被CDK的alpha版本自动解析出integrationUri或integrationSubtype,导致创建HttpAlbIntegration时缺少必要参数。
修复方法
方法1:升级CDK Alpha包
旧版本的@aws-cdk/aws-apigatewayv2-alpha和@aws-cdk/aws-apigatewayv2-integrations-alpha存在该问题,升级到最新版本可修复:
npm update @aws-cdk/aws-apigatewayv2-alpha @aws-cdk/aws-apigatewayv2-integrations-alpha
方法2:手动指定IntegrationUri
如果无法升级包,需要手动构造integrationUri参数传入HttpAlbIntegration。首先需要从props.stageInfo中传入ALB的ARN(假设添加PandaServiceAlbArn字段),然后构造格式为arn:aws:apigateway:<区域>:elb:path/<ALB-ARN>/<Listener-ARN>的URI:
修改generatePandaServiceIntegration方法中的HttpAlbIntegration创建代码:
const PandaServiceIntegration: ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration = new ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration( `${this.constructIdPrefix}-PandaServiceIntegration`, PandaServiceAlbListener , { method: ApiGatewayV2Alpha.HttpMethod.ANY, vpcLink: vpcLink, secureServerName: props.stageInfo.domainName, parameterMapping: new ApiGatewayV2Alpha.ParameterMapping(), // 手动指定integrationUri integrationUri: `arn:aws:apigateway:${this.region}:elb:path/${props.stageInfo.PandaServiceAlbArn}/${props.stageInfo.PandaServiceListenerArn}` } );
方法3:直接引用同栈创建的Listener
如果ALB和Listener是在同一CDK应用的其他栈中创建的,不要通过ARN查找,而是通过栈之间的引用传递Listener对象,这样CDK可以自动获取所需的集成参数。
内容的提问来源于stack exchange,提问作者Yang Liu
相关产品推荐
相关产品推荐

