Airbnb的动态kubernetes集群扩缩容

简介: Airbnb的动态kubernetes集群扩缩容

本文介绍了Airbnb的集群扩缩容的演化历史,以及当前是如何通过Cluster Autoscaler 实现自定义扩展器的。最重要的经验就是Airbnb是如何一步步演化到当前架构的,其驱动因素又是什么。

译自:Dynamic Kubernetes Cluster Scaling at Airbnb

简介

Airbnb的基础设施的一个重要作用是保证云能够根据需要自动执行扩缩容。我们每天的流量波动都非常大,需要依靠动态扩缩容来保证服务的正常运行。


为了支持扩缩容,Airbnb使用了Kubernetes编排系统。并且使用了一种基于Kubernetes的服务配置接口,OneTouch,具体参见这里


本文中,我们将讨论如何使用Kubernetes Cluster Autoscaler来动态调整集群的大小,并着重介绍了我们为Sig-Autoscalsing社区做出的贡献。

Airbnb的Kubernetes集群

过去几年中,Airbnb已经将绝大部分手动编排的EC2实例中迁移到了Kubernetes上。如今,我们在近百个集群中运行了上千个节点来容纳这些负载。然而,这些变化并不是一蹴而就的。在迁移过程中,底层的Kubernetes集群也同样进行着演进。随着新技术栈上的负载和流量越来越多,Kubernetes集群也随之变得越来越成熟。这些演进可以划分为如下几个阶段:

  • 阶段1:异构集群,手动扩容
  • 阶段2:多集群类型,独立扩缩容
  • 阶段3:异构集群,自动扩缩容

阶段1:异构集群,手动扩缩容

在使用Kubernetes之前,每个服务实例都运行在其所在的机器上,通过手动分配足够的容量来满足流量增加的场景。每个团队的容量管理方式都不尽相同,且一旦负载下降,很少会取消配置。


一开始我们的Kubernetes集群的配置相对比较简单。我们有少量集群,每个集群都有单独的底层节点类型和配置,用于运行无状态的线上服务。随着服务开始迁移到Kubernetes,我们开始在一个多租户(一个节点有多个pods)环境中运行容器化的服务。这种聚合方式减少了资源浪费,并且可以将这些服务的容量管理整合到Kuberentes控制平面上。在这个阶段,我们实现了集群的手动扩缩容,但相比之前仍然有着显著的提升。

阶段2:多集群类型,独立扩缩容

集群配置的第二个阶段是伴随多负载类型出现的,每个试图在Kubernetes上运行的负载都有着不同的需求。为了符合这些需求,我们创建了一个抽象的集群类型。"集群类型"定义了集群的底层配置,这意味着相同集群类型的集群,从节点类型到集群组件设置都是相同的。


越来越多的集群类型导致出现了越来越多的集群,一开始通过手动方式来调节每个集群容量的方式迅速变得支离破碎。为了修正这个问题,我们为每个集群添加了Kubernetes Cluster Autoscaler 。该组件会基于pod requests来动态调节集群的大小。如果一个集群的容量被耗尽,则会通过添加一个新的节点(由Cluster Autoscaler拉起)来满足pending状态的pods。类似地,如果在一段时间内集群的某些节点的利用率偏低,则Cluster Autoscaler会移除这些节点。这种方式行之有效,为我们节省了大约5%的总云开销,以及手动扩展集群的操作开销。

阶段3:异构集群,自动扩缩容

当Airbnb的几乎所有在线计算都转移到Kubernetes时,集群的类型已经超过30,集群数目超过100。这种扩展使得Kubernetes集群管理相当乏味。例如,在集群升级时需要单独对每种类型的集群进行测试。


