3大战略+1款东西,在K8s上搞定使用零宕机
原文链接:
https://jaadds.medium.com/building-resilient-applications-on-kubernetes-9e9e4edb4d33
翻译:cloudpilot.ai
Kubernetes 供给的某些特功用够协助企业充分使用云原生运用的优势,例如无需封闭整个集群即可更改基础设施、主动修正运用程序以及依据流量进行动态扩展。
可是,正是这种动态特性引发了一个问题:Kubernetes 是否满意安稳,能够运转那些使命要害型、高吞吐量的运用程序?
例如,Pod 随时或许呈现毛病,这意味着流量和用户体会或许会受到影响。虽然在装备不妥的状况下的确会产生这种状况,但经过正确的探针、Pod 分配战略以及扩展选项,任何运用程序都能够在 Kubernetes 上稳健运转。
本文中,咱们将评论怎么削减宕机时刻并介绍一款开源东西协助您进步在 Kubernetes 上运转的运用程序的弹性。
装备健康探针(Probe)
健康探针用于奉告用户 Kubernetes 操控平面运用程序是否健康、是否准备好接纳流量或仍处于发动状况。正确装备的健康探针能够进步运用程序的呼应才干,而装备不妥则或许导致不必要的宕机。
健康探针常常是简略装备过错的部分,因而了解不同类型健康探针的作用十分重要。
不同探针的作用
-
安排妥当探针(Readiness Probe): 在将流量路由到 Pod 之前进行检查。假设安排妥当探针检测失利,Pod 将不再接纳流量。
-
存活探针(Liveness Probe): 用于判别 Pod 内的容器是否正常运转。假设存活探针检测失利,容器将被从头发动。
安排妥当探针
当 Pod 彻底发动并准备好接纳流量时,安排妥当探针才会经过检测。假设需求经过发动缓存或初始化数据库衔接池来预热运用程序,请在安排妥当探针检测之前完结这些操作。
只要当您的 Pod 经过 Kubernetes 服务对外供给流量时,才需求装备安排妥当探针。假设您的 Pod 仅仅履行使命,例如运转批处理作业或从行列中消费数据,则不需求装备安排妥当探针。
安排妥当探针检测失利的状况
-
容器被过多的流量压垮,需求先完结当时恳求才干承受新的流量。
-
运用程序接纳到
SIGTERM
信号(咱们将在下一节中进一步评论这一点)。
挑选探针时的留意事项
检查 endpoint 和服务的 endpoint 坚持一致是一个不错的挑选;当恳求处理的 endpoint 被彻底占用时,发送给安排妥当探针的恳求也会失利,然后削减流量进入 Pod。
为了更好地评价运用程序的安排妥当状况,能够运用多种目标,例如数据库衔接池的使用率、正在运用的线程数以及并发恳求数。当这些目标显现运用程序现已到达负载极限时,您能够使安排妥当探针检测失利,以避免功用的进一步恶化。
依据服务的类型,您能够挑选运用指令、HTTP 探针、TCP 探针或 gRPC 探针。
需求留意的是,尽量避免运用 TCP 探针,由于它只检查服务是否能够经过端口拜访,不会深化到运用程序层面,因而不能正确反映运用程序是否能够承受新恳求。
一般状况下,Web 运用程序和露出 REST 或 GraphQL 接口的微服务/运用程序应运用 HTTP 探针。而关于运用 gRPC 接口的服务,则应运用 gRPC 探针。
几点主张
-
在运用程序代码中记载安排妥当探针的履行时刻。假设探针检测失利过于频频,有助于调整阈值。
-
避免在安排妥当探针中调用后端服务,由于这或许导致探针超时并检测失利。探针的意图是判别运用程序是否准备好接纳流量。假设后端服务呈现毛病,运用程序应该经过恰当的过错处理机制来应对。
-
假设运用程序彻底依靠后端服务,且需求在经过安排妥当探针前获取后端服务状况,请异步获取这些状况信息。
存活探针(Liveness Probe)
存活探针用于判别运用程序是否正在运转或存活。运用程序未准备好并不意味着它没有存活(它或许正在处理进行中的恳求,但暂时不承受新的恳求)。可是,假设运用程序不存活,那么它永久无法准备好接纳流量。
存活探针检测失利的状况
-
容器遇到了无法经过非重启办法处理的问题。
-
运用程序进入了冻住状况,无法经过等候或冷却康复。例如,由于数据库服务器呼应缓慢,数据库衔接池被阻滞。
-
与要害后端服务(如数据库或行列)的衔接失利,且无法在不重启的状况下从头树立衔接。
挑选探针时的留意事项
在我看来,只要当运用程序能够经过重启康复时,才应该运用存活探针。一个抱负的存活探针应回来十分简略(或硬编码)的呼应,除非运用程序呈现严重问题,不然不会导致探针失利。
假设您的运用程序需求经过重启来从头树立与后端服务(如数据库或行列)的衔接,那么在经过存活探针前检查这些衔接或许是个好做法。
不过需求留意的是,运用现代结构(如 Express、Spring Boot)开发的云原生运用一般不需求重启来从头树立衔接——处理后端衔接池的库一般能够主动完结此进程。假设您发现不需求存活探针,最好避免运用它。
留意事项
-
存活探针和安排妥当探针不应该运用相同的装备。这两个探针的要求不同,您在安排妥当探针中采纳的操作或许会导致存活探针过早报错。
-
假设有必要为两个探针运用相同的端点,请确保它们有不同的装备(如
initialDelay
、timeout
、period
等)。 -
Kubernetes 在履行探针时不确保次序,因而确保安排妥当探针先于存活探针失利。假设安排妥当探针答应三次失利,存活探针应忍受五次失利。
高雅处理 Pod 中止
Pod 中止时是恳求失利的另一个常见原因。除非能高雅地处理 Pod 的中止,不然发送到中止 Pod 的恳求或许会失利。
当 Pod 内的容器没有高雅地封闭(即忽然中止或溃散)时,正在处理中的恳求会受到影响。此外,与 pod 相关的 Kubernetes 服务目标会一向发送流量,直到运用程序退出,然后导致某些恳求收到“衔接回绝”的报错。
避免呈现此类突发毛病的办法是正确处理 SIGTERM
信号。为了了解其作业原理,让咱们具体看看 Pod 的中止生命周期。
-
当 Pod 被符号为删去时,kubelet 会调用 Pod 中界说的一切容器的
preStop
处理程序。一同,高雅中止周期(由terminationGracePeriodSeconds
界说)的倒计时也开端了。 -
在
prestop
钩子履行完毕后,kubelet 会向 Pod 内一切容器宣布SIGTERM
信号。SIGTERM
是恳求中止容器内运转的运用程序的信号。可是,运用程序在收到SIGTERM
后依然能够持续运转。 -
在高雅中止周期完毕后,kubelet 会向一切容器宣布
SIGKILL
信号。假设现已有正在运转的运用程序,该指令将使其中止运转。 -
Kubernetes 操控平面随后会移除 Pod,尔后,任何客户端都无法看到 Pod。
一般状况下,当 Pod 开端中止时,SIGTERM
是容器收到的第一个信号。假设指定了 prestop
处理器,它将优先被调用。在某些状况下,指定 prestop
处理器有助于完结 Pod 的高雅中止。
接下来,咱们将首要评论怎么处理 SIGTERM
信号,然后再了解 preStop
处理器怎么完结相同的作用。
处理 SIGTERM 信号
中止接纳流量的最牢靠办法是在 pod 开端中止时,经过捕捉 SIGTERM
信号使安排妥当探测器失利。
PS:妥善处理 SIGTERM 信号被认为是进步运用程序弹性的最重要环节。这是由于运用程序经过此信号得知自己即将被中止。Kubernetes 的动态特性要求它出于各种原因(如推出新运用版别、减缩副本、集群保护使命等)频频中止 pod。假设不处理 SIGTERM,您将为 Kubernetes 的动态特性损坏运用程序的安稳性埋下危险。
在收到 SIGTERM
后,运用程序需求捕获该信号并进行高雅封闭,具体步骤如下:
-
经过清晰符号条件或封闭承受恳求的线程池,使准备安排妥当探针失利。
-
让正在进行的恳求完结。
-
封闭任何双向衔接,如 WebSocket 或 gRPC。
-
封闭数据库衔接和行列衔接。
当安排妥当探针失利时,衔接到 Pod 的服务目标将不再将恳求发送到该 Pod 的 IP,这样能够当即削减流量。
要接纳 SIGTERM
信号,容器内的运用程序应该以进程 ID 1
运转。假设您运用脚原本发动运用程序,那么该脚本将是 PID 为 1 的进程。在这种状况下,您需求保存运用程序的 PID
,并运用该 PID
将 SIGTERM
信号转发回运用程序。
调整翻滚更新
在推出新版别运用程序时,也或许会呈现宕机。当布置被扩展到最大副本数并进行翻滚更新时,有资历处理流量的 Pod 或许会呈现毛病,导致某些恳求失利。
经过将 maxUnavailable
设置为 0,您能够确保在封闭任何现有 Pod 之前,先调度新 Pod。
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
请留意,一旦新 Pod 开端运转,旧 Pod 就会被封闭。操控平面并不会检查新 Pod 是否已准备好接纳流量。假设您需求在新 Pod 准备好接纳流量之前推迟中止旧 Pod,能够运用安排妥当门(readiness gates)。
现在,这一功用仅由 AWS 负载均衡器原生支撑。有关怎么在 AWS 负载均衡器中运用安排妥当门的更多信息,请检查AWS官方文档[1]
界说 Pod 中止预算
在进行集群保护使命时,例如更新 Kubernetes 版别或晋级集群节点,Pod 或许会被中止或从头调度到不同的节点。Pod 中止预算(Pod Disruption Budget, PDB)经过答应保存最小数量的 Pod,来保护布置不受这些中止的影响。以下装备表明在产生中止时,至少有 50% 的 Pod 处于可用状况:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: pdb-front–end
spec:
minAvailable: 50%
selector:
matchLabels:
app: front–end
假设您要保护的是无状况运用程序,最好运用百分比来表明 minAvailable
和 maxUnavailable
特点。由于跟着时刻的推移,运转运用程序所需的副本数量或许会添加,然后使 PDB 界说很快过期。
假设运用程序是有状况的,而且需求保护最低数量的 Pod 以到达基本要求,那么最好将特点指定为具体数字。
需求留意的是,并非一切中止都考虑 PDB。例如,运用 kubectl 删去布置并不会触发 PDB。一般,与节点相关的更改,如 kubectl delete
、kubectl drain
和 kubectl cordon
才会评价 PDB。这篇博客[2]具体评论了经过 PDB 的自愿中止。您还能够参阅 K8s 官方文档[3],以获取有关界说 PDB 的更多主张。
此外,开源K8s主动扩缩容东西 Karpenter 能够进一步赋能 PDB,它能够装备中止预算而且准确办理节点更新的速度。
例如,Karpenter 能够设置单个节点每15分钟更新一次,然后大大下降对运转服务的潜在影响。这种按部就班、可控的办法可确保服务坚持安稳,并最大极限地削减晋级期间的宕机时刻。
在节点之间分配 Pod
假设产生节点级毛病,将 Pod 散布在不同节点大将有助于削减毛病的影响。您能够经过运用 Pod 亲和性(Pod Affinity)或拓扑散布束缚(Topology Spread Constraints)来完结这一点。
Pod 反亲和性(Pod Anti-affinity)
经过运用反亲和性规矩,您能够指示 Kubernetes 调度器不要将两个 Pod 调度到同一个节点上。
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- transaction-service
topologyKey: kubernetes.io/hostname
依据这一规矩,标签为 app
且值为 transaction-service
的两个 Pod 将不会运转在具有相同 kubernetes.io/hostname
值的节点上。
依据您对这一行为的严厉程度,能够挑选 requiredDuringSchedulingIgnoredDuringExecution
或 preferredDuringSchedulingIgnoredDuringExecution
战略。当运用前者时,kube-scheduler
只要在满意条件的状况下才干调度 Pod。
假设找不到没有 transaction-service 运用的节点,它将等候新的节点可用。运用后者时,调度器会尽量避免将 transaction-service Pod 放置在同一节点上,但假设没有适宜的节点可用,它将违背条件进行调度。
拓扑散布束缚(Topology Spread Constraints)
假定您在一个保管的 Kubernetes 集群上运转,例如 EKS 或 AKS,而且需求将 Pod 均匀散布在不同的可用区(Availability Zones)中。您能够运用 topologySpreadConstraints
来完结这一点。
可用区是云基础设施供给商用来阻隔毛病的一种办法。经过在可用区之间涣散 Pod,能够使运用程序具有更高的可用性。
即便有恰当的反亲和性规矩将 Pod 放置在不同的节点上,您的运用程序也或许会被调度成如下状况:
经过界说如下的 topologySpreadConstraint
,您能够完结均匀散布:
topologySpreadConstraints:
- labelSelector:
matchLabels:
app: transaction-service
maxSkew: 1
topologyKey: topology.kubernetes.io/zone
matchLabelKeys:
- pod-template-hash
whenUnsatisfiable: DoNotSchedule
您或许会想知道,为什么在这种状况下不能运用反亲和性,只需将 Topology key 更改为 topology.kubernetes.io/zone
。假设不细心装备战略和参数,则会束缚运用程序的扩展性。例如,假设您仅仅简略地经过更改 Topology key 来更改咱们看到的反亲和性战略,那么您的运用程序将无法扩展到超越三个副本。
因而,当您的意图是将一个 Pod 与另一个 Pod 放在一同,或避免将 Pod 放在一一起,最好运用亲和;而运用拓扑散布束缚则能够在节点、可用区和区域之间分配 Pod。
凭借 Karpenter 进步运用弹性
Karpenter是一款开源的 Kubernetes 集群主动扩缩容东西。它能够经过调查不行调度的 Pod 的聚合资源恳求并做出发动和中止节点的决议计划,以最大极限地削减调度推迟,然后在几秒钟内(而不是几分钟)供给适宜的核算资源来满意您的运用程序的需求。
它依据 pod 的调度需求主动装备和撤销装备节点,然后完结高效扩展和本钱优化。它的主要功用包括:
-
监控 Kubernetes 调度器因资源束缚而无法调度的 pod。
-
评价无法调度 pod 的调度要求(资源恳求、节点挑选器、亲和力、忍受度等)。
-
供给满意这些 pod 要求的新节点。
-
在不再需求节点时将其移除。
2个月前,Karpenter 发布了 1.0(GA) 版别,在这一版别中 Karpenter 包括以下2个严重更新能够协助您进步运用弹性和安稳性:
1、按原因设置中止预算(Disruption Budget)
Karpenter 的中止操控在节约本钱和可用性方面现已是一项了不得的功用。Karpenter 会主动发现可中止的节点,并在需求时发动代替节点。
1.0 版引入了中止预算,可按原因(如未充分使用、闲暇或漂移)设置中止预算。该功用在对服务可用性要求极高的出产环境中十分要害。
假设您在“双十一”期间运转一个线上购物渠道。在流量高峰期,或许会兼并使用率低的节点以节约本钱,但这或许会无意间中止正在进行的买卖,然后导致糟糕的客户体会。
假设没有 Karpenter 合理的中止预算,则无法轻松避免此类状况。现在,您能够界说战略,在要害时期束缚节点兼并,而在非高峰期(如闪购或节假日促销)答应节点兼并,确保您的服务不中止并下降本钱。
2、新的高雅中止期限(Termination Grace Period)
安全性和合规性关于保护安稳、安全的 Kubernetes 环境至关重要。可是办理节点的生命周期以确保它们坚持合规性具有应战。
例如,假设您需求恪守严厉的安全和合规规则,您或许期望确保节点的运转时刻不超越预订的期限,以避免呈现潜在的缝隙。
在 Karpenter 1.0 之前,办理节点生命周期以满意这些规则需求手动操作或自界说主动化。terminationGracePeriod
经过强制履行节点的最长生命周期,主动中止和替换超越预订寿数的节点,然后完结了这一进程的主动化。
这能够避免运用过期或或许不合规的节点,确保基础设施在无需人工监督的状况下坚持安全和合规,并下降软件或装备过期的危险。
Karpenter 的这些严重更新意味着 K8s 集群的主动扩展正在向智能化跨进。
跟着越来越多的知名企业(如Slack、阿迪达斯、奥迪等)选用 Karpenter 来协助他们优化本钱,咱们能够预见:在未来,集群办理的复杂性将越来越主动化,然后使 DevOps 团队能够专心于更高层次的战略行动。
假设您正在寻求以更智能、主动化的办法优化 Kubernetes 基础设施,Karpenter + 云奇谋将您的绝佳挑选。
云奇谋经过智能节点挑选、Spot主动化及智能 AI 猜测功用,让用户能够选用最多样化的实例类型,最大化使用 Spot 实例而且提早猜测 Spot 实例中止时刻,下降运用50%以上的云本钱,一同确保运用安稳性。
结 论
虽然完结 Kubernetes 的弹性和零宕机布置似乎是不或许的,但经过精心规划和恰当装备,您能够使用该渠道的动态特性来运转要害使命运用程序。
经过选用本文介绍的战略——例如装备恰当的健康探针、高雅地处理 Pod 中止和界说 Pod 中止预算——您能够明显削减宕机时刻并进步运用程序的全体安稳性。此外,装备集群主动扩展东西 Karpenter 和 Pod 主动扩展能够更有效地应对流量激增。
跟着 Kubernetes 的不断发展,了解最新的功用和最佳实践将进一步增强您构建和保护弹性运用程序的才干。
💡引荐阅览
本钱立降50%!在EKS上凭借Karpenter布置大模型
奥迪凭借Karpenter为要害事务节约63%本钱
AWS月账单下降60%,揭秘咱们的FinOps改造之旅
引证链接
[1]
AWS官方文档: https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.1/deploy/pod_readiness_gate/[2]
这篇博客: https://medium.com/@xpiotrkleban/poddisruptionbudgets-situations-where-they-are-respected-and-ignored-in-kubernetes-29ebaabac175[3]
K8s 官方文档: https://kubernetes.io/docs/tasks/run-application/configure-pdb/