如何删除在用ECS容量提供商?CDK销毁栈失败求助
解决CDK销毁ECS栈时容量提供商占用的问题
以下是几种无需手动操作控制台即可自动清理资源并销毁栈的方案:
方案1:在CDK代码中添加销毁前的自动清理逻辑
通过自定义Lambda资源,在栈销毁阶段自动终止ECS任务、缩容ASG,确保容量提供商释放后再销毁集群关联资源:
- 创建清理用的Lambda函数,包含终止ECS任务、缩容ASG的逻辑
- 绑定自定义资源到栈的销毁生命周期
- 调整资源依赖顺序,让清理逻辑优先执行
示例TypeScript代码片段:
import * as cdk from 'aws-cdk-lib'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as iam from 'aws-cdk-lib/aws-iam'; import * as customresources from 'aws-cdk-lib/custom-resources'; // 替换为你的ECS集群和ASG实例 const ecsCluster = /* 你的ECS集群对象 */; const asg = /* 你的ASG对象 */; // 创建清理Lambda函数 const cleanupFn = new lambda.Function(this, 'EcsCleanupFn', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'index.handler', code: lambda.Code.fromInline(` const AWS = require('aws-sdk'); const ecs = new AWS.ECS(); const autoscaling = new AWS.AutoScaling(); exports.handler = async (event) => { if (event.RequestType === 'Delete') { // 将所有ECS服务的期望任务数设为0 const servicesResp = await ecs.listServices({ cluster: '${ecsCluster.clusterName}' }).promise(); for (const serviceArn of servicesResp.serviceArns) { const serviceName = serviceArn.split('/').pop(); await ecs.updateService({ cluster: '${ecsCluster.clusterName}', service: serviceName, desiredCount: 0 }).promise(); } // 等待服务任务停止(可根据实际情况调整等待时间) await new Promise(resolve => setTimeout(resolve, 45000)); // 停止所有独立运行的ECS任务 const tasksResp = await ecs.listTasks({ cluster: '${ecsCluster.clusterName}' }).promise(); for (const taskArn of tasksResp.taskArns) { await ecs.stopTask({ cluster: '${ecsCluster.clusterName}', task: taskArn }).promise(); } // 将ASG缩容到0 await autoscaling.updateAutoScalingGroup({ AutoScalingGroupName: '${asg.autoScalingGroupName}', MinSize: 0, MaxSize: 0, DesiredCapacity: 0 }).promise(); } return { Status: 'SUCCESS', PhysicalResourceId: event.PhysicalResourceId || 'ecs-cleanup' }; }; `), role: new iam.Role(this, 'CleanupLambdaRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonECS_FullAccess'), iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2AutoScalingFullAccess') ], }), }); // 创建自定义资源,触发清理逻辑 const cleanupResource = new customresources.AwsCustomResource(this, 'EcsCleanupCustomResource', { onCreate: { service: 'Lambda', action: 'invoke', parameters: { FunctionName: cleanupFn.functionName }, }, onDelete: { service: 'Lambda', action: 'invoke', parameters: { FunctionName: cleanupFn.functionName }, }, policy: customresources.AwsCustomResourcePolicy.fromSdkCalls({ resources: customresources.AwsCustomResourcePolicy.ANY_RESOURCE, }), }); // 设置依赖:集群需等待清理完成后再销毁 ecsCluster.node.addDependency(cleanupResource);
方案2:使用预销毁脚本+cdk destroy
编写Shell脚本自动清理资源,再执行销毁命令:
- 创建清理脚本(
cleanup-ecs.sh):
#!/bin/bash CLUSTER_NAME="sd-cluster" # 将所有ECS服务的期望任务数设为0 aws ecs list-services --cluster $CLUSTER_NAME --query 'serviceArns[]' --output text | tr '\t' '\n' | while read SERVICE_ARN; do SERVICE_NAME=$(echo $SERVICE_ARN | awk -F '/' '{print $NF}') aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE_NAME --desired-count 0 done # 停止所有运行中的ECS任务 aws ecs list-tasks --cluster $CLUSTER_NAME --query 'taskArns[]' --output text | tr '\t' '\n' | while read TASK_ARN; do aws ecs stop-task --cluster $CLUSTER_NAME --task $TASK_ARN done # 获取关联的容量提供商对应的ASG名称(假设仅一个容量提供商) CAPACITY_PROVIDER=$(aws ecs describe-clusters --clusters $CLUSTER_NAME --query 'clusters[0].capacityProviders[0]' --output text) ASG_NAME=$(aws ecs describe-capacity-providers --capacity-providers $CAPACITY_PROVIDER --query 'capacityProviders[0].autoScalingGroupProvider.autoScalingGroupArn' --output text | awk -F '/' '{print $NF}') # 将ASG缩容到0 aws autoscaling update-auto-scaling-group --auto-scaling-group-name $ASG_NAME --min-size 0 --max-size 0 --desired-capacity 0 # 等待资源清理完成 echo "等待资源清理完成..." sleep 60
- 赋予脚本执行权限并运行:
chmod +x cleanup-ecs.sh ./cleanup-ecs.sh
- 执行销毁命令:
cdk destroy --force
方案3:调整CDK资源的删除顺序和移除策略
通过设置资源的移除策略和依赖关系,确保ECS服务、ASG先被销毁,再处理集群的容量提供商关联:
import * as cdk from 'aws-cdk-lib'; // 对ECS服务设置销毁策略 ecsService.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY); // 对ASG设置销毁策略 asg.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY); // 设置依赖顺序:ASG需等待ECS服务销毁完成 asg.node.addDependency(ecsService); // 集群需等待ASG销毁完成 ecsCluster.node.addDependency(asg);
内容的提问来源于stack exchange,提问作者sak
相关产品推荐
相关产品推荐