在第三个阶段,我们会通过创建异构集群来整合集群类型,使用单个Kubernetes控制平面来适应多种不同的工作负载。首先,这种方式极大降低了集群管理的开销,通过更少且更通用的集群减少了需要测试的配置数目。其次,随着Airbnb 的主要服务已经运行在了Kubernetes集群上,集群的效率可以为成本优化提供一个很大的杠杆。整合集群类型可以允许我们在每个集群中运行多种负载。这种聚合的负载类型(有些大,有些小)可以带来更好的封装和效率,以及更高的利用率。通过这种额外的负载灵活性,我们可以有更多的空间来在默认的Cluster Autoscaler扩展逻辑之外,实现成熟的扩缩容策略。特别地,我们计划实现与Airbnb特定业务逻辑相关的扩缩容逻辑。

随着对集群的扩展和整合,我们实现了异构(每个集群有多种实例类型),我们开始在扩展过程中实现特定的业务逻辑,并且意识到有必要对扩缩容的行为进行某些变更。下一节将描述我们是如何修改Cluster Autoscaler,使其变得更加灵活。

Cluster Autoscaler 的提升

自定义gRPC扩展器

我们对Cluster Autoscaler的最显著改进是提供了一种新方法来确定要扩展的节点组。在内部,Cluster Autoscaler会维护一系列映射到不同候选扩容对象的节点组,它会针对当前Pending(无法调度)的pods执行模拟调度,然后过滤掉不满足调度要求的节点组。如果存在Pending(无法调度)的pods,Cluster Autoscaler会尝试通过扩展集群来满足这些pods。所有满足pod要求的节点组都会被传递给称为Expander的组件。

Expander 负责基于运行要求进一步过滤节点组。Cluster Autoscaler有大量内置的扩展器选项,每个选型都有不同的处理逻辑。例如,默认是随机扩展器,它会随机选择可用的节点组。另一个是Airbnb 曾经使用过的优先级扩展器,它会基于用户指定的优先级列表来选择需要扩展的节点组。


当我们使用异构集群逻辑的同时,我们发现默认的扩展器无法在成本和实例类型选择上满足复杂的业务需求。


假设,我们想要实现一个基于权重的优先级扩展器。目前的优先级扩展器仅允许用户为节点组设置不同的等级,这意味着它会始终以确定的顺序来扩展节点组。如果某个等级有多个节点组,则会随机选择一个节点组。基于权重的优先级策略可以支持在同一个等级下设置两个节点组,其中80%的时间会扩展一个节点组,另外20%的时间会扩展另一个节点组。但默认并不支持基于权重的扩展器。


除了现有扩展器的某些限制外,还有一些操作上的考量:

  1. Cluster Autoscaler的发布流水线比较严格,在合并到上游之前,需要花时间来审核变更。但我们的业务逻辑和扩展策略是持续变化的。能够满足当前需求的扩展器并不一定能够满足未来的需求。
  2. 我们的业务逻辑是与Airbnb 关联的,其他用户则没有这种业务逻辑。因此我们实现的特定逻辑并不一定对上游用户有用。

至此,我们对Cluster Autoscaler中的新扩展器类型提出了一系列要求:

  1. 我们希望扩展器是可扩展的,能够被其他用户使用。其他用户在使用默认的Expanders 可能会遇到类似的限制,我们希望提供一个通用的解决方案,并回馈上游。
  2. 我们的方案应该能够独立于Cluster Autoscaler部署,进而允许我们响应快速变更的业务需求。
  3. 我们的方案应该能够融入Kubernetes Cluster Autoscaler生态,这样就无需一直维护一个Cluster Autoscale的fork库。

鉴于这些需求,我们提出了一种设计,将扩展职责从Cluster Autoscaler的核心逻辑中分离出来。我们设计了一种插件自定义扩展器,它实现了gRPC客户端(类似custom cloud provider),这种自定义扩展器分为两个组件。


第一个组件是内置到Cluster Autoscaler中的gRPC客户端。这种扩展器使用与Cluster Autoscaler中的其他扩展器相同的接口,负责将Cluster Autoscaler中的有效节点组信息转换为定义好的protobuf 格式(见下文),接收gRPC 服务端的输出,并将其转换为最终的可选列表,提供给Cluster Autoscaler进行扩容。

