

# 安全停止在 EC2 实例上运行的 Amazon ECS 工作负载
<a name="managed-instance-draining"></a>

托管实例耗尽有助于优雅终止 Amazon EC2 实例。这使您的工作负载可以安全停止并重新安排到非终止实例。执行基础设施维护和更新时无需担心工作负载中断。通过使用托管实例耗尽功能，您可以简化需要更换 Amazon EC2 实例的基础设施管理工作流程，同时确保应用程序的恢复能力和可用性。

Amazon ECS 托管实例耗尽与自动扩缩组实例替换配合使用。根据实例刷新和最长实例生命周期，客户可以确保其容量符合最新的操作系统和安全规定。

托管式实例耗尽功能只能与 Amazon ECS 容量提供程序结合使用。您可以在使用 Amazon ECS、AWS CLI 或 SDK 创建或更新自动扩缩组容量提供程序时，开启托管式实例耗尽功能。

Amazon ECS 托管实例耗尽涵盖了以下事件。
+ [自动扩缩组实例刷新](https://docs.aws.amazon.com/autoscaling/ec2/userguide/asg-instance-refresh.html) – 使用实例刷新来滚动替换自动扩缩组中的 Amazon EC2 实例，而不是手动批量替换。当您需要替换大量实例时，这将有用。实例刷新是通过 Amazon EC2 控制台或 `StartInstanceRefresh` API 启动的。如果您使用托管终止保护，则请确保在调用 `StartInstanceRefresh` 时为横向缩减保护选择 `Replace`。
+ [最长实例生命周期](https://docs.aws.amazon.com/autoscaling/ec2/userguide/asg-max-instance-lifetime.html) – 在替换自动扩缩组实例时，您可以定义最长生命周期。这有助于根据内部安全策略或合规性安排替换实例。
+ 自动扩缩组横向缩减 – 根据扩缩策略和计划的扩缩操作，自动扩缩组支持自动扩缩实例。通过将自动扩缩组用作 Amazon ECS 容量提供程序，您可以在自动扩缩组实例中没有任务运行时横向缩减这些实例。
+ [自动扩缩组运行状况检查](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-health-checks.html) –自动扩缩组支持许多运行状况检查，以管理运行不正常的实例的终止。
+ [CloudFormation 堆栈更新](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-direct.html) – 您可以向 CloudFormation 堆栈添加 `UpdatePolicy` 属性，以便在组更改时执行滚动更新。
+ [竞价型容量再平衡](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-interruptions.html) – 自动扩缩组尝试根据 Amazon EC2 容量再平衡通知主动替换中断风险较高的竞价型实例。替换实例启动且正常运行后，自动扩缩组会终止旧实例。Amazon ECS 托管式实例耗尽功能会像耗尽非竞价型实例一样耗尽竞价型实例。
+ [Spot 中断](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-capacity-rebalancing.html) – 竞价型实例将在通知两分钟后终止。Amazon ECS 托管实例耗尽会将实例置于耗尽状态作为响应。

**Amazon EC2 Auto Scaling 生命周期挂钩（托管实例耗尽）**  
自动扩缩组生命周期挂钩使客户能够创建由实例生命周期中的特定事件触发的解决方案，并在该特定事件发生时执行自定义操作。一个自动扩缩组最多允许 50 个挂钩。可存在多个终止挂钩并可并行执行，自动扩缩组会等待所有挂钩完成后再终止实例。

除了 Amazon ECS 托管挂钩终止外，您还可以配置自己的生命周期终止挂钩。生命周期挂钩有 `default action`，建议将 `continue` 设置为默认操作，以确保其他挂钩（例如 Amazon ECS 托管式挂钩）不会受到自定义挂钩的任何错误的影响。

如果您已经配置了自动扩缩组终止生命周期挂钩并启用了 Amazon ECS 托管式实例耗尽功能，则两个生命周期挂钩都将执行。但不能保证相对时间。生命周期挂钩有一个 `default action` 设置，用于指定超时过后要采取的操作。如果失败，则建议使用 `continue` 作为自定义挂钩中的默认结果。这样可以确保其他挂钩（尤其是 Amazon ECS 托管式挂钩）不会受到自定义生命周期挂钩中任何错误的影响。`abandon` 的替代结果会导致跳过所有其他挂钩，因此应避免使用。有关自动扩缩组生命周期挂钩的更多信息，请参阅《Amazon EC2 Auto Scaling 用户指南》**中的 [Amazon EC2 Auto Scaling 生命周期挂钩](https://docs.aws.amazon.com/autoscaling/ec2/userguide/lifecycle-hooks.html)。

**任务和托管实例耗尽**  
Amazon ECS 托管实例耗尽使用容器实例中现有的耗尽功能。[容器实例耗尽](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/container-instance-draining.html)功能对属于 Amazon ECS 服务的副本任务执行替换和停止。处于 `PENDING` 或 `RUNNING` 状态的独立任务（如由 `RunTask` 调用的任务）将不受影响。您必须等待这些任务完成或手动停止这些任务。容器实例将保持 `DRAINING` 状态，直到所有任务均已停止或经过 48 小时。进程守护程序任务是在所有副本任务停止后最后停止的任务。

**托管实例耗尽和托管终止保护**  
即使禁用了托管终止，托管式实例耗尽功能也会起作用。有关托管式终止保护的信息，请参阅 [控制 Amazon ECS 终止的实例](managed-termination-protection.md)。

下表总结了托管终止和托管耗尽不同组合的行为。


|  托管终止  |  托管耗尽  |  结果  | 
| --- | --- | --- | 
|  已启用  | 已启用 | Amazon ECS 可保护正在运行任务的 Amazon EC2 实例不被横向缩减事件终止。任何正在终止的实例（例如未设置终止保护、已收到 Spot 中断或因实例刷新而强制终止的实例）都将正常地耗尽。 | 
|  已禁用  | 已启用 | Amazon ECS 无法保护运行任务的 Amazon EC2 实例免于横向缩减。但是，任何正在终止的实例都会正常地耗尽。 | 
|  已启用  | 已禁用 | Amazon ECS 可保护正在运行任务的 Amazon EC2 实例不被横向缩减事件终止。但是，实例仍可能因 Spot 中断、强制实例刷新或其未运行任何任务而终止。Amazon ECS 不会对这些实例执行正常耗尽，并在其停止后启动替换服务任务。 | 
|  已禁用  | 已禁用 | Amazon EC2 实例可以随时进行横向缩减或终止，即使其正在运行 Amazon ECS 任务。Amazon ECS 将在替换服务任务停止后启动这些任务。 | 

**托管式实例耗尽和竞价型实例耗尽**  
使用竞价型实例耗尽功能，您可以在 Amazon ECS 代理上设置环境变量 `ECS_ENABLE_SPOT_INSTANCE_DRAINING`，这样 Amazon ECS 就可以将实例置于耗尽状态，以应对两分钟的 Spot 中断。Amazon ECS 托管实例耗尽有助于正常关闭因多种原因而正在终止的 Amazon EC2 实例，而不仅仅是 Spot 中断。例如，您可以使用 Amazon EC2 Auto Scaling 容量再平衡来主动替换中断风险较高的竞价型实例，托管式实例耗尽会正常关闭替换的竞价型实例。使用托管式实例耗尽功能时，您无需单独启用竞价型实例耗尽功能，因此自动扩缩组用户数据中的 `ECS_ENABLE_SPOT_INSTANCE_DRAINING` 是冗余的。有关竞价型实例耗尽的更多信息，请参阅 [竞价型实例](create-capacity.md#container-instance-spot)。

## 托管式实例耗尽功能如何与 EventBridge 结合使用
<a name="managed-instance-draining-eventbridge"></a>

Amazon ECS 托管实例耗尽事件会发布到 Amazon EventBridge，并且 Amazon ECS 会在您账户的默认总线中创建 EventBridge 托管规则以支持托管实例耗尽。您可以将这些事件筛选到 Lambda、Amazon SNS 和 Amazon SQS 等其他 AWS 服务，以进行监控和问题排查。
+ Amazon EC2 Auto Scaling 在调用生命周期挂钩时向 EventBridge 发送事件。
+ Spot 中断通知已发布到 EventBridge。
+ Amazon ECS 会生成错误消息，您可以通过 Amazon ECS 控制台和 API 来检索这些消息。
+ EventBridge 内置了重试机制，可以缓解临时故障。

# 配置 Amazon ECS 容量提供程序，以安全关闭实例
<a name="enable-managed-instance-draining"></a>

使用 Amazon ECS 控制台和 AWS CLI 创建或更新自动扩缩组容量提供程序时，您可以开启托管式实例耗尽功能。

**注意**  
创建容量提供程序时，默认情况下，托管式实例耗尽功能已开启。

以下是使用 AWS CLI 创建启用托管实例耗尽功能的容量提供程序，以及为集群的现有容量提供程序启用托管实例耗尽功能的示例。

**创建启用托管实例耗尽功能的容量提供程序**  
要创建启用托管实例耗尽功能的容量提供程序，请使用 `create-capacity-provider` 命令。将 `managedDraining` 参数设置为 `ENABLED`。

```
aws ecs create-capacity-provider \
--name capacity-provider \
--auto-scaling-group-provider '{
  "autoScalingGroupArn": "asg-arn",
  "managedScaling": {
    "status": "ENABLED",
    "targetCapacity": 100,
    "minimumScalingStepSize": 1,
    "maximumScalingStepSize": 1
  },
  "managedDraining": "ENABLED",
  "managedTerminationProtection": "ENABLED",
}'
```

响应：

```
{
    "capacityProvider": {
        "capacityProviderArn": "capacity-provider-arn",
        "name": "capacity-provider",
        "status": "ACTIVE",
        "autoScalingGroupProvider": {
            "autoScalingGroupArn": "asg-arn",
            "managedScaling": {
                "status": "ENABLED",
                "targetCapacity": 100,
                "minimumScalingStepSize": 1,
                "maximumScalingStepSize": 1
            },
            "managedTerminationProtection": "ENABLED"
            "managedDraining": "ENABLED"
        }
    }
}
```

**为集群的现有容量提供程序启用托管实例耗尽功能**  
使用 `update-capacity-provider` 命令为集群的现有容量提供程序启用托管实例耗尽功能。您会看到 `managedDraining` 目前显示为 `DISABLED` 而 `updateStatus` 显示为 `UPDATE_IN_PROGRESS`。

```
aws ecs update-capacity-provider \
--name cp-draining \
--auto-scaling-group-provider '{
  "managedDraining": "ENABLED"
}
```

响应：

```
{
    "capacityProvider": {
        "capacityProviderArn": "cp-draining-arn",
        "name": "cp-draining",
        "status": "ACTIVE",
        "autoScalingGroupProvider": {
            "autoScalingGroupArn": "asg-draining-arn",
            "managedScaling": {
                "status": "ENABLED",
                "targetCapacity": 100,
                "minimumScalingStepSize": 1,
                "maximumScalingStepSize": 1,
                "instanceWarmupPeriod": 300
            },
            "managedTerminationProtection": "DISABLED",
            "managedDraining": "DISABLED" // before update
        },
        "updateStatus": "UPDATE_IN_PROGRESS", // in progress and need describe again to find out the result
        "tags": [
        ]
    }
}
```



使用 `describe-clusters` 命令并包含 `ATTACHMENTS`。托管实例耗尽 attachment 的 `status` 为 `PRECREATED`，总体 `attachmentsStatus` 为 `UPDATING`。

```
aws ecs describe-clusters --clusters cluster-name --include ATTACHMENTS
```

响应：

```
{
    "clusters": [
        {
            ...

            "capacityProviders": [
                "cp-draining"
            ],
            "defaultCapacityProviderStrategy": [],
            "attachments": [
                # new precreated managed draining attachment
                {
                    "id": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
                    "type": "managed_draining",
                    "status": "PRECREATED",
                    "details": [
                        {
                            "name": "capacityProviderName",
                            "value": "cp-draining"
                        },
                        {
                            "name": "autoScalingLifecycleHookName",
                            "value": "ecs-managed-draining-termination-hook"
                        }
                    ]
                },

                ...

            ],
            "attachmentsStatus": "UPDATING"
        }
    ],
    "failures": []
}
```

更新完成后，使用 `describe-capacity-providers`，您将看到 `managedDraining` 现在为 `ENABLED`。

```
aws ecs describe-capacity-providers --capacity-providers cp-draining
```

响应：

```
{
    "capacityProviders": [
        {
            "capacityProviderArn": "cp-draining-arn",
            "name": "cp-draining",
            "status": "ACTIVE",
            "autoScalingGroupProvider": {
                "autoScalingGroupArn": "asg-draning-arn",
                "managedScaling": {
                    "status": "ENABLED",
                    "targetCapacity": 100,
                    "minimumScalingStepSize": 1,
                    "maximumScalingStepSize": 1,
                    "instanceWarmupPeriod": 300
                },
                "managedTerminationProtection": "DISABLED",
                "managedDraining": "ENABLED" // successfully update
            },
            "updateStatus": "UPDATE_COMPLETE",
            "tags": []
        }
    ]
}
```

## 排查 Amazon ECS 托管式实例耗尽问题
<a name="managed-instance-troubleshooting"></a>

您可能需要对托管式实例耗尽问题进行排查。以下是您在使用它时可能遇到的问题和解决方法的示例。

**使用自动扩缩时，实例不会在超过最大实例生命周期后终止。**  
如果您的实例在使用自动扩缩组时达到并超过了实例的最大生命周期后仍未终止，则可能是因为它们受到了防止横向缩减的保护。您可以关闭托管式终止并允许托管耗尽功能来处理实例回收。

## Amazon ECS 托管实例的耗尽行为
<a name="managed-instances-draining-behavior"></a>

Amazon ECS 托管实例终止可确保工作负载正常过渡，同时优化成本并保持系统正常运行。终止系统为实例终止提供了三种不同的决策路径，每种路径都有不同的时间特征和客户影响概况。

### 终止决策路径
<a name="managed-instances-termination-paths"></a>

客户发起的终止  
当您需要立即从服务中移除容器实例时，可直接控制实例移除。您可以调用 DeregisterContainerInstance API 并将 force 标志设置为 true，表示尽管有工作负载正在运行，但仍需要立即终止。

系统发起的空闲终止  
Amazon ECS 托管实例通过终止未运行任何任务的闲置 Amazon ECS 容器实例，持续监控并主动优化成本。ECS 使用启发式延迟让容器实例有机会在终止之前获取新启动的任务。可以使用 `scaleInAfter` Amazon ECS 托管实例容量提供程序配置参数进行自定义。

基础设施刷新终止  
Amazon ECS 托管实例会自动管理和更新托管容器实例上的软件，进而确保安全性和合规性，同时保持工作负载可用性。有关更多信息，请参阅 [Amazon ECS 托管实例修补](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/managed-instances-patching.html)。

### 正常耗尽和工作负载迁移
<a name="managed-instances-draining-coordination"></a>

正常耗尽系统实施与 Amazon ECS 服务管理的复杂协调，确保服务管理的任务从计划终止的实例中正确迁移。

**服务任务耗尽协调**  
当实例转换为 DRAINING 状态时，Amazon ECS 计划程序会自动停止在实例上放置新任务，同时对现有服务任务实施正常关闭过程。服务任务耗尽包括与服务部署策略、运行状况检查要求和您的耗尽偏好进行协调，以确保最佳迁移时间和成功率。

**独立任务处理**  
独立任务需要不同的处理方式，因为它们不能从自动服务管理中受益。该系统评估独立任务特征，包括任务持续时间估计、完成概率分析和客户影响评估。正常完成策略允许独立任务在较长的宽限期内自然完成，而强制终止可确保在任务未自然完成时在可接受的时间范围内进行基础设施刷新。

### 两阶段完成策略
<a name="managed-instances-two-phase-completion"></a>

终止系统实施一种两阶段方法，在工作负载连续性和基础设施管理要求之间取得平衡。

**第 1 阶段：正常完成时间段**  
在此阶段，系统实施正常耗尽策略，优先考虑工作负载连续性。服务任务会通过正常的 Amazon ECS 计划流程正常耗尽，独立任务继续运行并可能会自然完成，系统会监控所有任务是否通过自然完成流程达到停止状态。

**第 2 阶段：强制执行硬性截止日期**  
当正常完成无法在可接受的时间范围内实现终止目标时，系统将强制执行硬性截止日期。硬性截止日期通常设定为启动时间加上七天，这样既能为正常完成留出充足的时间，又能满足运营要求。强制执行包括自动调用强制注销过程，以及无论完成状态如何都立即终止所有剩余任务。