原文链接:
https://medium.com/adevinta-tech-blog/the-karpenter-effect-redefining-our-kubernetes-operations-80c7ba90a599
编译:CloudPilot AI
Adevinta 是天下最大的在线分类广告商之一,其业务遍布环球9个国家及地区,每个月吸引超过 1.2 亿用户和 100 万家企业,2023 财年总营业额达 18 亿欧元。本文将先容 Adevinta 迁移至 Karpenter 的落地实践。
在 Adevinta 内部,已经对 Karpenter 的特性和它办理关键运维难题的潜力感到兴奋已久。如今,Adevinta 已经完成了从 Amazon EKS 托管节点组到 Karpenter 的全面迁移,现在正是总结这段历程并分享其中经验的最佳时机。
题目概述
管理一个由 2,000 多个 Kubernetes 节点、30 个集群构成的庞大体系,并服务于 25 个差异的市场,这绝非易事。固然一开始使用 Kubernetes Cluster Autoscaler 和 Amazon EKS 托管节点组表现良好,但随着时间推移,Adevinta 逐渐碰到了阻碍服从和扩展性的运维难题。
集群升级的复杂性、实例类型选择的范围性,以及用例灵活性不敷等题目,越来越成为 Adevinta 的负担。团队迫切必要一个能够正面办理这些寻衅的办理方案。
引入 Karpenter
Karpenter 是一款开源的高性能 Kubernetes 主动扩缩容工具,现在已捐献给 CNCF。与传统的主动扩缩差异,Karpenter 能够动态地在实时环境中为集群工作负载提供所需的盘算资源。它通过观察未调度 pod 的资源请求总量,智能决议并启动精准匹配需求的新节点。
Karpenter 项目地址:
https://github.com/kubernetes-sigs/karpenter
集群升级与维护变得轻松自若
过去,升级 Kubernetes 集群是一件令人头疼的事,尤其是在使用 EKS 托管节点组并通过 AWS CDK 举行资源设置时。控制平面与节点组升级之间的紧密耦合,使整个过程轻易报错。任何题目,比如设置错误或实例资源短缺,都会导致升级失败并陷入回滚的循环。
对于大型集群,这一寻衅更加艰巨。升级数百个节点同时将影响降到最低可能必要好几天,工程师必须全程密切监控。这不仅耗费时间和资源,而且常常由于实例可用性等外部因素导致失败,使升级过程更加复杂。
更新节点组时的硬依赖会导致整个升级回滚并卡住
失败原因不可控
为缓解这些风险,Adevinta 曾在执行 Kubernetes 升级前实施容量预留。然而,这种方法服从低下且缺乏可扩展性。
引入 Karpenter 后,升级流程变得更加简单。控制平面与节点池升级实现了解耦,使控制平面的升级变得更加简单,大多数升级可在 15 到 30 分钟内完成。Karpenter 异步管理工作节点的升级,当控制平面版本更新时,它会检测到 AMI(Amazon Machine Image)的变化,并通过标记为“漂移”的方式识别必要升级的节点。- {"level":"INFO","EC2NodeClass":{"name":"default"},"parameter":"/aws/service/eks/optimized-ami/1.30/amazon-linux-2-arm64/recommended/image_id","value":"ami-0d494a2874a2e7ec1"}
- {"level":"INFO","EC2NodeClass":{"name":"default"},"namespace":"","name":"default","reconcileID":"b99dbc2a-5112-4121-ab64-7e512bb0399f","parameter":"/aws/service/eks/optimized-ami/1.30/amazon-linux-2-gpu/recommended/image_id","value":"ami-01389330bfd276054"}
复制代码
一旦检测到新的 AMI,Karpenter 就会将现有版本标记为漂移,并开始主动升级。
漂移的节点会逐步被新版本替换,无需人工干预。这种分离极大地降低了升级所需的工作量,而且不再必要持续监控。
对中断的精细化控制
Karpenter 对 Pod 中断预算(PDB)的严格服从,为 Adevinta 的运维带来了显著改进。此前,即便启用了序列化选项(serialised option),Cluster Autoscaler 仍会在短时间超时后强制移除节点,导致服务频繁中断。而现在,Karpenter 能在设定的中断范围内从容应对,极大地减少了服务影响。
Adevinta 曾在使用托管节点组时碰到题目,例如重命名节点组或调整副本最小数目,这些操作经常引发比预期更严重的中断。这种环境让升级过程变得“鸡飞狗跳”,还经常引发故障,影响了客户的正常使用。这种不可猜测性让 Adevinta 对升级望而却步,因为它们通常会导致计划外的停机并增加额外的工作负担。
更多节点同时中断,导致应用步调停机
由于多种原因,受管理的节点群受到的干扰可能比我们预期的要大
通过 Karpenter,Adevinta 在节点中断管理方面获得了更大的掌控力,尤其是在升级过程中。其焦点优势之一是可以灵活设置中断预算(Disruption Budget),精准控制节点更新的频率。例如,可以设置每 15 分钟仅更新一个节点的策略,大幅降低对运行服务的影响。这种渐进、可控的方式确保了服务稳固性,将升级过程中的停机时间降到最低,办理了过去的一浩劫题。
Karpenter 的另一大优势在于其在差异节点池类型间设置中断预算的灵活性。Adevinta 现在可以根据工作负载的紧张性分配差异级别的可靠性要求。对于关键任务工作负载,严格限定节点中断;而对于非关键任务工作负载,则采取更宽松的限定,从而在集群内实现资源的最优管理与服务的高可靠性。
中断预算设置答应在 15 分钟窗口期内最多中断一个实例
Karpenter 的中断预算与用户设置的 Pod 中断预算(PDB)紧密共同,确保升级过程中的高可靠性。例如,在设定的 15 分钟窗口内,如果 PDB 要求不答应任何节点中断,Karpenter 将跳过该窗口,确保服务的持续稳固。这种机制在多租户场景下尤为紧张,因为它能够完全满意用户对可靠性的严格要求,确保服务始终处于高可用状态。
一个节点每 15 分钟中断一次,但如果 PDB 所需的时间超过 15 分钟,Karpenter 会等待下一个窗口再举行尝试。
别的,在 v1 版本中,Karpenter 支持针对差异类型的中断原因(如节点合并、节点过期或规格变更)指定差异的时间窗口。这种精细化管理使 Adevinta 能在保持高可用性的同时,顺遂完成须要的维护工作,从而在稳固性与维护服从之间实现了良好的均衡。- apiVersion: karpenter.sh/v1
- kind: NodePool
- metadata:
- name: default
- spec:
- template:
- spec:
- expireAfter: 720h # 30 * 24h = 720h
- disruption:
- consolidationPolicy: WhenEmptyOrUnderutilized
- budgets:
- - nodes: "20%"
- reasons:
- - "Empty"
- - "Drifted"
- - nodes: "5"
- - nodes: "0"
- schedule: "@daily"
- duration: 10m
- reasons:
- - "Underutilized"
复制代码 Karpenter 还支持一种名为“双跳”(double jump)的升级策略。在“双跳”过程中,Adevinta 可以连续升级 EKS 控制平面两个版本,只需举行一次集群重建。具体做法是,将 Karpenter 设置为在控制平面升级期间答应节点数为零,待控制平面连续升级两个版本后,再移除设置。这种方式有用简化了升级流程,大幅提升了升级服从,同时减少了中断风险。- disruption:
- budgets:
- {{- if has .Values.clusterName .Values.featureFlags.blockDisruption }}
- - nodes: "0"
- {{- end }}
复制代码 当 Karpenter 检测到 Kubernetes 新版本时,它会主动将所有节点标记为漂移状态。因此,如果某个节点被标记为漂移节点,替换的节点将使用 Karpenter 在启动时发现的最新 AMI。例如,版本为 1.28 的节点将被升级到 1.30 版本的 AMI。
这一简单的功能大大节省了运维时间,因为通常举行一次全面集群升级必要几周的规划和执行。通过“双跳”策略,即使在严格的限定条件下,我们也能避免不须要的全体节点重建。尽可能避免中断 Pod,减少对用户的干扰,始终是最佳选择。
灵活选择实例类型,办理资源瓶颈
过去,选择实例类型是一个繁琐的过程。每个节点组都必要明确指定实例类型,而且必须严格满意资源需求。固然使用云服务提供商意味着可以动态调度机器,但并不代表始终拥有无限的资源,尤其是在较小的区域,当出实际例资源耗尽的环境时,升级操作往往会失败。
实例耗尽的报错提示
在 AutoScalingGroup 中,存在辅助实例类型(secondary instance types)的概念,答应用户提供替代实例类型的列表以及节点组规格。然而,这个过程依然是手动的,轻易堕落且具有很多限定。例如,替代实例类型必须与主实例类型在 CPU 和内存上保持一致。随着规模的扩大,管理这一过程几乎成了一场噩梦。
添加辅助实例类型
Karpenter 通过让用户定义实例需求而非指定实例类型,成功抽象化了这种复杂性。Karpenter 会主动选择最合适且最经济的实例类型。这种灵活性不仅简化了管理工作,另有用降低了实例资源耗尽的风险,这对于 Adevinta 这样的规模来说尤为紧张。
CloudPilot AI 的智能节点选择功能可以进一步优化 Karpenter 的动态实例选择,智能匹配超过750种实例类型,为用户的工作负载主动匹配多样化的实例类型,以减少资源浪费,提升盘算性能,增强应用稳固性。
另一个额外的好处是,当有更好、更便宜或性能更强的实例类型可用时,Adevinta 不再必要时候监控或举行 2000 多台机器的全体重建。Karpenter 会主动、渐进地完成这一过程,确保资源的持续优化。
针对差异工作负载定制节点池
在 Adevinta 的环境中,Karpenter 最紧张的优势之一就是能够创建定制化的节点池,以满意差异工作负载的需求。对于管理一个多样化的应用生态体系来说,每个应用都有独特的资源需求和操作特性,这种灵活性至关紧张。
通过 Kubernetes CRD 简化节点池创建
Karpenter 使用 Kubernetes 自定义资源定义(CRD)来定义资源调度活动,使节点池的创建变得更加简单,尤其是对于熟悉 Kubernetes 的用户。通过定义 Provisioner CRD,Adevinta 可以指定约束条件和优先级,例如:
- 实例类型与系列: 选择广泛的 EC2 实例类型或系列,以匹配差异工作负载的需求。
- 节点标签与污点: 为节点分配标签和污点,以控制 Pod 调度,确保工作负载摆设到合适的节点。
- Kubelet 设置: 自定义 kubelet 参数,以优化节点性能,满意特定应用的需求。
这种方法使 Adevinta 能以声明的方式管理节点设置,减少了维护多个 Auto Scaling Groups 或托管节点组的复杂性,尤其是在处理差异工作负载时。
满意特定工作负载需求
以下是 Adevinta 怎样使用 Karpenter 来适应差异工作负载的几个实际示例:
1. GPU 密集型机器学习任务
Adevinta 的数据科学团队经常运行必要 GPU 加快的机器学习模子。过去,Adevinta 必要维护专门的 GPU 节点组,但这些节点组往往未得到充分使用且成本较高。借助 Karpenter,Adevinta 可以定义一个 Provisioner,设置如下规格:
- 资源需求:节点必须具备 GPU 能力(例如,NVIDIA Tesla V100)。
- 实例类型:优先选择 g4dn 实例系列。
- 污点与标签:应用污点,确保只有 GPU 工作负载被调度到这些节点上。
当有 Pod 请求 GPU 资源,而且该 Pod 满意我们指定的污点容忍条件时,Karpenter 会动态地为其设置一个 GPU 支持的节点。一旦工作负载完成,如果不再必要该节点,该节点可以被开释。这种动态扩展方式优化了资源的使用率,降低了成本,同时,通过污点和标签的设置,确保工作负载能够被调度到与所需资源匹配的节点类型上。
2. 专用节点用于监控和日志网络
Adevinta 的监控栈,包括 Prometheus 和日志网络器,受益于与其他工作负载的隔离,以避免资源争用、Pod 更替频繁和可能出现的“邻人噪声”效应(即当同一物理服务器上的其他用户突然占用更多的资源,如CPU、内存或I/O,可能会导致整个服务器性能下降,进而影响到所有用户)。通过使用 Karpenter,Adevinta 能够设置一个 Provisioner,具体设置如下:
- 盘算优化:选择针对内存密集型工作负载优化的实例类型(例如,r5 系列)。
- 应用特定标签和污点:确保只有监控和日志网络的 Pod 被调度到这些节点。
- 自定义 kubelet 设置:主动调整设置,例如 kubelet 最大 Pod 数目和驱逐策略。
这种隔离有用稳固了 Adevinta 的监控服务,并减少了“邻人噪声”效应,避免了资源密集型工作负载影响同一节点上其他工作负载的性能。例如,将 Prometheus 工作负载隔离到专用节点上,不仅提升了性能,还带来了额外的成本节省。
增强稳固性的附加功能
像定义 startupTaints 这样的功能也非常宝贵。它们让 Adevinta 在调度 Pod 之前,能够提前准备好节点上的关键组件——例如 IAM 代理。这大大减少了由于应用步调被调度到尚未完全启动的节点上而导致的间歇性故障。通过确保节点在担当工作负载之前完全准备好,Adevinta 提升了服务的团体稳固性和可靠性。
通过 Kyverno 策略提供灵活性
为了无缝地向客户提供这种灵活性,Adevinta 使用了 Kyverno 策略。这些策略根据节点选择器主动为 Pod 分配容忍性,简化了用户的操作,并最小化了设置错误的风险。
例如,考虑以下 Kyverno 策略:- apiVersion: kyverno.io/v1
- kind: ClusterPolicy
- metadata:
- name: enforce-gpu-taint
- spec:
- validationFailureAction: Enforce
- background: false
- rules:
- - name: enforce-gpu-t4-taint
- match:
- any:
- - resources:
- kinds:
- - Pod
- preconditions:
- all:
- - key: "{{ request.object.spec.nodeSelector."alpha.gpu.node.x.io/nvidia-gpu-name" || '' }}"
- operator: Equals
- value: "t4"
- mutate:
- patchesJson6902: |-
- - path: "/spec/tolerations/-"
- op: add
- value:
- key: "alpha.gpu.node.schip.io/nvidia-gpu-name"
- operator: "Equal"
- value: "t4"
- effect: "NoSchedule"
- - name: enforce-gpu-a10g-taint
- match:
- any:
- - resources:
- kinds:
- - Pod
- preconditions:
- all:
- - key: "{{ request.object.spec.nodeSelector."alpha.gpu.node.x.io/nvidia-gpu-name" || '' }}"
- operator: Equals
- value: "a10g"
- mutate:
- patchesJson6902: |-
- - path: "/spec/tolerations/-"
- op: add
- value:
- key: "alpha.gpu.node.schip.io/nvidia-gpu-name"
- operator: "Equal"
- value: "a10g"
- effect: "NoSchedule"
- - name: enforce-gpu-taint
- match:
- any:
- - resources:
- kinds:
- - Pod
- preconditions:
- all:
- - key: "{{ request.object.spec.nodeSelector."accelerator.node.x.io/gpu" || '' }}"
- operator: Equals
- value: "true"
- mutate:
- patchesJson6902: |-
- - path: "/spec/tolerations/-"
- op: add
- value:
- key: "accelerator.node.schip.io/gpu"
- operator: "Exists"
- effect: "NoSchedule"
复制代码 优势与寻衅
Kyverno 为 Adevinta 带来了显著的优势:
- 简化用户体验: 通过 Kyverno 主动根据节点选择器分配容忍性,用户无需深入了解 Kubernetes 调度的复杂性即可摆设工作负载。用户只需指定需求,策略会主动处理剩余部分。
- 一致且正确的调度: 主动化容忍性分配确保 Pod 被调度到正确的节点,并具备相应的污点。这保持了我们已创建的隔离和性能优化,减少了 Pod 被调度到不得当节点的风险。
- 降低设置错误风险: 通过主动处理容忍性,减少了人为错误的可能性,例如忘记包含须要的容忍性,这可能导致 Pod 无法调度或被错误调度。
通过将 Kyverno 策略与 Karpenter 的资源设置能力结合,Adevinta 使客户能够轻松使用 Kubernetes 的高级功能。这种协同作用提升了用户体验,优化了资源使用,同时保持了 Adevinta 的高性能和高可靠性标准。
主动化安全更新
安全至关紧张,而保持我们的 Amazon Machine Images(AMIs)更新曾是一个繁琐且耗时的手动过程。借助 Karpenter,AMI 更新现在可以无缝处理。当新的 AMI 发布时,Karpenter 会识别出漂移的节点并逐步替换它们,同时服从 PDB(Pod Disruption Budget)和中断策略。这一主动化过程确保了我们的集群始终保持最新的安全补丁,而无需人工干预。
过去,由于无法持续检查更新,Adevinta 并未积极更新 AMI。同时,之前的架构每次更新都必要举行全量集群重建,这会带来更多的中断。
通过实例优化实现显著的成本节省
今年,Adevinta 团队的一个关键目标是成本优化。他们发现,将实例从 Intel 迁移到 AMD 实例,可以在不影响性能的前提下,每月节省多达 30,000 欧元。
然而,手动在数千个节点之间执行此迁移是不可行的。
Karpenter 让这一迁移变得轻松无比。通过选择符合 Adevinta 需求的最具成本效益的实例,Karpenter 自然偏向于使用 AMD 实例,而不是 Intel 实例,从而立即带来了成本节省。
这一优势是在 Adevinta 迁移到 Karpenter 的过程中实现的,展示了它在无需额外干预的环境下,怎样同时提供运维服从和财务收益。
Karpenter 迁移后,使用 AMD CPU 可节省的费用数据
增强的度量指标与洞察
Karpenter 提供了大量以前难以获取的度量指标。从漂移检测和节点中断次数,到合并变乱和 Pod 调度时间,这些洞察信息非常宝贵。它们使 Adevinta 能够做出数据驱动的决议,并在题目升级之前主动办理潜在的题目。
Karpenter 公开了很多对决议和可观察性至关紧张的指标
在使用托管节点组时,Adevinta 只能通过 AutoScalingGroups 获取关于节点的度量指标,而这些指标并非集群本身的原生指标。因此,这些数据并不敷以帮助 Adevinta 明确在诸如升级或合并等变乱期间,节点的活动和变化。
本文为 Adevinta 落地实践的上半部分,先容了他们怎样使用 Karpenter 为运维团队减负、增强应用稳固性以及实现成本优化。下周我们将发布下半部分,先容 Adevinta 在迁移之路上踩过的坑以及他们是怎样办理的。敬请期待!
关注「CloudPilot AI」,获取 Karpenter 落地实践不迷路。
推荐阅读
CloudPilot AI携手阿里云发布Karpenter阿里云 Provider,优化ACK集群主动扩展
1000+节点、200+集群,Slack怎样使用Karpenter降本增效?
阿迪达斯怎样降低50%的K8s集群成本?
公司先容
云妙算(CloudPilot.ai)是一家环球领先的 Karpenter 托管云服务提供商,致力于通过智能化、主动化的云资源调度和编排技术,帮助企业最大化云资源使用率。我们秉持“让客户在云中耗费的每一分钱都物超所值”的使命,为客户提升10倍的资源服从,同时将云成本降低50%以上。
现在,开源K8s弹性伸缩器 Karpenter 已为环球超500家知名企业在生产环境中提供服务,包括阿迪达斯、Anthropic、Slack、Figma等。云妙算已为数十家环球顶尖科技公司提供服务,累计为客户节省超过30万美金,平均节省67%。 选择云妙算,让每一笔支出都更智慧。
免费试用,2步5分钟,降低50%云成本:
cloudpilot.ai
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |