无法从AWS API Gateway移除Lambda函数:提示仍被引用
问题描述
被这个问题卡了好几天,想从AWS API Gateway里移除一个Lambda函数的关联方法,但不想删除整个Lambda函数(实际上也无法删除)。怀疑问题出在旧部署版本还在引用该Lambda——因为设置了retainDeployments: true?
ApiGatewayStack代码
import { Stack } from "aws-cdk-lib"; import { Construct } from "constructs"; import { StackPropsConfig } from "../config/stackPropsConfig"; import { Deployment, DomainName, EndpointType, LambdaIntegration, RestApi, Stage } from "aws-cdk-lib/aws-apigateway"; import { IHostedZone } from "aws-cdk-lib/aws-route53"; import { ICertificate } from "aws-cdk-lib/aws-certificatemanager"; interface ApiGatewayProps extends StackPropsConfig { hostedZone: IHostedZone; certificate: ICertificate; testLambda: LambdaIntegration; createPost: LambdaIntegration; getPost: LambdaIntegration; } export class ApiGatewayStack extends Stack { public readonly customDomain: DomainName; constructor(scope: Construct, id: string, props: ApiGatewayProps) { super(scope, id, props); const apiGateway = new RestApi(this, `butlai-api-gateway-${props.config.ENV}`, { deploy: false }); this.customDomain = apiGateway.addDomainName(`butlai-api-gateway-custom-domain-${props.config.ENV}`, { domainName: props.config.ENV_URL, certificate: props.certificate, endpointType: EndpointType.EDGE, }); // Explicitly create a deployment for v1 const deploymentV1 = new Deployment(this, `butlai-api-deployment-v1-${props.config.ENV}-${Date.now()}`, { api: apiGateway, retainDeployments: true, }); // Create a stage for v1 new Stage(this, `butlai-api-stage-v1-${props.config.ENV}`, { deployment: deploymentV1, stageName: 'v1' }); // Create resources and methods for v1 const postsResourcesV1 = apiGateway.root.addResource("posts"); postsResourcesV1.addMethod("POST", props.createPost); const postResourcesV1 = postsResourcesV1.addResource("{id}"); postResourcesV1.addMethod("GET", props.getPost); postResourcesV1.addMethod("DELETE", props.testLambda); } }
现在想要删除最后一个方法:
// postResourcesV1.addMethod("DELETE", props.testLambda);
但部署时CloudFormation控制台报错:
Export ButlaiLambdaStack-dev:ExportsOutputFnGetAtttestFunctionFOOBAR cannot be deleted as it is in use by ButlaiApiGatewayStack-dev
代码库中没有其他地方引用这个testLambda函数,只是想部署不含该方法的API新版本,请问遗漏了什么?该如何解决?
更新1:Launcher.ts代码
import { App } from "aws-cdk-lib" import { NetworkStack } from "./stacks/NetworkStack"; import { AppConfig } from "./config/types"; import { loadConfig } from "./config/loadConfig"; import { DataStack } from "./stacks/DataStack"; import { LambdaStack } from "./stacks/LambdaStack"; import { ApiGatewayStack } from "./stacks/ApiGatewayStack"; import { CertificateStack } from "./stacks/CertificateStack"; import { Route53Stack } from "./stacks/Route53Stack"; import { ApiGatewayDomain } from "aws-cdk-lib/aws-route53-targets"; import { SecurityStack } from "./stacks/SecurityStack"; const app = new App(); const appConfig: AppConfig = loadConfig(app); const route53Stack = new Route53Stack(app, `ButlaiRoute53Stack-${appConfig.ENV}`, { config: appConfig, }) const certificateStack = new CertificateStack(app, `ButlaiCertificateStack-${appConfig.ENV}`, { config: appConfig, hostedZone: route53Stack.hostedZone }); certificateStack.addDependency(route53Stack); const networkStack = new NetworkStack(app, `ButlaiNetworkStack-${appConfig.ENV}`, { config: appConfig }); const securityStack = new SecurityStack(app, `ButlaiSecurityStack-${appConfig.ENV}`, { vpc: networkStack.vpc, }); securityStack.addDependency(networkStack); const dataStack = new DataStack(app, `ButlaiDataStack-${appConfig.ENV}`, { config: appConfig, vpc: networkStack.vpc, databaseSecurityGroup: securityStack.databaseSecurityGroup, }); dataStack.addDependency(securityStack); const lambdaStack = new LambdaStack(app, `ButlaiLambdaStack-${appConfig.ENV}`, { config: appConfig, vpc: networkStack.vpc, databaseSecrets: dataStack.databaseSecrets, lambdaSecurityGroup: securityStack.lambdaSecurityGroup, databaseSecurityGroup: securityStack.databaseSecurityGroup, }); lambdaStack.addDependency(dataStack); const apiGatewayStack = new ApiGatewayStack(app, `ButlaiApiGatewayStack-${appConfig.ENV}`, { config: appConfig, hostedZone: route53Stack.hostedZone, certificate: certificateStack.certificate, testLambda: lambdaStack.testLambdaFunction, createPost: lambdaStack.createPostLambdaFunction, getPost: lambdaStack.getPostLambdaFunction, }); apiGatewayStack.addDependency(route53Stack); apiGatewayStack.addDependency(certificateStack); apiGatewayStack.addDependency(lambdaStack);
解决方案
1. 移除不必要的Lambda参数传递
报错的核心原因是:尽管你注释了API方法,但ApiGatewayStack的Props定义中仍保留testLambda参数,且Launcher.ts里还在传递该Lambda实例。CDK会自动为跨栈传递的资源创建CloudFormation导出/导入依赖,导致CloudFormation认为该Lambda的导出仍被ApiGatewayStack使用。
解决步骤:
- 修改
ApiGatewayProps,移除testLambda字段:interface ApiGatewayProps extends StackPropsConfig { hostedZone: IHostedZone; certificate: ICertificate; createPost: LambdaIntegration; getPost: LambdaIntegration; } - 修改Launcher.ts中ApiGatewayStack的实例化代码,删除
testLambda参数:const apiGatewayStack = new ApiGatewayStack(app, `ButlaiApiGatewayStack-${appConfig.ENV}`, { config: appConfig, hostedZone: route53Stack.hostedZone, certificate: certificateStack.certificate, createPost: lambdaStack.createPostLambdaFunction, getPost: lambdaStack.getPostLambdaFunction, });
2. 分阶段部署(若直接修改后仍报错)
如果一次性修改后部署失败,可分两步执行:
- 先保留
testLambda参数和传递,但注释掉API方法,部署一次。此时API会更新为不含DELETE方法的版本,但仍保留跨栈依赖。 - 再移除
testLambda参数和传递,再次部署,此时CloudFormation会清理掉ApiGatewayStack对该Lambda的导入依赖,报错消失。
3. 清理旧API部署(可选)
由于设置了retainDeployments: true,旧的API部署版本会保留在AWS控制台中。这些旧部署可能仍持有对Lambda的执行权限,虽然不影响当前部署,但可以手动删除不再使用的部署版本,避免后续混淆。
4. 检查Lambda权限
确认API Gateway对该testLambda的执行权限是否已被CDK自动清理。若存在手动添加的权限,需手动删除IAM中对应的权限策略。
内容的提问来源于stack exchange,提问作者tpotjj

