亚马逊AWS官方博客
Amazon EKS 集群快速缩容指定节点实例的最佳实践
![]() |
在现代云计算环境中,Kubernetes 已成为管理容器化应用程序的主流平台。Amazon EKS(Elastic Kubernetes Service)为用户提供了一个托管的 Kubernetes 服务,使得部署和管理 Kubernetes 集群变得更加高效和便捷。
在实际运维过程中,随着业务需求的变化,灵活地调整集群资源至关重要。其中,节点实例的数量是确保资源利用率和成本效益的关键因素。EKS 提供了两种类型的节点组:托管节点组和非托管节点组。通过调整节点组的数量,我们可以轻松地扩展或缩减集群的规模。 另外我们可以使用 Cluster Autoscaler 自动扩展和缩减节点,这种方式非常适合根据负载动态调整集群规模。但是,如果我们需要快速缩容指定的节点,例如由于某些原因需要隔离或下线并替换特定节点, 传统的手动或自动缩容功能是没有办法满足这种需求。在这种情况下,我们需要一种更加灵活的方式来实现快速缩容指定节点的目标。
EKS 的托管节点组或非托管节点组实际是在操作 EC2 Auto Scaling Group(ASG),在本篇博客中,我将介绍几种基于 ASG 的可行方案,并对它们进行比较和总结,最后给出建议的最佳实践方案。
方案介绍
基于 ASG 缩容指定节点组的方案主要有下面 4 种:
- 使用 Auto Scaling Group 设置缩容保护 – 可以防止特定实例在缩容过程中被意外终止。这对于关键应用程序或重要服务的节点尤其重要。启用缩容保护后,这些节点将不会被 ASG 自动终止,从而确保它们的可用性和稳定性。
- 使用 Auto Scaling Group 的分离实例功能 – 允许您将特定节点从 ASG 中分离,而不是直接终止它们。这样做的好处是,您可以在不影响 ASG 的情况下,保留实例以供后续使用或进行维护。这种方法适合需要临时下线某些节点但不希望完全删除它们的场景。
- 使用 Auto Scaling Group 自定义缩容策略 – 可以根据特定条件和优先级来控制哪些实例被终止。这种灵活性使得您能够根据业务需求、节点健康状态或其他指标来制定更智能的缩容决策。例如,可以设置优先终止低负载或非关键服务的节点,从而最大限度地减少对业务的影响。
- 使用 Auto Scaling Group 的终止实例功能 – 直接选择要终止的节点。这种方式简单直接,适合在需要快速释放资源时使用。用户可以通过 AWS 管理控制台或 AWS CLI 进行操作。
前置条件
在开始之前,请确保您具备以下条件:
- 具有基于 Unix 的操作系统 – 如 Linux、MacOS 或 Windows 子系统 for Linux 的访问权限
- 已安装 AWS CLI 命令工具
- 已安装 kubectl 命令行工具
- 已安装 eksctl 命令行工具
- 已创建 eks 集群并配置好节点组
准备工作
在缩容之前,我们首先需要将被缩容的节点实例进行排空,将节点上面的业务 Pod 驱逐,这里需要注意根据业务的优先级和重要性等因素考虑副本数量、亲和度和 Pod Disruption Budget(PDB)等设置,从而减少因为 Pod 重新调度带来的业务影响。
我们首先获取集群中所有节点的列表:
- 从列表中找到您想要删除的节点名称
- 使用
kubectl drain
命令将节点上的所有 Pod 驱逐到其他节点上
注意替换 <node-name>
为您要删除的节点名称, 如果要对多个节点进行操作用空格分开。--ignore-daemonsets
参数可以忽略驱逐 DaemonSet 控制的 Pod。
使用 Auto Scaling Group 设置缩容保护
缩容保护可以设置在 Auto Scaling Group 或特定的实例上。我们建议在 Auto Scaling Group 上启用实例缩容保护设置,以便在实例启动后立即对其进行保护。当实例状态变为 InService 时,缩容保护将自动启用。若要控制哪些实例可以被终止,可以禁用特定实例的缩容保护设置。这样,仍然可以保护某些实例,防止它们被意外终止。
![]() |
先为 Auto Scaling Group 设置缩容保护。
新建的 Auto Scaling Group:
已有的 Auto Scaling Group(注意如更新已有的 Auto Scaling Group 只会对新启动的实例生效):
根据业务需求获取需要缩容的实例清单列表,然后为这些实例设置禁用缩容保护(注意每次最多只能提供 50 个实例):
缩容节点组可以使用 awsli 或 eksctl,下面是 awsli 的例子:
注意事项:
如果 Auto Scaling 组中的所有实例都受到保护,无法进行缩容,并且发生了缩减事件,则所需容量会减少。但在禁用实例缩减保护之前,Auto Scaling 组无法终止所需数量的实例。在活动历史记录中,如果所有实例都受到保护,缩减事件发生时不会缩小,会显示以下消息:“无法缩减到所需容量,因为所有剩余实例都受到保护。”
实例缩减保护不适用于以下情况:
- 实例未通过健康检查时的替换。
- 竞价型实例中断,当容量不再可用或超出最高价格时。
- 容量块预留结束时,即使这些实例受到保护。
- 手动终止实例,包括使用
terminate-instance-in-auto-scaling-group
命令或通过控制台、CLI 和 API 操作。
使用 Auto Scaling Group 的分离实例功能
与上一种方案类似,我们也可以直接利用 Auto Scaling Group 的 detach instance 功能将指定节点从组中分离。该操作也是直接缩容 Auto Scaling Group 的实例来实现缩容。这种方式的也是可以批量操作多个节点, 缩容过程可以自动化完成。但是这里需要注意的是 detach instance 并不会终止节点,只是将节点从 Auto Scaling Group 移除,还需要配合 terminate 操作的终止节点。同时为了防止在执行终止节点过程出现异常需要维护被 detach 的实例信息,以用于重试终止实例的操作。
![]() |
这种方案的步骤如下:
通过 AWS CLI 调用 detach-instances API,并配置 should-decrement-desired-capacity 参数, 在移除节点的同时自动缩减节点数量。注意 instance-ids 最多只能有 20 个。
待节点被 detach 后,再终止实例。
终止指定的实例。此操作是幂等的;如果您多次终止一个实例,每次调用都会成功。 如果您指定多个实例且请求失败(例如,由于单个实例 ID 不正确),则没有任何实例被终止。 如果您在多个可用区中终止多个实例,并且一个或多个指定的实例启用了终止保护,则请求将失败,结果如下:
- 与受保护实例位于同一可用区的指定实例不会被终止。
- 与受保护实例不在同一可用区的指定实例(且没有其他指定实例受到保护)将成功终止。
使用 Auto Scaling Group 自定义缩容策略
Auto Scaling 使用终止策略来确定在缩小 Auto Scaling 组规模时需要哪些实例。默认情况下, Auto Scaling 组采用默认的终止策略,但可以选择或创建自定义终止策略。这里我们创建一个自定义终止策略,该策略使用 AWS Lambda 函数,在特定事件发生时由 Amazon EC2 Auto Scaling 调用。我们创建的 Lambda 函数将处理 Amazon EC2 Auto Scaling 发送的输入数据,并返回一个准备好终止的实例列表。 自定义终止策略提供了更好的控制,允许我们决定哪些实例被终止以及何时终止。
例如我们创建一个 Lambda 函数,该函数会根据 EC2 的 tag 返回需要终止的实例列表。创建好 Lambda 函数后,注意需要在基于资源的策略部分选择“添加权限”,基于资源的策略用于授予指定在策略中的主体调用函数的权限。在这个例子中,主体将是与 Auto Scaling 组关联的 Amazon EC2 Auto Scaling 服务链接角色。详细步骤请参考文档。
Lambda 的 playload 包含有关 Amazon EC2 Auto Scaling 需要终止的容量信息、建议终止的实例列表以及触发终止的事件。需要注意的是在由于缩减规模事件和基于实例刷新的终止导致实例终止时,保持可用区之间的平衡是首要考虑的。因此,如果某个可用区的实例数量超过其他可用区,则输入数据仅包含来自不平衡可用区的可终止实例。如果所有可用区的实例数量相对均衡,则输入数据将包含该组所有可用区中的实例。
在使用自定义终止策略时,请注意以下事项:
- Lambda 函数限制 – 在 Auto Scaling 组的终止策略中只能指定一个 Lambda 函数。如果指定了多个终止策略,Lambda 函数必须排在首位。
- 实例数量限制 – 输入数据中提供的实例数量限制为 30,000 个。如果可终止的实例超过 30,000 个,输入数据将包含
"HasMoreInstances": true
,以指示返回了最大数量的实例。 - Lambda 函数最大运行时间 – 您的 Lambda 函数最大运行时间为两秒(2000 毫秒)。作为最佳实践,您应根据预期运行时间设置 Lambda 函数的超时值。Lambda 函数的默认超时为三秒,但可以减少。
- 超时处理 – 如果运行时间超过 2 秒,任何缩减操作将被暂停,直到运行时间降至此阈值以下。对于运行时间持续较长的 Lambda 函数,应寻找减少运行时间的方法,例如缓存结果,以便在后续 Lambda 调用中检索。
使用 Auto Scaling Group 的终止实例功能
终止指定的实例,并可选择调整所需的组大小。此调用仅发起终止请求,实例不会立即终止。当实例被终止时,其状态会更改为“已终止”。 这里注意需要指定减少所需容量的选项(should-decrement-desired-capacity),不然 Amazon EC2 Auto Scaling 将启动新实例来替换已终止的实例。
需要注意这种方式一次只能缩容一个节点,如果要缩容的节点数量多,需要多次调用缩容 api 并有可能导致 api 限流。
缩容速度测试
我们这里模拟一个缩容场景,节点组包含 250 个实例(规格为 t3.medium),将需要缩容的实例(200 台)打上标签 should-scale-in=ture,分别用 4 种方法测试下缩容的耗时。下表是缩容消耗的时间的对比,可以看到批量缩容采用自定义策略(Lambda 函数)方案,速度最快。终止实例的方案由于每次只能缩容一台,速度最慢。分离实例的方案可以分成两个步骤,不考虑终止实例的情况下缩容时间可以更短。
方案 | 缩容耗时 | 说明 |
设置缩容保护 | 170s | 包含了 set-instance-protection(15s),缩容时间包括第一个节点开始缩容和最后一个节点缩容完毕。虽然一次性缩容 200 台实例,但是后台是分批执行的。 |
分离实例 | 164s | 缩容+从 Auto Scaling Group 分离实例 76s,终止实例 88s。 |
自定义缩容策略 | 146s | 一次请求包含 200 个实例,Auto Scaling Group 实际上也是分批处理。 |
终止实例 | 373s | 每次只能终止并缩容一台实例。 |
总结
方案 | 优点 | 缺点 |
设置缩容保护 | 操作简单 | 需要手动操作每个节点 |
detach instance | 可自动化批量操作 | 需要编写代码或脚本 |
自定义缩容策略 | 高度可定制化 | 实现复杂,需要 Lambda 函数 |
终止实例 | 操作简单 | 一个命令只能终止一台实例 |
综合考虑上述三种方案的优缺点,如果只是偶尔需要缩容少量节点,那么使用设置缩容保护的方式就已经足够了,操作简单且无需编写代码。
但如果需要经常性地缩容节点,特别是大量节点的情况,建议使用 detach instance 的方式。通过编写脚本或代码来自动化整个过程,可以大大提高效率,减少人工操作的工作量。
如果对缩容规则有特殊的定制需求,比如根据节点的标签、运行的工作负载等条件来决定是否缩容,那么自定义缩容策略就是不二之选。虽然实现相对复杂,但它提供了最大的灵活性。
因此,我们的建议是:
- 如果只是偶尔缩容少量节点,使用设置缩容保护即可;
- 如果需要经常性地缩容大量节点,使用 detach instance 方式自动化操作;
- 如果有特殊的缩容规则需求,使用自定义缩容策略并编写 Lambda 函数。
以上就是关于在 EKS 集群中快速缩容指定节点的几种可行方案和建议。在实际应用中,可以根据具体的业务场景和需求来选择最合适的方案。