Scheduler

Kubernetes是一个开源的容器编排平台,它提供了许多功能来自动化应用程序的部署、扩展、管理和升级。其中一个重要的组件是Pod Scheduler(Pod调度器),它负责将应用程序的容器(Pod)分配到可用的节点(Node)上。

Pod Scheduler的作用非常重要,因为它可以确保应用程序在集群中的运行是高效、稳定、可靠的。

如果没有Pod Scheduler,管理员可能需要手动将容器分配到节点上,并需要时刻监控集群状态以保证应用程序的高可用性。而这样的方式是非常低效且容易出错的。

为什么要学pod调度策略

学习Pod Scheduler的知识可以帮助管理员更好地了解Kubernetes的工作原理,从而更好地管理和运维集群。

学习 Kubernetes 中的 Pod 调度 (scheduling) 是非常重要的,因为 Pod 调度是 Kubernetes 中的核心功能之一。Pod 是 Kubernetes 中的最小调度单位,它包含了一个或多个容器,而 Pod 调度是 Kubernetes 集群将 Pod 分配到节点的过程。

学习 Pod 调度的预选、优选、驱逐和容忍等概念,可以帮助你更好地理解 Kubernetes 中的调度机制和原理。这些概念与 Kubernetes 集群的可用性、可靠性和性能密切相关。

以下是一些具体的原因:

  1. 了解 Kubernetes 中的 Pod 调度策略可以帮助你更好地规划和管理集群资源。你可以通过配置调度策略来确保 Pod 在运行时满足资源需求,以及最大化利用集群资源。
  2. 了解 Pod 调度的预选、优选、驱逐和容忍等过程可以帮助你更好地排查和解决调度问题。当你遇到调度失败或 Pod 被驱逐的问题时,你可以通过了解这些概念来确定问题的根本原因,并作出相应的调整。
  3. 熟悉 Pod 调度的预选、优选、驱逐和容忍等机制可以帮助你更好地设计和管理应用程序。在应用程序设计时,你可以考虑集群中的节点资源情况,以及应用程序对资源的需求,从而使应用程序更好地适应 Kubernetes 环境。

学习pod调度是为了理解,在业务本身的k8s化部署以外,需要学习k8s自身提供的一些pod调度相关的功能。

为什么要限制pod调度规则

因为默认pod调度室schduler自动取选择的,我们也可以加上一些pod调度的策略。

  • 集群中有些机器的配置高(SSD,更好的内存等),我们希望核心的服务(比如说数据库)运行在上面
  • 某两个服务的网络传输很频繁,我们希望它们最好在同一台机器上
  • ......

Kubernetes Scheduler 的作用是将待调度的 Pod 按照一定的调度算法和策略绑定到集群中一个合适的 Worker Node 上,并将绑定信息写入到 etcd 中,之后目标 Node 中 kubelet 服务通过 API Server 监听到 Scheduler 产生的 Pod 绑定事件获取 Pod 信息,然后下载镜像启动容器。

img

理解调度阶段

在Kubernetes中,调度器(Scheduler)是一种组件,它负责将Pod分配到可用的节点上。在Scheduler中,预选和优选是两个不同的阶段,它们帮助Scheduler选择最佳的节点来运行Pod。

预选阶段是指Scheduler在考虑节点是否可用时所执行的第一轮筛选。在预选阶段,Scheduler会对所有可用的节点进行评估,并根据预设的策略和Pod的要求进行筛选,剔除那些无法满足Pod的要求的节点。例如,如果Pod需要特定的资源(如CPU或内存),Scheduler会排除那些不符合要求的节点。

优选阶段是指Scheduler在预选阶段之后所执行的第二轮筛选。在优选阶段,Scheduler会对通过预选的节点进行再次评估,并根据更多的因素(如负载均衡、亲和性、反亲和性等)来选择最佳的节点。例如,Scheduler可以考虑已经运行在节点上的其他Pod,以确保节点的资源分配合理。

总之,预选和优选是Kubernetes调度器中的两个重要阶段,它们可以帮助Scheduler选择最适合Pod的节点,并确保Pod的健康和高可用性。

Scheduler 提供的调度流程分为预选 (Predicates) 和优选 (Priorities) 两个步骤:

  • 预选,K8S会遍历当前集群中的所有 Node,筛选出其中符合要求的 Node 作为候选。
    • 预选是0、1的关系
    • 例如端口冲突
    • 例如nodeSelector
  • 优选,K8S将对候选的 Node 进行打分
    • 例如候选机器的机器负载情况,CPU、内存等

经过预选筛选和优选打分之后,K8S选择分数最高的 Node 来运行 Pod,如果最终有多个 Node 的分数最高,那么 Scheduler 将从当中随机选择一个 Node 来运行 Pod。

总之,预选和优选是Kubernetes调度器中的两个阶段,它们有助于调度器选择最适合Pod的节点,并确保Pod的高可用性和资源利用率。

图解2个调度阶段

image-20230401181916644

预选策略

img

优选策略

img

NodeSelector

官网文档

https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/

labelkubernetes中一个非常重要的概念,用户可以非常灵活的利用 label 来管理集群中的资源,POD 的调度可以根据节点的 label 进行特定的部署。

查看节点的label:

kubectl get nodes --show-labels

为节点打label:

$ kubectl label node k8s-master disktype=ssd

当 node 被打上了相关标签后,在调度的时候就可以使用这些标签了,只需要在spec 字段中添加nodeSelector字段,里面是我们需要被调度的节点的 label。

...
spec:
  volumes: 
  - name: mysql-data
    hostPath: 
      path: /opt/mysql/data
  nodeSelector:   # 使用节点选择器将Pod调度到指定label的节点
    mysql: "true"
  containers:
  - name: mysql
      image: mysql:5.7
...

为什么需要学nodeAffinity

机器数量较少的话就别整亲和性了。。

至少几百个节点,需要设置复杂规则时,用亲和性

nodeAffinity和nodeSelector都是用来控制Pod在哪些节点上运行的机制,但它们有一些区别:

  1. 灵活性:nodeAffinity比nodeSelector更加灵活。nodeSelector只能使用等于操作符进行节点标签匹配,而nodeAffinity支持使用in、notIn、exists、doesNotExist、gt、lt等多种操作符,同时还支持使用节点的资源使用情况、节点的角色、节点的拓扑位置等信息进行选择。
  2. 粒度:nodeAffinity可以实现更细粒度的控制。nodeSelector只能指定一个或多个节点标签,而nodeAffinity可以通过使用多个节点标签或其他属性来实现更加精确的控制。
  3. 复杂性:nodeAffinity相对于nodeSelector来说更加复杂。由于其支持更多的操作符和属性,因此需要更多的学习和配置成本。

综上所述,nodeAffinity比nodeSelector更加灵活和精确,但同时也更加复杂。在实际应用中,用户需要根据自己的需求来选择适合自己的节点选择机制。

nodeSelector 和nodeAffinity的区别

nodeSelector 、我要吃红烧排骨、没有我就不吃了。

nodeAffinity、我要吃饭,有红烧排骨优先。。不行就吃其他的吧

nodeAffinity(节点亲和性)

Pod -> Node的标签

Label标签是0和1的关系,行或不行。

而节点亲和性 , 比上面的nodeSelector更加灵活,它可以进行一些简单的逻辑组合,不只是简单的相等匹配 。

硬策略和软策略

requiredDuringSchedulingIgnoredDuringExecution : 硬策略,如果没有满足条件的节点的话,就不断重试直到满足条件为止,简单说就是你必须满足我的要求,不然我就不会调度Pod。

preferredDuringSchedulingIgnoredDuringExecution:软策略,如果你没有满足调度要求的节点的话,Pod就会忽略这条规则,继续完成调度过程,说白了就是满足条件最好了,没有满足就忽略掉的策略。

详细解释

这两个参数是 Kubernetes Pod 中的调度策略字段,它们的作用是指定 Pod 调度时节点的要求。

  • preferredDuringSchedulingIgnoredDuringExecution 表示希望 Pod 能够调度到具有指定标签的节点,但如果没有满足条件的节点也不会阻止 Pod 调度到其他节点。这个参数是一个列表,可以指定多个标签和权重,Kubernetes 将根据权重决定选择哪个节点。如果有多个节点都满足要求,则会随机选择一个节点。
  • requiredDuringSchedulingIgnoredDuringExecution 表示 Pod 必须调度到具有指定标签的节点上,否则调度将失败。如果没有满足条件的节点,Pod 将一直处于 Pending 状态。

两个参数的共同点是它们都会被忽略在 Pod 运行时。也就是说,一旦 Pod 被调度到节点上并且开始运行,这两个参数的值将被忽略,不会对运行时产生任何影响。

使用这两个参数可以帮助你控制 Pod 的调度,以便让它们运行在特定的节点上,或者让它们尽可能地均匀地分布在集群中的节点上。

使用案例

要求 Pod 不能运行在k8s-slave1和k8s-slave2两个节点上,如果有节点满足disktype=ssd或者sas的话就优先调度到这类节点上 ...

...
spec:
      containers:
      - name: eladmin-api
        image: 10.0.0.66:5000/eladmin-api:v1
        ports:
        - containerPort: 8000
      affinity:
          nodeAffinity:
            # 硬策略
            # 强制要求,只要label出现如下字符串,就禁止调度。
            requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                    - key: kubernetes.io/hostname
                      operator: NotIn
                      values:
                        - k8s-slave1
                        - k8s-slave2
             # 软策略
             # 在所有node上进行判断,如果label有符合是ssd、或者sas优先调度
             # 
            preferredDuringSchedulingIgnoredDuringExecution:
                - weight: 1
                  preference:
                    matchExpressions:
                    - key: disktype
                      operator: In
                      values:
                        - ssd
                        - sas
...

该配置中包含一个权重(weight)和一个偏好(preference)。当节点满足偏好条件时,权重越高的节点将优先被选择。

在这个特定的配置中,偏好条件是节点的磁盘类型必须是SSD或SAS。这个偏好使用了matchExpressions的方式进行匹配,即只有当节点的标签中包含disktype且其值为SSD或SAS时,才会被认为是符合条件的。

这里的匹配逻辑是 label 的值在某个列表中,现在Kubernetes提供的操作符有下面的几种:

  • In:label 的值在某个列表中
  • NotIn:label 的值不在某个列表中
  • Gt:label 的值大于某个值
  • Lt:label 的值小于某个值
  • Exists:某个 label 存在
  • DoesNotExist:某个 label 不存在

注意

  • 如果nodeSelectorTerms下面有多个选项的话,满足任何一个条件就可以了;

  • 如果matchExpressions有多个选项的话,则必须同时满足这些条件才能正常调度 Pod;

pod亲和性、反亲和性

Pod 亲和性和反亲和性的主要目的是为了帮助 Kubernetes 集群管理员更好地控制 Pod 的调度和部署,从而实现更高的可用性、可靠性和性能。

以下是一些常见的原因和用例:

  1. 提高可用性和可靠性:Pod 亲和性可以将相关的 Pod 调度到同一节点上,这样可以降低节点故障对应用的影响。同时,反亲和性可以将相关的 Pod 分散到不同的节点上,避免单点故障影响整个应用。
  2. 改善性能和资源利用率:Pod 亲和性可以将需要共享资源的 Pod 调度到同一节点上,这样可以降低网络延迟和提高吞吐量。同时,反亲和性可以将需要竞争资源的 Pod 分散到不同的节点上,避免资源竞争导致的性能下降。
  3. 分离敏感数据:Pod 亲和性可以将处理敏感数据的 Pod 调度到同一节点上,避免数据泄露和安全漏洞。同时,反亲和性可以将处理不同数据的 Pod 分散到不同的节点上,避免数据交叉和混淆。

总之,Pod 亲和性和反亲和性是 Kubernetes 集群管理的重要工具,可以帮助管理员更好地管理 Pod 的调度和部署,提高应用的可用性、可靠性和性能。

语法

eladmin-web启动多副本,但是期望可以尽量分散到集群的可用节点中

[root@k8s-master ~]#kubectl -n yuchao get po -owide
NAME                          READY   STATUS    RESTARTS       AGE    IP            NODE         NOMINATED NODE   READINESS GATES
eladmin-api-9446bcc45-jrpk4   1/1     Running   0              11d    10.244.0.44   k8s-master   <none>           <none>
eladmin-api-9446bcc45-mhrmp   1/1     Running   1 (143m ago)   11d    10.244.2.56   k8s-slave1   <none>           <none>
eladmin-api-9446bcc45-p5q2r   1/1     Running   0              11d    10.244.2.57   k8s-slave1   <none>           <none>
eladmin-api-9446bcc45-pkpjr   1/1     Running   0              11d    10.244.1.39   k8s-slave2   <none>           <none>
eladmin-web-95f5dcd64-z9b2n   1/1     Running   0              3d2h   10.244.2.53   k8s-slave1   <none>           <none>
mysql-7c7cf8495f-5w5bk        1/1     Running   0              12d    10.244.0.43   k8s-master   <none>           <none>
ngx-test                      1/1     Running   0              2d1h   10.244.1.36   k8s-slave2   <none>           <none>
redis-7957d49f44-cxj8z        1/1     Running   0              12d    10.244.1.37   k8s-slave2   <none>           <none>
[root@k8s-master ~]#

分析:为了让eladmin-web应用的多个pod尽量分散部署在集群中,可以利用pod的反亲和性,告诉调度器,如果某个节点中存在了eladmin-web的pod,则可以根据实际情况,实现如下调度策略:

不允许同一个node节点,调度两个eladmin-web的副本(硬策略)

# 如果某个节点中,存在了app=eladmin-web的label的pod,那么 调度器一定不要给我调度过去
...
    spec:
      affinity:
        # pod反亲和性
        podAntiAffinity:
          # 硬策略
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - eladmin-web
            topologyKey: kubernetes.io/hostname
      containers:
...

其中,affinity字段用于指定Pod的调度策略,podAntiAffinity表示Pod的反亲和性(即避免与具有某些标签的其他Pod调度到同一个节点上)。
requiredDuringSchedulingIgnoredDuringExecution则表示Pod的反亲和性规则是硬策略(即强制执行),如果违反规则则不会被调度。
在本例中,labelSelector指定了匹配Pod标签的方式,topologyKey表示反亲和性规则应该在节点级别上执行,基于节点的主机名进行匹配。

可以允许同一个node节点中调度两个eladmin-web的副本,前提是尽量把pod分散部署在集群中(软策略)

这是一段给pod设置的反亲和性
...
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - eladmin-web
              topologyKey: kubernetes.io/hostname
      containers:
...
# 如果某个节点中,存在了app=eladmin-web的label的pod,那么调度器尽量不要调度过去.

参数解释

  • affinity 段定义了 Pod 的亲和性规则。
  • 在这个例子中,使用 podAntiAffinity 配置来确保同一节点上不会调度多个具有相同标签的 Pod。
  • preferredDuringSchedulingIgnoredDuringExecution 指定了调度器如何偏好调度的 Pod。
  • weight 字段指定权重,此处为 100。
  • podAffinityTerm 指定了 Pod 亲和性的条件,其中 labelSelector 选择了具有 app=eladmin-web 标签的
  • Pod,topologyKey 则指定 Pod 应该在不同主机上分配。

实践软策略

这里的规则是,如果节点上有了eladmin-web的标签,就尽量不会再调取eladmin-api。

[root@k8s-master ~]#kubectl -n yuchao edit deployments.apps eladmin-api 

...
     30   template:
     31     metadata:
     32       creationTimestamp: null
     33       labels:
     34         app: eladmin-api
     35     spec:
     36       affinity:
     37         podAntiAffinity:
     38           preferredDuringSchedulingIgnoredDuringExecution:
     39           - podAffinityTerm:
     40               labelSelector:
     41                 matchExpressions:
     42                 - key: app
     43                   operator: In
     44                   values:
     45                   - eladmin-web
     46               topologyKey: kubernetes.io/hostname
     47             weight: 100
     48       containers:
     49       - env:
     50         - name: DB_HOST

# 看新的pod调度情况
[root@k8s-master ~]#kubectl -n yuchao get po -owide |grep eladmin-api
eladmin-api-79b478cf54-24snm   1/1     Running   0          94s    10.244.1.41   k8s-slave2   <none>           <none>
eladmin-api-79b478cf54-m5ntl   1/1     Running   0          94s    10.244.0.46   k8s-master   <none>           <none>
eladmin-api-79b478cf54-qfwr9   1/1     Running   0          2m5s   10.244.1.40   k8s-slave2   <none>           <none>
eladmin-api-79b478cf54-zr9pr   1/1     Running   0          2m5s   10.244.0.45   k8s-master   <none>           <none>

# 很明显,不会去eladmin-web所在节点部署了

污点Taint、容忍tolerations

污点、理解为坏毛病
你要是不能忍,你就别跟我做朋友

对于nodeAffinity无论是硬策略还是软策略方式,都是调度 Pod 到预期节点上;

Taints恰好与之相反,如果一个节点标记为 Taints ,除非 Pod 也被标识为可以容忍污点节点,否则该 Taints 节点不会被调度Pod。

Taints(污点)是Node的一个属性,设置了Taints(污点)后,因为有了污点,所以Kubernetes是不会将Pod调度到这个Node上的。

还记得初始化安装k8s时,k8s-master有taints而默认不允许调度pos吗。

于是Kubernetes就给Pod设置了个属性Tolerations(容忍),只要Pod能够容忍Node上的污点,那么Kubernetes就会忽略Node上的污点,就能够(不是必须)把Pod调度过去。

为什么需要有taints

nodeAffinity 和 taints 是 Kubernetes 中用于调度和管理 Pod 的两个重要概念,它们之间有密切的关系。

NodeAffinity 是用于指定 Pod 调度到哪些节点的策略,可以根据节点的标签和其他属性对节点进行匹配。与之对应的是 PodAffinity 和 PodAntiAffinity,用于指定 Pod 与其他 Pod 之间的调度关系。

Taints 则是用于标记节点的一种机制,它可以阻止一些不希望运行在该节点上的 Pod 调度到该节点上。与之对应的是 Tolerations,用于让某个 Pod 可以容忍某个节点的 Taint。

因此,NodeAffinity 和 Taints 可以结合起来使用,以实现更灵活的 Pod 调度和管理。例如,我们可以为某个节点设置 Taint,表示该节点只能运行特定类型的 Pod,然后使用 NodeAffinity 来指定只有特定的 Pod 能够被调度到该节点上。另外,如果某个 Pod 需要运行在某个被 Taint 标记的节点上,我们可以为该 Pod 设置对应的 Tolerations,以允许它在该节点上运行。

因此,可以说 NodeAffinity 和 Taints 是 Kubernetes 中非常重要的概念,它们可以帮助用户更好地管理和控制 Pod 的调度和运行。

使用taint场景

场景一:私有云服务中,某业务使用GPU进行大规模并行计算。为保证性能,希望确保该业务对服务器的专属性,避免将普通业务调度到部署GPU的服务器。

场景二:用户希望把 Master 节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 Pod,则污点就很有用了,Pod 不会再被调度到 taint 标记过的节点。

taint 标记节点举例如下:

设置taints

$ kubectl taint node [node_name] key=value:[effect]   
      其中[effect] 可取值: [ NoSchedule | PreferNoSchedule | NoExecute ]
       NoSchedule:一定不能被调度。
       PreferNoSchedule:尽量不要调度。
       NoExecute:不仅不会调度,还会驱逐Node上已有的Pod。

在选择这三个策略时,需要考虑以下因素:

节点资源:如果节点资源已经用尽,可以将其标记为 NoSchedule 或 NoExecute,以防止在该节点上调度新的 Pod,或者将现有的 Pod 驱逐出该节点。这样可以保证节点不会过载,从而确保其他 Pod 的可用性和性能。

特殊节点:如果有某些节点具有特殊的限制或需求,可以将其标记为 PreferNoSchedule,以便调度器优先考虑在其他可用节点上调度 Pod。这可以确保这些特殊节点上不会调度太多的 Pod,从而满足它们的限制和需求。

安全性问题:如果节点存在安全性问题,例如存在漏洞或被攻击,可以将其标记为 NoExecute,以避免任何进一步的攻击或数据泄露。在这种情况下,运行在该节点上的所有 Pod 都将被删除,以确保集群的安全性。

因此,在选择这三个策略时,应该考虑节点的资源状况、特殊的限制或需求,以及安全性问题,选择最适合的策略以确保集群的高可用性、资源利用率和安全性。



示例:kubectl taint node k8s-slave1 smoke=true:NoSchedule

去掉污点

去除指定key及其effect:
     kubectl taint nodes [node_name] key:[effect]-    #这里的key不用指定value
     kubectl taint node k8s-slave1 smoke-
 去除指定key所有的effect: 
     kubectl taint nodes node_name key-

 示例:
     kubectl taint node k8s-master smoke=true:NoSchedule
     kubectl taint node k8s-master smoke:NoExecute-
     kubectl taint node k8s-master smoke-

实战污点玩法

## 给k8s-slave1打上污点,smoke=true:NoSchedule
$ kubectl taint node k8s-master gamble=true:NoSchedule
$ kubectl taint node k8s-slave1 drunk=true:NoSchedule
$ kubectl taint node k8s-slave2 smoke=true:NoSchedule


## 扩容eladmin-web的Pod,观察新Pod的调度情况
$ kubectl -n yuchao scale deploy eladmin-web --replicas=0
$ kubectl -n yuchao scale deploy eladmin-web --replicas=1

[root@k8s-master ~]#kubectl -n yuchao get po |grep web
eladmin-web-95f5dcd64-t9mg9    0/1     Pending   0          25s

# 为什么?
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  39s   default-scheduler  0/3 nodes are available: 1 node(s) had untolerated taint {drunk: true}, 1 node(s) had untolerated taint {gamble: true}, 1 node(s) had untolerated taint {smoke: true}. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling.
[root@k8s-master ~]#kubectl -n yuchao describe po eladmin-web-95f5dcd64-t9mg9 

# 3个节点,都有污点(坏习惯、抽烟、喝酒、赌博、)
# 并且你这个pod没有提前说,你能容忍这些污点,所以就拒绝做朋友!!!
# 除非你能容忍他这个污点

pod加上容忍

[root@k8s-master ~]#kubectl -n yuchao edit deployments.apps  eladmin-web 
deployment.apps/eladmin-web edited


...
spec:
      containers:
      - name: eladmin-web
        image: 10.0.0.66:5000/eladmin/eladmin-web:v2
      tolerations: #设置容忍性
      - key: "smoke" 
        operator: "Equal"  #不指定operator,默认为Equal
        value: "true"
        effect: "NoSchedule"
      - key: "drunk" 
        operator: "Exists"  
        # 如果操作符为Exists,那么value属性可省略,不指定operator,默认为Equal
        # 允许你喝酒,值是什么随意,都容忍了

# 意思是这个Pod要容忍的有污点的Node的key是smoke Equal true,效果是NoSchedule,
# tolerations属性下各值必须使用引号,容忍的值都是设置Node的taints时给的值。
# 这里是一个比较全的案例,等于你想找对象,容忍了抽烟、喝酒,两个坏习惯。

继续查看刚才的pod这一次是成功调度了,以及查看pod的容忍有哪些

Tolerations:                 drunk op=Exists # 只要有这个drunk污点,就容忍
                             node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
                             smoke=true:NoSchedule
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  36s   default-scheduler  Successfully assigned yuchao/eladmin-web-759f77b7cb-v7bpw to k8s-slave1
  Normal  Pulled     36s   kubelet            Container image "10.0.0.66:5000/eladmin/eladmin-web:v5" already present on machine
  Normal  Created    36s   kubelet            Created container eladmin-web
  Normal  Started    36s   kubelet            Started container eladmin-web
[root@k8s-master ~]#
[root@k8s-master ~]#kubectl -n yuchao describe po eladmin-web-759f77b7cb-v7bpw
  • drunk op=Exists:表示 Pod 可以被调度到一个被标记为 "drunk" 的节点上,"op=Exists" 表示只要这个污点存在就允许调度。
  • node.kubernetes.io/not-ready:NoExecute op=Exists for 300s:表示 Pod 可以被调度到一个被标记为 "not-ready" 的节点上,"NoExecute" 表示该污点标记的节点上的 Pod 会被驱逐(Eviction),"op=Exists for 300s" 表示只有该污点存在 300 秒以上时才允许调度。
  • node.kubernetes.io/unreachable:NoExecute op=Exists for 300s:表示 Pod 可以被调度到一个被标记为 "unreachable" 的节点上,同样 "NoExecute" 表示该污点标记的节点上的 Pod 会被驱逐,"op=Exists for 300s" 表示只有该污点存在 300 秒以上时才允许调度。
  • smoke=true:NoSchedule:表示 Pod 可以被调度到一个被标记为 "smoke=true" 的节点上,"NoSchedule" 表示该污点标记的节点上不会再调度新的 Pod,只会等待现有 Pod 的终止或迁移。

容忍所有的污点(最大接受度)

spec:
      containers:
      - name: eladmin-web
        image: 10.0.0.66:5000/eladmin/eladmin-web:v2
      tolerations:
        - operator: "Exists" 
        # 这段意思是,随你是什么污点,只要有,就容忍

有一个内置的组件,就是容忍所有污点,都可以调度

QoS Class:                   BestEffort
Node-Selectors:              kubernetes.io/os=linux
Tolerations:                 op=Exists
                             node.kubernetes.io/disk-pressure:NoSchedule op=Exists
                             node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                             node.kubernetes.io/network-unavailable:NoSchedule op=Exists
                             node.kubernetes.io/not-ready:NoExecute op=Exists
                             node.kubernetes.io/pid-pressure:NoSchedule op=Exists
                             node.kubernetes.io/unreachable:NoExecute op=Exists
                             node.kubernetes.io/unschedulable:NoSchedule op=Exists
Events:                      <none>
[root@k8s-master ~]#kubectl -n kube-system describe pod kube-proxy-np8rb 

# 或者导出pod-yaml也可以看到容忍
[root@k8s-master ~]#kubectl -n kube-system get pod kube-proxy-np8rb -oyaml

去掉污点

[root@k8s-master ~]#kubectl describe no k8s-master |grep -i taint
Taints:             gamble=true:NoSchedule
[root@k8s-master ~]#kubectl taint node k8s-master gamble-
node/k8s-master untainted

[root@k8s-master ~]#kubectl describe no k8s-slave1 |grep -i taint
Taints:             drunk=true:NoSchedule
[root@k8s-master ~]#
[root@k8s-master ~]#kubectl taint node k8s-slave1 drunk=true:NoSchedule-
node/k8s-slave1 untainted


[root@k8s-master ~]#kubectl taint node k8s-slave2 smoke-
node/k8s-slave2 untainted

cordon/drain

在Kubernetes中,cordon和drain是管理节点的两个命令。

cordon 标记不可用
drain 驱逐所有pod

cordon命令可以将节点标记为不可调度,这意味着Kubernetes调度器将不会将新的Pod调度到该节点上。但是该节点上已经运行的Pod不会被删除或迁移。

这个命令可以用于维护节点或者在节点出现问题时限制节点的使用。

drain命令则更加彻底,它除了标记节点为不可调度外,还会删除该节点上的所有Pod。这个命令通常用于将节点从集群中移除,以便进行维护或升级操作。

当我们需要对某个节点进行维护或者更新操作时,我们可以使用cordon命令将该节点标记为不可调度,等待该节点上的Pod自然结束或者迁移至其他节点。

在所有Pod都已经迁移后,我们可以使用drain命令来删除该节点上的所有Pod,然后进行节点维护操作。

需要注意的是,使用cordon和drain命令时,我们需要确保该节点上的Pod已经有备份,以便在需要时能够恢复。

# 等于给你机器,加上污点,就默认不允许调度了
$ kubectl cordon k8s-slave1

# cordon就等于用taint命令,加上一个污点
[root@k8s-master ~]#kubectl describe no k8s-slave1 |grep -i taint
Taints:             node.kubernetes.io/unschedulable:NoSchedule


[root@k8s-master ~]#kubectl get po -owide
NAME         READY   STATUS    RESTARTS        AGE   IP            NODE         NOMINATED NODE   READINESS GATES
ngx01        1/1     Running   3 (8m51s ago)   11d   10.244.0.51   k8s-master   <none>           <none>
ngx1         1/1     Running   4 (8m54s ago)   22d   10.244.2.59   k8s-slave1   <none>           <none>
test-nginx   1/1     Running   4 (8m54s ago)   24d   10.244.2.61   k8s-slave1   <none>           <none>
[root@k8s-master ~]#



# 驱逐节点上所有pod,默认会驱逐失败,因为不允许直接干掉daemonset的pod
$ kubectl drain k8s-slave1
$ kubectl drain k8s-slave1 --force --ignore-daemonsets 

# 检查所有机器的pod,会发现普通pod都被删除了,忽略了daemonsets的pod
[root@k8s-master ~]#kubectl get po -A -owide|grep k8s-slave1
kube-flannel           kube-flannel-ds-gs9dt                        1/1     Running     4 (120m ago)     24d     10.0.0.81     k8s-slave1   <none>           <none>
kube-system            kube-proxy-np8rb                             1/1     Running     3 (120m ago)     12d     10.0.0.81     k8s-slave1   <none>           <none>
[root@k8s-master ~]#


# drain是包含cordon的污点操作的

# 没有撤销动作,需要撤销cordon
[root@k8s-master ~]#kubectl uncordon k8s-slave1
node/k8s-slave1 uncordoned
[root@k8s-master ~]#
[root@k8s-master ~]#kubectl describe no k8s-slave1 |grep -i taint
Taints:             <none>

pod驱逐策略

pod驱逐解释

Pod驱逐(Pod Eviction)是指Kubernetes集群自动删除节点上运行的Pod的过程。Pod驱逐策略是指在何种情况下Kubernetes集群会自动驱逐Pod。

Pod驱逐策略通常与节点维护(Node Maintenance)相关。当需要对某个节点进行维护或升级时,需要将该节点上运行的Pod驱逐到其他节点上,以保证服务的高可用性。

Pod驱逐策略可以由用户指定,也可以由Kubernetes集群自动计算。用户可以通过PodDisruptionBudget对象来指定Pod的最小可用性要求,并且可以设置Pod的驱逐顺序、驱逐时间等参数。

Kubernetes集群自动计算Pod驱逐策略的方式是通过考虑Pod的调度约束、副本数、节点资源负载情况等因素,来确定哪些Pod需要被驱逐。

当需要驱逐Pod时,Kubernetes会先尝试进行Graceful Termination,即向Pod发送SIGTERM信号,让Pod自行清理工作并停止服务。

如果在一定时间内Pod仍未停止,则Kubernetes会强制终止Pod,并在其他节点上重新调度该Pod的副本。

故障场景

k8s是如何处理你的node节点,突然关机,上面的pod如何迁移的?

K8S 有个特色功能叫 pod eviction,它在某些场景下如节点 NotReady,或者资源不足时,把 pod 驱逐至其它节点,这也是出于业务保护的角度去考虑的。

  1. Kube-controller-manager: 周期性检查所有节点状态,当节点处于 NotReady 状态超过一段时间后,驱逐该节点上所有 pod。
    • pod-eviction-timeout:NotReady 状态节点超过该时间后,执行驱逐,默认 5 min,适用于k8s 1.13版本之前
    • 1.13版本后,集群开启TaintBasedEvictions 与TaintNodesByCondition 功能,即taint-based-evictions,即节点若失联或者出现各种异常情况,k8s会自动为node打上污点,同时为pod默认添加如下容忍设置:
TaintBasedEvictions(基于Taint的驱逐)和pod-eviction-timeout(Pod驱逐超时)都是Kubernetes中与Pod驱逐相关的概念。

TaintBasedEvictions是一种Pod驱逐策略,它基于节点的Taint设置来决定哪些Pod可以被驱逐。节点的Taint是一种标记,用于标识该节点是否允许运行一定类型的Pod。当节点需要被维护或升级时,管理员可以通过设置Taint来通知Kubernetes集群驱逐该节点上运行的一些Pod,以便在节点维护期间保持服务的高可用性。

pod-eviction-timeout是指在驱逐Pod时,Kubernetes等待Pod停止的最长时间。如果Pod在该时间内未能停止,则Kubernetes会强制终止Pod并进行重新调度。默认情况下,Pod驱逐超时时间是5分钟。

这两个概念之间的关系是:在TaintBasedEvictions策略中,如果节点上有一个Pod被标记为不可驱逐(例如Pod的PodDisruptionBudget对象设置了最小可用性),那么Pod-eviction-timeout参数将被忽略,Pod将不会被驱逐,以保证集群的最小可用性要求。否则,Pod将按照pod-eviction-timeout参数指定的时间进行Graceful Termination,并在超时后被强制终止和重新调度。

查看pod默认容忍

在 Kubernetes 中,当节点不可用或者不适合调度 Pod 时,Pod 会被调度器(Scheduler)拒绝调度。但是,在某些情况下,调度器拒绝调度一个 Pod 并不意味着该 Pod 无法在该节点上运行。例如,节点可能会因为维护或升级等原因暂时不可用,但是这种情况只是暂时的,节点很快就会恢复正常。

为了避免因为节点暂时不可用而频繁地调度 Pod,Kubernetes 允许在 Pod 中设置 tolerations 字段,来容忍一些特定的节点问题,例如节点不可用或者不稳定。其中 tolerationSeconds 字段可以设置容忍的时间(单位:秒)。如果节点的状态在容忍时间内得到了修复,Pod 就可以在该节点上运行,否则该 Pod 将被删除。

在这个例子中,tolerations 字段中的 tolerationSeconds: 300 表示 Pod 在节点不可用或者不稳定的情况下,可以容忍 300 秒。在这 300 秒内,如果节点状态得到修复,Pod 就可以在该节点上运行;否则该 Pod 将被删除。

这种容忍机制可以确保 Kubernetes 集群的稳定性和可用性。例如,当节点因为网络故障或其他原因暂时不可用时,容忍机制可以保证 Pod 不会频繁地被调度到不可用的节点上,从而提高应用程序的稳定性和可靠性。

[root@k8s-master ~]#kubectl -n yuchao get po ngx-test -oyaml
...
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300 
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300

k8s会给pod默认的加上容忍时间300秒,是因为防止机器的断网问题,宕机问题,超过300秒,立马被驱逐走;
留下五分钟时间,允许你的机器恢复正常
如果五分钟后,这台机器,还是有污点,pod就会被驱逐。

默认情况下,Kubernetes创建的Pod会自动添加一些容忍度(tolerations),这是因为Kubernetes集群中的Node节点可能会出现故障或者维护,此时Pod可能会被调度到其他节点上,而这个过程可能会导致Pod的部分或者全部容器在短时间内无法正常工作。

容忍度的作用就是告诉Kubernetes调度器,允许Pod在某些特定的情况下继续运行,例如节点不可用、节点处于未就绪状态等。这可以保证Pod的高可用性和稳定性。

在上面提供的配置信息中,tolerations的作用是容忍节点处于不可用或者未就绪状态的情况,tolerationSeconds参数表示节点可以在这段时间内不可用或者未就绪。

在实际的生产环境中,tolerations的配置需要根据具体的应用场景和业务需求进行调整。

图解

image-20230403155841873

即各pod可以独立设置驱逐容忍时间。

kubelet巡检

Kubelet: 周期性检查本节点资源,当资源不足时,按照优先级驱逐部分 pod

Kubernetes 中的 kubelet 组件负责管理每个节点上的容器,并与 API 服务器交互以接收 Pod 调度信息并报告节点的状态。为了确保节点的健康和稳定性,kubelet 组件需要定期对节点进行巡检,并向 Kubernetes API 服务器报告节点的资源使用情况和可用性。

在巡检期间,kubelet 会检查节点的各种资源,包括内存、存储空间和 inodes 等。具体来说,以下是一些常见的 kubelet 巡检项及其含义:

  • memory.available:节点可用内存,表示节点上未被占用的内存空间。
  • nodefs.available:节点根盘可用存储空间,表示节点上根目录挂载的文件系统中未被占用的存储空间。
  • nodefs.inodesFree:节点 inodes 可用数量,表示节点上根目录挂载的文件系统中未被占用的 inodes 数量。
  • imagefs.available:镜像存储盘的可用空间,表示节点上 Docker 镜像存储目录中未被占用的存储空间。
  • imagefs.inodesFree:镜像存储盘的 inodes 可用数量,表示节点上 Docker 镜像存储目录中未被占用的 inodes 数量。

通过对这些巡检项进行监控和报告,kubelet 可以帮助 Kubernetes 集群管理员了解节点的资源使用情况和健康状态,及时发现和解决潜在的问题,确保集群的稳定性和可用性。

/var/lib/containerd/ 
如磁盘超过80%,判断节点不可用。

回顾k8s调度

Kubernetes (k8s) Scheduler是一种重要的组件,它负责将Pods调度到合适的节点上运行。下面是Kubernetes Scheduler的用法总结:

  1. 默认情况下,Kubernetes Scheduler会尝试将Pods均匀地分配到可用的节点上,以保持集群的负载均衡。
  2. 如果您想将Pods调度到特定的节点上运行,可以通过为Pods设置节点选择器或节点亲和性规则来实现。
  3. 您还可以为Pods设置Pod优先级和调度期限,以确保高优先级的Pods尽快被调度,并在规定时间内完成调度。
  4. 如果您想要在节点上运行特定类型的工作负载,可以使用节点标签和Pod亲和性规则来实现。
  5. 您还可以自定义调度程序来实现更高级的调度策略,如优化资源利用率和降低资源浪费。
  6. Kubernetes Scheduler还支持预选和扩展,可以使用它们来扩展调度器的功能,并将自定义调度器集成到集群中。

总之,Kubernetes Scheduler是Kubernetes集群中一个非常重要的组件,可以根据不同的需求配置它的调度策略,以最大程度地提高集群的效率和性能。

image-20230407143115705

Copyright © www.yuchaoit.cn 2025 all right reserved,powered by Gitbook作者:于超 2024-03-31 19:28:26

results matching ""

    No results matching ""