You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EC2实例终止前如何优雅关闭ECS服务?

解决ECS EC2实例终止前优雅关闭服务的方案

1. 给Auto Scaling Group配置生命周期钩子(核心)

ASG默认滚动更新会直接终止实例,必须通过生命周期钩子在终止前注入ECS实例注销与任务排空逻辑:

  • 在CDK中为ASG添加INSTANCE_TERMINATING类型的生命周期钩子,绑定Lambda函数处理注销流程
  • Lambda核心逻辑:
    1. 调用ecs.deregisterContainerInstance并设置force=false,触发ECS任务排空
    2. 轮询等待ECS实例状态变为DRAINING,直到所有任务完成或被重新调度
    3. 调用autoscaling:CompleteLifecycleAction,允许实例继续终止
  • 设置足够的钩子超时时间(如30分钟),避免任务排空超时导致ASG更新失败

CDK代码示例:

// 假设已定义ASG和ECS集群实例
const lifecycleHook = new autoscaling.LifecycleHook(this, 'EcsTerminationHook', {
  autoScalingGroup: asg,
  lifecycleTransition: autoscaling.LifecycleTransition.INSTANCE_TERMINATING,
  heartbeatTimeout: Duration.minutes(30),
  defaultResult: autoscaling.DefaultResult.ABANDON, // 超时则放弃终止,避免实例僵死
});

// 处理注销逻辑的Lambda
const drainHandler = new lambda.Function(this, 'EcsDrainHandler', {
  runtime: lambda.Runtime.PYTHON_3_11,
  code: lambda.Code.fromAsset('lambda'),
  handler: 'drain.handler',
  environment: {
    CLUSTER_NAME: cluster.clusterName,
  },
});

// 给Lambda添加必要权限
drainHandler.addToRolePolicy(new iam.PolicyStatement({
  actions: ['ecs:DeregisterContainerInstance', 'ecs:DescribeContainerInstances'],
  resources: [cluster.clusterArn],
}));
drainHandler.addToRolePolicy(new iam.PolicyStatement({
  actions: ['autoscaling:CompleteLifecycleAction'],
  resources: [asg.autoScalingGroupArn],
}));

// 绑定钩子与Lambda
lifecycleHook.addTarget(new autoscalingLifecycleHookTargets.LambdaHook(drainHandler));

2. 配置ECS服务与负载均衡的优雅排空参数

  • ECS服务层面:设置容器停止超时时间,确保请求处理完成后再退出;同时调整部署配置避免服务中断:
const taskDef = new ecs.Ec2TaskDefinition(this, 'AppTaskDef', {
  containers: {
    app: {
      image: ecs.ContainerImage.fromRegistry('your-app-image'),
      stopTimeout: Duration.seconds(60), // 容器优雅关闭超时
    },
  },
});

const service = new ecs.Ec2Service(this, 'AppService', {
  cluster: cluster,
  taskDefinition: taskDef,
  desiredCount: 2,
  deploymentConfiguration: {
    maximumPercent: 200,
    minimumHealthyPercent: 100,
  },
});
  • 负载均衡目标组层面:调整注销延迟时间,给正在处理的请求留足完成时间:
const targetGroup = new elbv2.ApplicationTargetGroup(this, 'AppTargetGroup', {
  port: 80,
  targetType: elbv2.TargetType.INSTANCE,
  deregistrationDelay: Duration.seconds(300), // 注销后继续接受请求的时长
  healthCheck: {
    interval: Duration.seconds(10),
    timeout: Duration.seconds(5),
  },
});

3. 优化ASG滚动更新配置

调整ASG滚动更新参数,确保新实例完全注册到ECS并通过健康检查后,再终止旧实例:

const asg = new autoscaling.AutoScalingGroup(this, 'EcsAsg', {
  // 其他基础配置(启动模板、实例类型等)
  updatePolicy: autoscaling.UpdatePolicy.rollingUpdate({
    minInstancesInService: 2, // 与服务最小运行实例数匹配
    maxBatchSize: 1,
    pauseTime: Duration.minutes(10), // 延长暂停时间,确保新实例完成ECS注册
    waitOnResourceSignals: true, // 可选:等待实例发送就绪信号(需在启动脚本中添加cfn-signal)
  }),
});

额外注意事项

  • 确保使用的ECS优化AMI包含最新版本的ecs-agent,旧版本可能存在注销逻辑bug
  • 手动触发ASG实例终止,验证生命周期钩子是否正常触发ECS排空流程
  • 监控ECS实例的DRAINING状态和ASG生命周期动作,排查超时或失败情况

内容的提问来源于stack exchange,提问作者nicou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 16:00:27