service Expander {
  rpc BestOptions (BestOptionsRequest) returns (BestOptionsResponse) 
}message BestOptionsRequest {
  repeated Option options;
map<string, k8s.io.api.core.v1.Node> nodeInfoMap;
}message BestOptionsResponse {
  repeated Option options;
}message Option {
// ID of node to uniquely identify the nodeGroup
string nodeGroupId;
int32 nodeCount;
string debug;
  repeated k8s.io.api.core.v1.Pod pod;
}

第二个组件是gRPC服务端,这需要由用户实现。该服务端作为一个独立的应用或服务。通过客户端传递的信息以及复杂的扩展逻辑来选择需要扩容的节点组。当前通过gRPC传递的protobuf 消息是 Cluster Autoscaler中传递给扩展器的内容的(略微)转换版本。


在前面的例子中,基于权重的随机优先级扩展器可以很容易地通过服务端来读取优先级列表,并通过confimap配置权重百分比来实现。

我们的实现还包含一个故障保护选项。建议使用该选项将多个扩展器作为参数传递给Cluster Autoscaler。使用该选择后,如果服务端出现故障,Cluster Autoscaler仍然能够使用一个备用的扩展器进行扩展。


由于服务端作为一个独立的应用,因此可以在Cluster Autoscaler外开发扩展逻辑,且gRPC服务端可以根据用户需求实现自定义,因此这种方案对整个社区来说也非常有用。


从2022年开始,Airbnb 已经在内部使用这种方案来扩缩容所有的集群,当中没有出现任何问题。它允许我们动态地选择何时去扩展特定的节点组来满足Airbnb 的业务需求。通过这种方式实现了最初的开发目标--可扩展的自定义扩展器。

其他方面的改进

在迁移到异构Kubernetes集群的过程中,我们发现了其他一些可以对Cluster Autoscaler进行改进的bug。以下简要介绍:

  • Early abort for AWS ASGs with no capacity: 断开Cluster Autoscaler中等待节点尝试通过调用AWS EC2端点来检查ASG是否具有容量的循环。当启用该功能时,用户可以更快地进行扩缩容。之前,使用优先级的用户在每次尝试ASG启动之间必须等待15分钟,然后才能尝试较低优先级的ASG。
  • Caching launch templates to reduce AWS API calls: 为AWS ASG Launch Templates引入缓存。该变更可以允许使用大量ASGs,这对于我们的通用集群策略至关重要。之前,对于空的ASGs,Cluster Autoscaler会反复调用AWS端点来启用模板,导致AWS API限流。

总结

