Descheduler 调度平衡器 Kubernetes 经常使用
从 kube-scheduler 的角度来看,它是经过一系列算法计算出最佳节点运转 Pod,当出现新的 Pod 启动调度时,调度程序会依据其过后对Kubernetes 集群的资源形容做出最佳调度选择,但是 Kubernetes集群是十分灵活的,由于整个集群范围内的变动,比如一个节点为了保养,咱们先执行了驱逐操作,这个节点上的一切 Pod会被驱逐到其余节点去,但是当咱们保养成功后,之前的 Pod 并不会智能回到该节点过去,由于 Pod一旦被绑定了节点是不会触发从新调度的,由于这些变动,Kubernetes 集群在一段期间内就或许会出现不平衡的形态,所以须要平衡器来从新平衡集群。
当然咱们可以去手动做一些集群的平衡,比如手动去删掉某些Pod,触发从新调度就可以了,但是显然这是一个繁琐的环节,也不是处置疑问的方式。为了处置实践运转中集群资源无法充沛应用或糜费的疑问,可以经常使用descheduler 组件对集群的 Pod 启动调度提升,descheduler可以依据一些规定和性能战略来协助咱们从新平衡集群形态,其外围原理是依据其战略性能找到可以被移除的 Pod 并驱逐它们,其自身并不会启动调度被驱逐的Pod,而是依托自动的调度器来成功,目前支持的战略有:
这些战略都是可以启用或许禁用的,作为战略的一局部,也可以性能与战略相关的一些参数,自动状况下,一切战略都是启用的。另外,还有一些通用性能,如下:
咱们可以经过如下所示的 DeschedulerPolicy 来性能:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"nodeSelector: prod=devevictLocalStoragePods: truemaxNoOfPodsToEvictPerNode: 40ignorePvcPods: falsestrategies:# 性能战略...
装置
descheduler 可以以 Job、CronJob 或许 Deployment 的方式运转在 k8s 集群内,雷同咱们可以经常使用 Helm Chart来装置 descheduler:
➜ helm repo add descheduler
经过 Helm Chart 咱们可以性能 descheduler 以 CronJob 或许 Deployment 方式运转,自动状况下descheduler 会以一个 critical pod 运转,以防止被自己或许 kubelet 驱逐了,须要确保集群中有system-cluster-critical 这个 Priorityclass:
➜ kubectl get priorityclass system-cluster-criticalNAMEVALUEGLOBAL-DEFAULTAGEsystem-cluster-critical2000000000false87d
经常使用 Helm Chart 装置自动状况下会以 CronJob 的方式运转,执行周期为 schedule: "*/2 * * **",这样每隔两分钟会执行一次性 descheduler 义务,自动的性能战略如下所示:
apiVersion: v1kind: ConfigMapmetadata:name: deschedulerdata:policy.yaml: |apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:LowNodeUtilization:enabled: trueparams:nodeResourceUtilizationThresholds:targetThresholds:cpu: 50memory: 50pods: 50thresholds:cpu: 20memory: 20pods: 20RemoveDuplicates:enabled: trueRemovePodsViolatingInterPodAntiAffinity:enabled: trueRemovePodsViolatingNodeAffinity:enabled: trueparams:nodeAffinityType:- requiredDuringSchedulingIgnoredDuringExecutionRemovePodsViolatingNodeTaints:enabled: true
经过性能 DeschedulerPolicy 的 strategies,可以指定 descheduler的执行战略,这些战略都是可以启用或禁用的,上方咱们会详细引见,这里咱们经常使用自动战略即可,经常使用如下命令间接装置即可:
➜ helm upgrade --install descheduler descheduler/descheduler --set image.repository=cnych/descheduler,podSecurityPolicy.create=false -n kube-systemRelease "descheduler" does not exist. Installing it now.NAME: deschedulerLAST DEPLOYED: Fri Jan 21 10:35:55 2022NAMESPACE: kube-systemSTATUS: deployedREVISION: 1NOTES:Descheduler installed as a cron job.
部署成功后会创立一个 CronJob 资源对象来平衡集群形态:
➜ kubectl get cronjob -n kube-systemNAMESCHEDULESUSPENDACTIVELAST SCHEDULEAGEdescheduler*/2 * * * *False127s31s➜ kubectl get job -n kube-systemNAMECOMPLETIONSDURATIONAGEdescheduler-273788761/172s79s➜ kubectl get pods -n kube-system -l job-name=descheduler-27378876NAMEREADYSTATUSRESTARTSAGEdescheduler-27378876--1-btjmd0/1Completed02m21s
反常状况下就会创立一个对应的 Job 来执行 descheduler 义务,咱们可以经过检查日志可以了解做了哪些平衡操作:
➜ kubectl logs -f descheduler-27378876--1-btjmd -n kube-systemI0121 02:37:10.1272661 named_certificates.go:53] "Loaded SNI cert" index=0 certName="self-signed loopback" certDetail="\"apiserver-loopback-client@1642732630\" [serving] validServingFor=[apiserver-loopback-client] issuer=\"apiserver-loopback-client-ca@1642732629\" (2022-01-21 01:37:09 +0000 UTC to 2023-01-21 01:37:09 +0000 UTC (now=2022-01-21 02:37:10.127237 +0000 UTC))"I0121 02:37:10.1273241 secure_serving.go:195] Serving securely on [::]:10258I0121 02:37:10.1273631 tlsconfig.go:240] "Starting DynamicServingCertificateController"I0121 02:37:10.1387241 node.go:46] "Node lister returned empty list, now fetch directly"I0121 02:37:10.1722641 nodeutilization.go:167] "Node is overutilized" node="master1" usage=map[cpu:1225m memory:565Mi pods:16] usagePercentage=map[cpu:61.25 memory:15.391786081415567 pods:14.545454545454545]I0121 02:37:10.1723131 nodeutilization.go:164] "Node is underutilized" node="node1" usage=map[cpu:675m memory:735Mi pods:16] usagePercentage=map[cpu:16.875 memory:9.542007959787252 pods:14.545454545454545]I0121 02:37:10.1723281 nodeutilization.go:170] "Node is appropriately utilized" node="node2" usage=map[cpu:975m memory:1515Mi pods:15] usagePercentage=map[cpu:24.375 memory:19.66820054018583 pods:13.636363636363637]I0121 02:37:10.1723401 lownodeutilization.go:100] "Criteria for a node under utilization" CPU=20 Mem=20 Pods=20I0121 02:37:10.1723461 lownodeutilization.go:101] "Number of underutilized nodes" totalNumber=1I0121 02:37:10.1723551 lownodeutilization.go:114] "Criteria for a node above target utilization" CPU=50 Mem=50 Pods=50I0121 02:37:10.1723601 lownodeutilization.go:115] "Number of overutilized nodes" totalNumber=1I0121 02:37:10.1723741 nodeutilization.go:223] "Total capacity to be moved" CPU=1325 Mem=3267772416 Pods=39I0121 02:37:10.1723991 nodeutilization.go:226] "Evicting pods from node" node="master1" usage=map[cpu:1225m memory:565Mi pods:16]I0121 02:37:10.1724851 nodeutilization.go:229] "Pods on node" node="master1" allPods=16 nonRemovablePods=13 removablePods=3I0121 02:37:10.1724951 nodeutilization.go:236] "Evicting pods based on priority, if they have same priority, they'll be evicted based on QoS tiers"I0121 02:37:10.1803531 evictions.go:130] "Evicted pod" pod="default/topo-demo-6bbf65d967-lzlfh" reason="LowNodeUtilization"I0121 02:37:10.1815061 nodeutilization.go:269] "Evicted pods" pod="default/topo-demo-6bbf65d967-lzlfh" err=<nil>I0121 02:37:10.1815411 nodeutilization.go:294] "Updated node usage" node="master1" CPU=1225 Mem=592445440 Pods=15I0121 02:37:10.1824961 event.go:291] "Event occurred" object="default/topo-demo-6bbf65d967-lzlfh" kind="Pod" apiVersion="v1" type="Normal" reason="Descheduled" message="pod evicted by sigs.k8s.io/deschedulerLowNodeUtilization"......
从日志中咱们就可以明晰的知道由于什么战略驱逐了哪些 Pods。
由于经常使用 descheduler 会将 Pod驱逐启动重调度,但是假设一个服务的一切正本都被驱逐的话,则或许造成该服务无法用。假设服务自身存在单点缺点,驱逐的时刻必需就会形成服务无法用了,这种状况咱们剧烈倡导经常使用反亲和性和多正原本防止单点缺点,但是假设服务自身就被打散在多个节点上,这些Pod 都被驱逐的话,这个时刻也会形成服务无法用了,这种状况下咱们可以经过性能 PDB(PodDisruptionBudget)对象来防止一切正本同时被删除,比如咱们可以设置在驱逐的时刻某运行最多只要一个正本无法用,则创立如下所示的资源清单即可:
apiVersion: policy/v1kind: PodDisruptionBudgetmetadata:name: pdb-demospec:maxUnavailable: 1# 设置最多无法用的正本数量,或许经常使用 minAvailable,可以经常使用整数或百分比selector:matchLabels:# 婚配Pod标签app: demo
关于 PDB的更多详细消息可以检查官网文档:。
所以假设咱们经常使用 descheduler 来从新平衡集群形态,那么咱们剧烈倡导给运行创立一个对应的 PodDisruptionBudget对象启动包全。
战略
PodLifeTime
该战略用于驱逐比 maxPodLifeTimeSeconds 更旧的 Pods,可以经过 podStatusPhases 来性能哪类形态的 Pods会被驱逐,倡导为每个运行程序创立一个 PDB,以确保运行程序的可用性,比如咱们可以性能如下所示的战略来驱逐运转超越7天的 Pod:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"PodLifeTime":enabled: trueparams:maxPodLifeTimeSeconds: 604800# Pods 运转最多7天
RemoveDuplicates
该战略确保只要一个和 Pod 关联的 RS、Deployment 或许 Job 资源对象运转在同一节点上。假设还有更多的 Pod 则将这些重复的 Pod启动驱逐,以便更好地在集群中扩散 Pod。假设某些节点由于某些要素解体了,这些节点上的 Pod 漂移到了其余节点,造成多个与 RS 关联的 Pod在同一个节点上运转,就有或许出现这种状况,一旦出现缺点的节点再次预备就绪,就可以启用该战略来驱逐这些重复的 Pod。
性能战略的时刻,可以指定参数 excludeOwnerKinds 用于扫除类型,这些类型下的 Pod 不会被驱逐:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"RemoveDuplicates":enabled: trueparams:removeDuplicates:excludeOwnerKinds:- "ReplicaSet"
LowNodeUtilization
该战略重要用于查找未充沛应用的节点,并从其余节点驱逐 Pod,以便 kube-scheudler从新将它们调度到未充沛应用的节点上。该战略的参数可以经过字段 nodeResourceUtilizationThresholds 启动性能。
节点的应用率无余可以经过性能 thresholds 阈值参数来确定,可以经过 CPU、内存和 Pods数量的百分比启动性能。假设节点的经常使用率均低于一切阈值,则以为该节点未充沛应用。
此外,还有一个可性能的阈值 targetThresholds,用于计算或许驱逐 Pods 的潜在节点,该参数也可以性能 CPU、内存以及 Pods数量的百分比启动性能。thresholds 和 targetThresholds 可以依据你的集群需求进执行态调整,如下所示示例:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"LowNodeUtilization":enabled: trueparams:nodeResourceUtilizationThresholds:thresholds:"cpu" : 20"memory": 20"pods": 20targetThresholds:"cpu" : 50"memory": 50"pods": 50
须要留意的是:
假设未指定任何资源类型,则自动是100%,以防止节点从未充沛应用变为适度应用。和 LowNodeUtilization 战略关联的另一个参数是numberOfNodes,只要当未充沛应用的节点数大于该性能值的时刻,才可以性能该参数来激活该战略,该参数关于大型集群十分有用,其中有一些节点或许会频繁经常使用或短期经常使用无余,自动状况下,numberOfNodes为0。
RemovePodsViolatingInterPodAntiAffinity
该战略可以确保从节点中删除违犯 Pod 反亲和性的 Pod,比如某个节点上有 podA 这个 Pod,并且 podB 和podC(在同一个节点上运转)具备制止它们在同一个节点上运转的反亲和性规定,则 podA 将被从该节点上驱逐,以便 podB 和 podC 运转反常运转。当podB 和 podC 曾经运转在节点上后,反亲和性规定被创立就会发送这样的疑问。
要禁用该战略,间接性能成 false 即可:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"RemovePodsViolatingInterPodAntiAffinity":enabled: false
RemovePodsViolatingNodeTaints
该战略可以确保从节点中删除违犯 NoSchedule 污点的 Pod,比如有一个名为 podA 的 Pod,经过性能容忍key=value:NoSchedule 准许被调度到有该污点性能的节点上,假设节点的污点随后被更新或许删除了,则污点将不再被 Pods的容忍满足,而后将被驱逐:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"RemovePodsViolatingNodeTaints":enabled: true
RemovePodsViolatingNodeAffinity
该战略确保从节点中删除违犯节点亲和性的 Pod。比如名为 podA 的 Pod 被调度到了节点 nodeA,podA 在调度的时刻满足了节点亲和性规定requiredDuringSchedulingIgnoredDuringExecution,但是随着期间的推移,节点 nodeA不再满足该规定了,那么假设另一个满足节点亲和性规定的节点 nodeB 可用,则 podA 将被从节点 nodeA 驱逐,如下所示的战略性能示例:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"RemovePodsViolatingNodeAffinity":enabled: trueparams:nodeAffinityType:- "requiredDuringSchedulingIgnoredDuringExecution"
RemovePodsViolatingTopologySpreadConstraint
该战略确保从节点驱逐违犯拓扑散布解放的 Pods,详细来说,它试图驱逐将拓扑域平衡到每个解放的 maxSkew 内所需的最小 Pod 数,不过该战略须要k8s 版本高于1.18能力经常使用。
自动状况下,此战略仅处置硬解放,假设将参数 includeSoftConstraints 设置为 True,也将支持软解放。
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"RemovePodsViolatingTopologySpreadConstraint":enabled: trueparams:includeSoftConstraints: false
RemovePodsHavingTooManyRestarts
该战略确保从节点中删除重启次数过多的 Pods,它的参数包括 podRestartThreshold(这是应将 Pod逐出的从新启动次数),以及包括InitContainers,它确定在计算中能否招思考初始化容器的从新启动,战略性能如下所示:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"RemovePodsHavingTooManyRestarts":enabled: trueparams:podsHavingTooManyRestarts:podRestartThreshold: 100includingInitContainers: true
过滤 Pods
在驱逐 Pods 的时刻,有时并不须要一切 Pods 都被驱逐,descheduler 提供了两种重要的方式启动过滤:命名空间过滤和优先级过滤。
命名空间过滤
该战略可以性能是蕴含还是扫除某些称号空间。可以经常使用该战略的有:
比如只驱逐某些命令空间下的 Pods,则可以经常使用 include 参数启动性能,如下所示:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"PodLifeTime":enabled: trueparams:podLifeTime:maxPodLifeTimeSeconds: 86namespaces:include:- "namespace1"- "namespace2"
又或许要扫除掉某些命令空间下的 Pods,则可以经常使用 exclude 参数性能,如下所示:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"PodLifeTime":enabled: trueparams:podLifeTime:maxPodLifeTimeSeconds: 86namespaces:exclude:- "namespace1"- "namespace2"
优先级过滤
一切战略都可以性能优先级阈值,只要在该阈值以下的 Pod 才会被驱逐,咱们可以经过设置thresholdPriorityClassName(将阈值设置为指定优先级类别的值)或thresholdPriority(间接设置阈值)参数来指定该阈值。自动状况下,该阈值设置为 system-cluster-critical 这个PriorityClass 类的值。
比如经常使用 thresholdPriority:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"PodLifeTime":enabled: trueparams:podLifeTime:maxPodLifeTimeSeconds: 86thresholdPriority: 10000
或许经常使用 thresholdPriorityClassName 启动过滤:
apiVersion: "descheduler/v1alpha1"kind: "DeschedulerPolicy"strategies:"PodLifeTime":enabled: trueparams:podLifeTime:maxPodLifeTimeSeconds: 86thresholdPriorityClassName: "priorityclass1"
不过须要留意不能同时性能 thresholdPriority 和 thresholdPriorityClassName,假设指定的优先级类不存在,则descheduler 不会创立它,并且会引发失误。
留意事项
当经常使用descheduler驱除Pods的时刻,须要留意以下几点: