乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • Kubernetes
  • Prometheus
  • ELK
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • Kubernetes
  • Prometheus
  • ELK
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • Docker

  • Golang

  • AIOps

  • Python

  • DevOps

  • Kubernetes

    • 什么是云原生?
    • Docker容器技术
    • Kubernetes简介
    • Kubernetes核心对象
    • Kubernetes集群管理
    • Kubernetes权限管理
    • Kubernetes工作负载管理
    • Kubernetes调度管理
      • 基本介绍
        • 1、Informer Path
        • 2、Scheduler Parh
        • 常用的预算策略有:
      • 优先级和抢占机制
      • 高级调度
        • nodeSelector
        • nodeName
        • nodeAffinity
        • podAffinity
        • podAntiAffinity
        • 污点调度
      • 重新调度
      • 总结
    • Kubernetes应用质量管理
    • Kubernetes数据持久化管理
    • Kubernetes应用访问管理
    • Kubernetes应用配置管理
    • Kubernetes有状态应用管理
    • Kubernetes 网络管理
    • Helm 应用包管理
  • Prometheus

  • ELK

  • 专栏
  • Kubernetes
乔克
2025-07-19
目录

Kubernetes调度管理

# 基本介绍

在日常工作中,每个机场都有调度室,用来管理飞机应该从哪里降落,停在什么地方。在 Kubernetes 也有这样的调度器,主要作用就是将 Pod 安排到合适的节点上。

Kubernetes 中的调度器是 kube-scheduler,起工作流程如下:

  1. 在集群中所有 Node 中,根据调度算法挑选出可以运行该 Pod 的所有 Node;
  2. 在上一步的基础上,再根据调度算法给筛选出的 Node 进行打分,筛选出分数最高的 Node 进行调度;
  3. 将 Pod 的 spec.nodeName 填上调度结果的 Node 名字;

其原理图如下:

[[附件/images/20e05099be08d7fe9f69c855e66b05fc_MD5.jpeg|Open: 1573178213038-f29ec980-dff4-4b92-a3f4-4deea9659c83.png]] ![[附件/images/20e05099be08d7fe9f69c855e66b05fc_MD5.jpeg]]

由上图可知,Kubernetes 的调度器核心是两个相互独立的控制循环。

# 1、Informer Path

其主要作用是启动一个 Informer 来监听 Etcd 中 Pod,Node,Service 等与调度器相关的 API 对象的变化。当一个 Pod 被创建出来后,就被通过 Informer Handler 将待调度的 Pod 放入调度队列中,默认情况下,Kubernetes 的调度策略是一个优先级队列,并且当集群信息发生变化的时候,调度器还会对调度队列里的内容进行一些特殊操作。而且 Kubernetes 的默认调度器还负责对调度器缓存(scheduler cache)进行更新,以执行调度算法的执行效率。

# 2、Scheduler Parh

其主要逻辑是不断从队列中出一个 Pod,然后调用 Predicates 进行过滤,然后得到一组 Node(也就是可运行 Pod 的所有 Node 信息,这些信息都是来自 scheduler cache),接下来调用 Priorities 对筛选出的 Node 进行打分,然后分数最高的 Node 会作为本次调度选择的对象。调度完成后,调度器需要将 Pod 的 spec.nodeName 的值修改为调度的 Node 名字,这个步骤称为 Bind。

但是在 Bind 阶段,Kubernetes 默认调度器只会更新 scheduler cache 中的信息,这种基于乐观假设的 API 对象更新方式被称为 Assume。在 Assume 之后,调度器才会向 API Server 发起更新 Pod 的请求,来真正完成 Bind 操作。如果本次 Bind 失败,等到 scheduler cache 更新之后又会恢复正常。

正是由于有 Assume 的原因,当一个 Pod 完成调度需要在某个 Node 节点运行之前,kubelet 还会进行一部 Admit 操作来验证该 Pod 是否能够运行在该 Node 上,作为 kubelet 的二次验证。

# 常用的预算策略有:

  • CheckNodeCondition

  • GeneralPredication:

    • HostName,
    • PodFitsHostPort,
    • MatchNodeSelector,
    • PodFitsResources
  • NoDiskConflict

# 优先级和抢占机制

正常情况下,当一个 Pod 调度失败后,它会被搁置起来,直到 Pod 被更新,或者集群状态发生变化,调度器才会对这个 Pod 进行重新调度。但是有的时候我们不希望一个高优先级的 Pod 在调度失败就被搁置,而是会把某个 Node 上的一些低优先级的 Pod 删除,来保证高优先级的 Pod 可以调度成功。

Kubernetes 中优先级是通过 ProrityClass 来定义,如下:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for high priority service pods only."
1
2
3
4
5
6
7

其中的 value 就是优先级数值,数值越大,优先级越高。优先级是一个 32bit 的整数,最大值不超过 10 亿,超过 10 亿的值是被 Kubernetes 保留下来作为系统 Pod 使用的,就是为了保证系统 Pod 不会被抢占。另外如果 globalDefault 的值设置为 true 的话表明这个 PriorityClass 的值会成为系统默认值,如果是 false 就表示只有在申明这个 PriorityClass 的 Pod 才会拥有这个优先级,而对于其他没有申明的,其优先级为 0。

如下定义 Pod 并定义优先级:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
    - name: nginx
      image: nginx
      imagePullPolicy: IfNotPresent
  priorityClassName: high-priority
1
2
3
4
5
6
7
8
9
10
11
12

上面的 PriotiryClassName 就是定义我们的 PriorityClass,当这个 Pod 提交给 Kubernetes 之后,Kubernetes 的 PriorityAdmissionController 会自动将这个 Pod 的 spec.priority 字段设置为我们定义的值。而当这个 Pod 拥有这个优先级之后,高优先级的 Pod 就可能比低优先级的 Pod 先出队,从而尽早完成调度。

而当一个高优先级的 Pod 调度失败后,其抢占机制就会被触发,这时候调度器就会试图从当前的集群中寻找一个节点,使得这个节点上的一个或多个低优先级的 Pod 被删除,然后这个高优先级的 Pod 就可以被调度到这个节点上。

当抢占发生时,这个高优先级 Pod 并不会立即调度到即将抢占的节点上,调度器只会将这个 Pod 的 spec.nominatedNodeName 的值设置为被抢占节点的 Node 名字,然后这个 Pod 会重新进入下一个调度周期,然后会在这个周期内决定这个 Pod 被调度到哪个节点上。在这个重新调度期间,如果有一个更高的优先级 Pod 也要抢占这个节点,那么调度器就会清空原 Pod 的 nominatedNodeName 的值,而更高优先级的 Pod 将会抢占这个值。

实现原理:

Kubernetes 用两个队列来实现抢占算法:ActiveQ 和 unschedulableQ。

  1. ActiveQ:凡是在 ActiveQ 里的 Pod,都是下一个周期需要调度的对象,所以当 Kubernetes 创建一个新的 Pod,这个 Pod 就会被放入 ActiveQ 里;
  2. unschedulableQ:专门用来存放调度失败的 Pod;

那么如果一个 Pod 调度失败,调度器就会将其放入 unschedulableQ 里,然后调度器会检查这个调度失败的原因,分析并确认是否可以通过抢占来解决此次调度问题,如果确定抢占可以发生,那么调度器就会把自己缓存的所有信息都重新复制一份,然后使用这个副本来模拟抢占过程。如果模拟通过,调度器就会真正开始抢占操作了:

  1. 调度器会检查牺牲者列表,清空这些 Pod 所携带的 nominatedNodeName 字段;
  2. 调度器会把抢占者的 nominatedNodeName 的字段设置为被抢占的 Node 名字;
  3. 调度器会开启 Goroutine,同步的删除牺牲者;

接下来调度器就会通过正常的调度流程,把抢占者调度成功。在这个过程中,调度器会对这个 Node,进行两次 Predicates 算法:

  1. 假设上述抢占者已经运行在这个节点上,然后运行 Predicates 算法;
  2. 调度器正常执行 Predicates 算法;

只有上述者两个都通过的情况下,这个 Node 和 Pod 才会被 绑定。

# 高级调度

上面介绍的是 Kubernetres 默认的调度策略,有时候默认的调度策略不能满足我们的需求,比如想把 Pod 调度到指定的节点,或者不让某些节点调度 Pod。这时候就要用到更高级的调度策略,主要有如下几种:

  • nodeSelector
  • nodeName
  • nodeAffinity
  • podAffinity
  • podAntiAffinity
  • 污点调度

# nodeSelector

nodeSelector 也可以叫做节点选择器,其原理是通过在节点上定义 label 标签,然后 Pod 中指定选择这些标签,让 Pod 能够调度到指定的节点上。

比如给 kk-node01 指定 env=uat 标签,命令如下:

kubectl label nodes kk-node01 env=uat
1

现在在 Pod 的 YAML 清单中配置 nodeSelector,如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector
spec:
  containers:
    - name: myapp
      image: ikubernetes/myapp:v1
  nodeSelector:
    env: uat
1
2
3
4
5
6
7
8
9
10

这样,该 Pod 就会调度到 kk-node01 节点上,如果该 Pod 指定为 env=prod,则调度不到 kk-node01 节点。

# nodeName

nodeName 也是节点选择器,和 nodeSelector 不同之处在于 nodeName 是直接指定节点名,这属于强调度,定义方式如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
spec:
  containers:
    - name: myapp
      image: ikubernetes/myapp:v1
  nodeName: kk-node01 ## 节点名字
1
2
3
4
5
6
7
8
9

# nodeAffinity

nodeAffinity 叫做节点亲和性调度,其调度方式比 nodeSelector 和 nodeName 更强大。

目前,nodeAffinity 支持两种调度策略:

  • preferredDuringSchedulingIgnoredDuringExecution
  • requiredDuringSchedulingIgnoredDuringExecution

preferredDuringSchedulingIgnoredDuringExecution 表示如果有 Node 匹配,则优先调度到该 Node,如果没有,可以根据配置调度到其他节点。requiredDuringSchedulingIgnoredDuringExecution 则表示必须满足条件的节点才允许调度。

定义 preferredDuringSchedulingIgnoredDuringExecution 的例子如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-preferred
spec:
  containers:
    - name: myapp
      image: ikubernetes/myapp:v1
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
        - preference:
            matchExpressions:
              - key: disktype
                operator: In
                values: ["ssd", "harddisk"]
          weight: 60
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

requiredDuringSchedulingIgnoredDuringExecution 的例子如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
spec:
  containers:
    - name: myapp
      image: ikubernetes/myapp:v1
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: disktype
                operator: In
                values: ["ssd", "harddisk"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

其中,operator 支持 In,NotIn, Exists, DoesNotExist. Gt, and Lt。

# podAffinity

上面介绍的 nodeSelector,nodeName,nodeAffinity 都是针对节点的,下面介绍的 podAffinity 和 podAntiAffinity 则是针对 Pod。

podAffinity 表示 Pod 亲和性调度,意识就是把 Pod 调度到与它比较紧密的 Pod 上,如下:

apiVersion: v1
kind: Pod
metadata:
  name: fronted
  labels:
    app: myapp
    row: fronted
spec:
  containers:
    - name: myapp
      image: ikubernetes/myapp:v1
---
apiVersion: v1
kind: Pod
metadata:
  name: backend
  labels:
    app: db
    row: backend
spec:
  containers:
    - name: db
      image: busybox
      imagePullPolicy: IfNotPresent
      command:
        - "/bin/sh"
        - "-c"
        - "sleep 3600"
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
              - key: app
                operator: In
                values: ["myapp"]
          topologyKey: kubernetes.io/hostname
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

这表示把后端 pod 和前端 pod 调度在一起。

podAffinity 也有 preferredDuringSchedulingIgnoredDuringExecution 和 requiredDuringSchedulingIgnoredDuringExecution,也就是硬亲和和软亲和,其使用情况和 nodeAffinity 一样。

# podAntiAffinity

上面介绍了 pod 的亲和性,这里介绍的 podAntiAffinity 则是 Pod 的反亲和性,也就是说不将这类 Pod 调度到一起。在日常工作中,这种亲和性使用频率还比较高。微服务很少有单 Pod,基本都是多个 Pod,为了提高应用的高可用,不会将同应用的多个 Pod 调度到同一台机器上,这时候就要用到 podAntiAffinity,如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - nginx
              topologyKey: kubernetes.io/hostname
      containers:
        - name: nginx
          image: nginx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 污点调度

在 Kubernetes 中,有些节点自带污点 ,比如 Master 节点,这类节点,如果 Pod 没有配置容忍污点,则这些 Pod 不会调度到这类节点上。

在实际中,污点调度也是非常有用的,有些场景某些节点只允许某些项目组的 Pod 允许,比如大数据项目是一些高 IO 项目,不想和其他普通项目混合在一起,而其他项目如果使用标签选择器配置部署又比较麻烦,这时候就可以使用污点选择器。

我们可以通过kubectl explain node.spec.taints来查看污点相关的配置信息:

kubectl explain node.spec.taints
KIND:     Node
VERSION:  v1

RESOURCE: taints <[]Object>

DESCRIPTION:
     If specified, the node's taints.

     The node this Taint is attached to has the "effect" on any pod that does
     not tolerate the Taint.

FIELDS:
   effect       <string> -required-
     Required. The effect of the taint on pods that do not tolerate the taint.
     Valid effects are NoSchedule, PreferNoSchedule and NoExecute.

     Possible enum values:
     - `"NoExecute"` Evict any already-running pods that do not tolerate the
     taint. Currently enforced by NodeController.
     - `"NoSchedule"` Do not allow new pods to schedule onto the node unless
     they tolerate the taint, but allow all pods submitted to Kubelet without
     going through the scheduler to start, and allow all already-running pods to
     continue running. Enforced by the scheduler.
     - `"PreferNoSchedule"` Like TaintEffectNoSchedule, but the scheduler tries
     not to schedule new pods onto the node, rather than prohibiting new pods
     from scheduling onto the node entirely. Enforced by the scheduler.

   key  <string> -required-
     Required. The taint key to be applied to a node.

   timeAdded    <string>
     TimeAdded represents the time at which the taint was added. It is only
     written for NoExecute taints.

   value        <string>
     The taint value corresponding to the taint key.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

其中 effect 定义对 Pod 的排斥效果:

  • NoSchdule:仅影响调度过程,对现存在的 Pod 不产生影响;
  • NoExecute:不仅影响调度,而且还影响现存 Pod,不容忍的 Pod 对象将被驱逐;
  • PreferNoSchedule:软排斥,不是完全禁止 Pod 调度;

如果要给节点添加污点,则如下:

kubectl taint nodes kk-node01 node-type=dev:NoSchedule
1

给节点 kk-node01 增加一个污点,它的键名是 node-type,键值是 dev,效果是 NoSchedule。 这表示只有拥有和这个污点相匹配的容忍度的 Pod 才能够被分配到 kk-node01 这个节点。

如果要删除污点,则使用如下命令:

kubectl taint nodes kk-node01 node-type=dev:NoSchedule-
1

如果要配置容忍污点,则如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.7.9
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
      tolerations:
        - key: "node-type"
          operator: Equal
          value: dev
          effect: NoSchedule
          tolerationSeconds: 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

operator 支持Equal和Exists,默认是Equal。

如果是 Equal,表示污点的键值需要一致,如果使用 Exists,则表示只要存在该键的污点,比如:

tolerations:
- key: "key1"
  operator: "Exists"
  effect: "NoSchedule"
1
2
3
4

该配置表示只要匹配容忍度,并且 key1 的健存在即可调度。

如果一个容忍度的 key 为空且 operator 为 Exists, 表示这个容忍度与任意的 key、value 和 effect 都匹配,即这个容忍度能容忍任何污点。

如果 effect 为空,则可以与所有键名 key1 的效果相匹配。

你可以给一个节点添加多个污点,也可以给一个 Pod 添加多个容忍度设置。 Kubernetes 处理多个污点和容忍度的过程就像一个过滤器:从一个节点的所有污点开始遍历, 过滤掉那些 Pod 中存在与之相匹配的容忍度的污点。余下未被过滤的污点的 effect 值决定了 Pod 是否会被分配到该节点,特别是以下情况:

  • 如果未被忽略的污点中存在至少一个 effect 值为 NoSchedule 的污点, 则 Kubernetes 不会将 Pod 调度到该节点。
  • 如果未被忽略的污点中不存在 effect 值为 NoSchedule 的污点, 但是存在 effect 值为 PreferNoSchedule 的污点, 则 Kubernetes 会 尝试 不将 Pod 调度到该节点。
  • 如果未被忽略的污点中存在至少一个 effect 值为 NoExecute 的污点, 则 Kubernetes 不会将 Pod 调度到该节点(如果 Pod 还未在节点上运行), 或者将 Pod 从该节点驱逐(如果 Pod 已经在节点上运行)。

例如,假设你给一个节点添加了如下污点

kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
1
2
3

假定有一个 Pod,它有两个容忍度:

tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoSchedule"
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoExecute"
1
2
3
4
5
6
7
8
9

在这种情况下,上述 Pod 不会被调度到上述节点,因为其没有容忍度和第三个污点相匹配。 但是如果在给节点添加上述污点之前,该 Pod 已经在上述节点运行, 那么它还可以继续运行在该节点上,因为第三个污点是三个污点中唯一不能被这个 Pod 容忍的。

通常情况下,如果给一个节点添加了一个 effect 值为 NoExecute 的污点, 则任何不能忍受这个污点的 Pod 都会马上被驱逐,任何可以忍受这个污点的 Pod 都不会被驱逐。 但是,如果 Pod 存在一个 effect 值为 NoExecute 的容忍度指定了可选属性 tolerationSeconds 的值,则表示在给节点添加了上述污点之后, Pod 还能继续在节点上运行的时间。例如:

tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoExecute"
    tolerationSeconds: 3600
1
2
3
4
5
6

这表示如果这个 Pod 正在运行,同时一个匹配的污点被添加到其所在的节点, 那么 Pod 还将继续在节点上运行 3600 秒,然后被驱逐。 如果在此之前上述污点被删除了,则 Pod 不会被驱逐。

# 重新调度

在 Kubernetes 中,kube-scheduler 负责将 Pod 调度到合适的 Node 上,但是 Kubernetes 是一个非常动态的,高度弹性的环境,有时候会造成某一个或多个节点 pod 数分配不均,比如:

  • 一些节点利用率低下或过度使用
  • 添加删除标签或添加删除污点,pod 或 Node 亲和性改变等造成原调度不再满足
  • 一些节点故障,其上运行的 Pod 调度到其他节点
  • 新节点加入集群

由于以上种种原因,可能导致多个 Pod 运行到不太理想的节点,而整个 K8S 集群也会处于一段时间不均衡的状态,这时候就需要重新平衡集群。Descheduler 就是这样一个项目。

Descheduler 可以根据一些规则配置来重新平衡集群状态,目前支持的策略有:

  • RemoveDuplicates
  • LowNodeUtilization
  • RemovePodsViolatingInterPodAntiAffinity
  • RemovePodsViolatingNodeAffinity
  • RemovePodsViolatingNodeTaints
  • RemovePodsViolatingTopologySpreadConstraint
  • RemovePodsHavingTooManyRestarts
  • PodLifeTime

这些策略可以启用,也可以关闭,默认情况下,所有策略都是启动的。

另外,还有一些通用配置,如下:

  • nodeSelector:限制要处理的节点
  • evictLocalStoragePods: 驱除使用 LocalStorage 的 Pods
  • ignorePvcPods: 是否忽略配置 PVC 的 Pods,默认是 False
  • maxNoOfPodsToEvictPerNode:节点允许的最大驱逐 Pods 数

由于我集群版本是 1.24.2,所以安装 descheduler v0.24 版本。

(1)下载对应的 Helm chart,我这里选择的是 0.24 版本

wget https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.24.0/descheduler-0.24.0.tgz
1

(2)如果可以科学上网,直接使用以下命令部署即可。

helm install descheduler .
1

如果不能科学上网,就替换镜像,修改value.yaml里的镜像信息,如下:

image:
  repository: registry.cn-hangzhou.aliyuncs.com/coolops/descheduler
  ## Overrides the image tag whose default is the chart version
  tag: "v0.24.0"
  pullPolicy: IfNotPresent
1
2
3
4
5

然后再执行安装命令。

安装完成过后,会配置默认的调度策略,如下:

apiVersion: v1
data:
  policy.yaml: |
    apiVersion: "descheduler/v1alpha1"
    kind: "DeschedulerPolicy"
    strategies:
      LowNodeUtilization:
        enabled: true
        params:
          nodeResourceUtilizationThresholds:
            targetThresholds:
              cpu: 50
              memory: 50
              pods: 50
            thresholds:
              cpu: 20
              memory: 20
              pods: 20
      RemoveDuplicates:
        enabled: true
      RemovePodsViolatingInterPodAntiAffinity:
        enabled: true
      RemovePodsViolatingNodeAffinity:
        enabled: true
        params:
          nodeAffinityType:
          - requiredDuringSchedulingIgnoredDuringExecution
      RemovePodsViolatingNodeTaints:
        enabled: true
kind: ConfigMap
metadata:
  annotations:
    meta.helm.sh/release-name: descheduler
    meta.helm.sh/release-namespace: default
  creationTimestamp: "2022-08-02T03:06:57Z"
  labels:
    app.kubernetes.io/instance: descheduler
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: descheduler
    app.kubernetes.io/version: 0.24.0
    helm.sh/chart: descheduler-0.24.0
  name: descheduler
  namespace: default
  resourceVersion: "894636"
  uid: 4ab2e628-9404-4e52-bd88-615f5e096d90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

其中配置了:

  • LowNodeUtilization:设置了 cpu\内存\pod 水位,thresholds 表示未充分利用,targetThresholds 表示过度使用
  • RemoveDuplicates:开启同节点只有一个 Pod 运行
  • RemovePodsViolatingInterPodAntiAffinity:删除违反亲和性的 Pod
  • RemovePodsViolatingNodeAffinity:删除不满足 Node 亲和性的 Pod
  • RemovePodsViolatingNodeTaints:删除不被 Node 污点容忍的 Pod

并且会创建一个 CronJob,周期性的执行调度均衡。

apiVersion: batch/v1
kind: CronJob
metadata:
  annotations:
    meta.helm.sh/release-name: descheduler
    meta.helm.sh/release-namespace: default
  creationTimestamp: "2022-08-02T03:06:57Z"
  generation: 1
  labels:
    app.kubernetes.io/instance: descheduler
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: descheduler
    app.kubernetes.io/version: 0.24.0
    helm.sh/chart: descheduler-0.24.0
  name: descheduler
  namespace: default
  resourceVersion: "898221"
  uid: e209e498-71cb-413f-97a9-372aea5442bc
spec:
  concurrencyPolicy: Forbid
  failedJobsHistoryLimit: 1
  jobTemplate:
    metadata:
      creationTimestamp: null
    spec:
      template:
        metadata:
          annotations:
            checksum/config: 5efec14c3638fa4028e25f3fa067758f13dcae442fe711439c7d0b2e9913d41e
          creationTimestamp: null
          labels:
            app.kubernetes.io/instance: descheduler
            app.kubernetes.io/name: descheduler
          name: descheduler
        spec:
          containers:
          - args:
            - --policy-config-file
            - /policy-dir/policy.yaml
            - --v
            - "3"
            command:
            - /bin/descheduler
            image: registry.cn-hangzhou.aliyuncs.com/coolops/descheduler:v0.24.0
            imagePullPolicy: IfNotPresent
            livenessProbe:
              failureThreshold: 3
              httpGet:
                path: /healthz
                port: 10258
                scheme: HTTPS
              initialDelaySeconds: 3
              periodSeconds: 10
              successThreshold: 1
              timeoutSeconds: 1
            name: descheduler
            resources:
              requests:
                cpu: 500m
                memory: 256Mi
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
              privileged: false
              readOnlyRootFilesystem: true
              runAsNonRoot: true
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            volumeMounts:
            - mountPath: /policy-dir
              name: policy-volume
          dnsPolicy: ClusterFirst
          priorityClassName: system-cluster-critical
          restartPolicy: Never
          schedulerName: default-scheduler
          securityContext: {}
          serviceAccount: descheduler
          serviceAccountName: descheduler
          terminationGracePeriodSeconds: 30
          volumes:
          - configMap:
              defaultMode: 420
              name: descheduler
            name: policy-volume
  schedule: '*/2 * * * *'
  successfulJobsHistoryLimit: 3
  suspend: false
status:
  lastScheduleTime: "2022-08-02T03:28:00Z"
  lastSuccessfulTime: "2022-08-02T03:28:03Z"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

该 Job 会每 2 分钟执行一次均衡调度。

# 总结

Kubernetes 的调度策略是非常复杂的,里面有许多复杂的算法,这里介绍的只是一些常用的调度策略,足够满足日常使用。如果想更深入的研究可以多看看官方文档以及源码。

上次更新: 2025/07/19, 21:23:02
Kubernetes工作负载管理
Kubernetes应用质量管理

← Kubernetes工作负载管理 Kubernetes应用质量管理→

最近更新
01
elastic 账户认证 401 问题
07-20
02
使用 helm 安装 es 和 kibana
07-20
03
elastic stack 搭建
07-20
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式