在过去的四年中,在Kubernetes集群配置中,Airbnb已经走了很长的路。Airbnb在单个平台上拥有最大的计算量,这为提高效率提供了强大的整合杠杆,我们现在专注于推广我们的集群设置。通过在Cluster Autoscaler 中开发和引入更加成熟的扩展器,可以实现更加复杂、围绕成本和多实例类型的特定扩展策略,并将有用的特性回馈社区。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
2天前
|
Prometheus Kubernetes 监控
OpenAI故障复盘 - 阿里云容器服务与可观测产品如何保障大规模K8s集群稳定性
聚焦近日OpenAI的大规模K8s集群故障,介绍阿里云容器服务与可观测团队在大规模K8s场景下我们的建设与沉淀。以及分享对类似故障问题的应对方案:包括在K8s和Prometheus的高可用架构设计方面、事前事后的稳定性保障体系方面。
|
4天前
|
Kubernetes 网络协议 应用服务中间件
Kubernetes Ingress:灵活的集群外部网络访问的利器
《Kubernetes Ingress:集群外部访问的利器-打造灵活的集群网络》介绍了如何通过Ingress实现Kubernetes集群的外部访问。前提条件是已拥有Kubernetes集群并安装了kubectl工具。文章详细讲解了Ingress的基本组成(Ingress Controller和资源对象),选择合适的版本,以及具体的安装步骤,如下载配置文件、部署Nginx Ingress Controller等。此外,还提供了常见问题的解决方案,例如镜像下载失败的应对措施。最后,通过部署示例应用展示了Ingress的实际使用方法。
20 2
|
16天前
|
存储 Kubernetes 关系型数据库
阿里云ACK备份中心,K8s集群业务应用数据的一站式灾备方案
本文源自2024云栖大会苏雅诗的演讲,探讨了K8s集群业务为何需要灾备及其重要性。文中强调了集群与业务高可用配置对稳定性的重要性,并指出人为误操作等风险,建议实施周期性和特定情况下的灾备措施。针对容器化业务,提出了灾备的新特性与需求,包括工作负载为核心、云资源信息的备份,以及有状态应用的数据保护。介绍了ACK推出的备份中心解决方案,支持命名空间、标签、资源类型等维度的备份,并具备存储卷数据保护功能,能够满足GitOps流程企业的特定需求。此外,还详细描述了备份中心的使用流程、控制台展示、灾备难点及解决方案等内容,展示了备份中心如何有效应对K8s集群资源和存储卷数据的灾备挑战。
|
1月前
|
Kubernetes 监控 Cloud Native
Kubernetes集群的高可用性与伸缩性实践
Kubernetes集群的高可用性与伸缩性实践
74 1
|
2月前
|
JSON Kubernetes 容灾
ACK One应用分发上线:高效管理多集群应用
ACK One应用分发上线,主要介绍了新能力的使用场景
|
2月前
|
Kubernetes 持续交付 开发工具
ACK One GitOps:ApplicationSet UI简化多集群GitOps应用管理
ACK One GitOps新发布了多集群应用控制台,支持管理Argo CD ApplicationSet,提升大规模应用和集群的多集群GitOps应用分发管理体验。
|
2月前
|
Kubernetes Cloud Native 云计算
云原生之旅:Kubernetes 集群的搭建与实践
【8月更文挑战第67天】在云原生技术日益成为IT行业焦点的今天,掌握Kubernetes已成为每个软件工程师必备的技能。本文将通过浅显易懂的语言和实际代码示例,引导你从零开始搭建一个Kubernetes集群,并探索其核心概念。无论你是初学者还是希望巩固知识的开发者,这篇文章都将为你打开一扇通往云原生世界的大门。
147 17
|
2月前
|
Kubernetes Ubuntu Linux
Centos7 搭建 kubernetes集群
本文介绍了如何搭建一个三节点的Kubernetes集群,包括一个主节点和两个工作节点。各节点运行CentOS 7系统,最低配置为2核CPU、2GB内存和15GB硬盘。详细步骤包括环境配置、安装Docker、关闭防火墙和SELinux、禁用交换分区、安装kubeadm、kubelet、kubectl,以及初始化Kubernetes集群和安装网络插件Calico或Flannel。
208 4
|
2月前
|
Kubernetes 应用服务中间件 nginx
搭建Kubernetes v1.31.1服务器集群,采用Calico网络技术
在阿里云服务器上部署k8s集群,一、3台k8s服务器,1个Master节点,2个工作节点,采用Calico网络技术。二、部署nginx服务到k8s集群,并验证nginx服务运行状态。
984 1
|
2月前
|
Kubernetes Cloud Native 流计算
Flink-12 Flink Java 3分钟上手 Kubernetes云原生下的Flink集群 Rancher Stateful Set yaml详细 扩容缩容部署 Docker容器编排
Flink-12 Flink Java 3分钟上手 Kubernetes云原生下的Flink集群 Rancher Stateful Set yaml详细 扩容缩容部署 Docker容器编排
93 3

热门文章

最新文章

推荐镜像

更多