【Linux39-14】k8s集群调度与驱离(scheduling+Eviction)(节点分配、污点和容忍度)



一、Kubernetes 调度器


【集群调度官方文档:https://kubernetes.io/zh/docs/concepts/scheduling-eviction/kube-scheduler/

在 Kubernetes 中,调度 是指将 Pod 放置到合适的 Node 上,然后对应 Node 上的 Kubelet 才能够运行这些 pod。

调度器通过 kubernetes 的监测(Watch)机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。 调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。 调度器会依据下文的调度原则来做出调度选择

1.1 kube-scheduler


【kube-scheduler命令官方文档:https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-scheduler/

kube-scheduler 是 Kubernetes 集群的默认调度器,并且是集群 控制面 的一部分。 如果你真的希望或者有这方面的需求,kube-scheduler 在设计上是允许 你自己写一个调度组件并替换原有的 kube-scheduler。

对每一个新创建的 Pod 或者是未被调度的 Pod,kube-scheduler 会选择一个最优的 Node 去运行这个 Pod。然而,Pod 内的每一个容器对资源都有不同的需求,而且 Pod 本身也有不同的资源需求。因此,Pod 在被调度到 Node 上之前, 根据这些特定的资源调度需求,需要对集群中的 Node 进行一次过滤。

在一个集群中,满足一个 Pod 调度请求的所有 Node 称之为 可调度节点。 如果没有任何一个 Node 能满足 Pod 的资源请求,那么这个 Pod 将一直停留在 未调度状态直到调度器能够找到合适的 Node。

调度器先在集群中找到一个 Pod 的所有可调度节点,然后根据一系列函数对这些可调度节点打分, 选出其中得分最高的 Node 来运行 Pod。之后,调度器将这个调度决定通知给 kube-apiserver,这个过程叫做 绑定

在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、 亲和以及反亲和要求、数据局域性、负载间的干扰等等。

二、节点选择约束方式


【约束节点官方文档:https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/

master端:server2
node节点:server3、server4
Harbor仓库:server1


2.1 nodeName


nodeName 是节点选择约束的最简单方法,但由于其自身限制,一般不推荐。
如果 nodeName 在 PodSpec 中指定了,则它优先于其他的节点选择方法。

使用 nodeName 来选择节点的一些限制:

  • 如果指定的节点不存在。
  • 如果指定的节点没有资源来容纳 pod,则pod 调度失败。
  • 云环境中的节点名称并非总是可预测或稳定的。

nodeName示例:

此pod将运行在server3上

在这里插入图片描述

# pod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeName: server3

nodeName 的值改为不存在的节点:server5,则一直处于 Pending 状态,一会会后自动取消调度

在这里插入图片描述

2.2 nodeSelector


nodeSelector 是节点选择约束的最简单推荐形式

nodeSelector 示例:

1)添加标签 disktype=ssd 到节点

在这里插入图片描述

2)添加 nodeSelector 字段到 Pod 配置中

在这里插入图片描述

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd

2.3 亲和性与反亲和性


【亲和性与反亲和性官方:https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/#%E4%BA%B2%E5%92%8C%E6%80%A7%E4%B8%8E%E5%8F%8D%E4%BA%B2%E5%92%8C%E6%80%A7

  • nodeSelector 提供了一种非常简单的方法来将 pod 约束到具有特定标签的节点上。亲和/反亲和功能极大地扩展了你可以表达约束的类型。
  • 你可以发现规则是“软”/“偏好”,而不是硬性要求,因此,如果调度器无法满足该要求,仍然调度该 pod
  • 你可以使用节点上的 pod 的标签来约束,而不是使用节点本身的标签,来允许哪些 pod 可以或者不可以被放置在一起。

亲和性功能包含两种类型的亲和性:

  • 节点亲和性:节点亲和性就像现有的 nodeSelector(但具有上面列出的前两个好处)
  • Pod 间亲和性/反亲和性:约束 Pod 标签而不是节点标签

2.3.1 节点亲和性(nodeAffinity)


两种类型的节点亲和性:

  • requiredDuringSchedulingIgnoredDuringExecution:硬需求(必须满足的规则)
  • preferredDuringSchedulingIgnoredDuringExecution:软需求(将尝试执行但不能保证)

nodeaffinity支持多种规则匹配条件的配置:

  • In:label 的值在列表内
  • NotIn:label 的值不在列表内
  • Gt:label 的值大于设置的值,不支持Pod亲和性
  • Lt:label 的值小于设置的值,不支持pod亲和性
  • Exists:设置的label 存在
  • DoesNotExist:设置的 label 不存在

“IgnoredDuringExecution” 表示如果在Pod运行期间Node的标签发生变化,导致亲和性策略不能满足,则继续运行当前的Pod。

节点亲和性通过 PodSpec 的 affinity 字段下的 nodeAffinity 字段进行指定。

节点亲和性示例: 规定硬需求为 disktype=ssddisktype=sata,软需求为 roles=nginx

# pod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity
spec:
  containers:
  - name: nginx
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: disktype
               operator: In
               values:
                 - ssd
                 - sata
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: roles
            operator: In
            values:
            - nginx

1)只有节点server3满足硬需求,调度server3

在这里插入图片描述

2)节点server3和server4都满足硬需求,server4满足软需求,调度server4

在这里插入图片描述

3)节点server4满足软需求,但两个节点都不满足硬需求,无节点可调度,处于 Pending 状态

在这里插入图片描述

2.3.2 pod 间亲和性与反亲和性


Pod 间亲和性与反亲和性需要大量的处理,这可能会显著减慢大规模集群中的调度。 我们不建议在超过数百个节点的集群中使用它们。


通过 PodSpec 中的两个字段进行指定:

  • podAffinity:pod间亲和性(主要解决POD可以和哪些POD部署在同一个拓扑域中的问题(拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的cluster、zone等)
  • podAntiAffinity:pod间反亲和性(主要解决POD不能和哪些POD部署在同一个拓扑域中的问题。它们处理的是Kubernetes集群内部POD和POD之间的关系)

与节点亲和性一样,当前有两种类型的 Pod 亲和性与反亲和性,即requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution,分别表示“硬性”与“软性”要求。

topologyKey 是节点标签的键以便系统 用来表示这样的拓扑域

亲和性示例: 将pod:myapp必须调度到带有标签 app=nginx 的pod上

在这里插入图片描述

 cat pod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
---
apiVersion: v1
kind: Pod
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  containers:
  - name: myapp
    image: myapp:v1
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: kubernetes.io/hostname

反亲和性示例: 将pod:myapp必须调度到没有标签 app=nginx 的pod上

将上述文件的参数 podAffinity 改为 podAntiAffinity

在这里插入图片描述

三、污点和容忍度


NodeAffinity节点亲和性,是Pod上定义的一种属性,使Pod能够按我们的要求调度到某个Node上,而Taints则恰恰相反,它可以让Node拒绝运行Pod,甚至驱逐Pod。

  • Taints(污点)是Node的一个属性,设置了Taints后,所以Kubernetes是不会将Pod调度到这个Node上的
  • Tolerations(容忍),只要Pod能够容忍Node上的污点,那么Kubernetes就会忽略Node上的污点,就能够(不是必须)把Pod调度过去。

3.1 污点


污点有关命令:

# 增加污点
kubectl taint nodes 节点 key1=v1:NoSchedule
# 查看污点
kubectl describe nodes 节点 | grep Taints
# 删除污点
kubectl taint nodes 节点 key1=v1:NoSchedule-

effect 可取值:

  • NoSchedule:POD 不会被调度到标记为 taints 节点,只会影响新创建的pod。
  • PreferNoSchedule:NoSchedule 的软策略版本。
  • NoExecute:该选项意味着一旦 Taint 生效,如该节点内正在运行的 POD 没有对应Tolerate 设置,会直接被逐出。

污点示例

1)创建pod

# pod.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx

2)在节点server3上增加污点 NoExecute ,发现server3的调度被驱离

在这里插入图片描述

3)在节点server4上增加污点 NoSchedule ,增加副本数,应用pod文件,发现新创建的pod处于 pending 状态,但以前调度在server4上的pod仍旧Running

在这里插入图片描述

3.2 容忍度


一个容忍度和一个污点相“匹配”是指它们有一样的键名和效果,并且:

  • operator 是 Exists (此时容忍度不能指定 value)即这个容忍度能容忍任意 taint。
  • operator 是 Equal (默认):则它们的 value 应该相等

容忍示例: 在污点示例文件添加容忍如下

1)添加容忍 Exists ,有任意污点的节点都可以被调度

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
      tolerations:
      - operator: "Exists"

在这里插入图片描述

2)增加副本数足够大(这里设为15),master节点也会被调度

在这里插入图片描述

3)删除污点

在这里插入图片描述

四、其他调度策略


影响Pod调度的指令还有:cordon、drain、delete,后期创建的pod都不会被调度到该节点上,但操作的暴力程度不一样。


4.1 cordon 停止调度


影响最小:

  • 只会将节点调为 SchedulingDisabled
  • 新创建pod时,不会被调度到该节点
  • 节点原有pod不受影响,仍正常对外提供服务。

# 停止调度
kubectl cordon server3
# 恢复
kubectl uncordon server3

cordon 示例:

在这里插入图片描述

4.2 drain 驱逐节点


  • 首先会驱逐node上的pod,在其他节点重新创建
  • 然后将节点调为 SchedulingDisabled

# 驱逐
kubectl drain server3
# 恢复
kubectl uncordon server3

drain 示例:
在这里插入图片描述

4.3 delete 删除节点


最暴力的一个:

  • 首先驱逐node上的pod,在其他节点重新创建
  • 然后,从master节点删除该node,master失去对其控制

如要恢复调度,需进入node节点,重启kubelet服务(基于node的自注册功能,恢复使用)

# 删除节点
kubectl delete node server3
# 基于node的自注册功能,恢复使用
systemctl restart kubelet

delete 示例:

1)在master节点删除server3
在这里插入图片描述

2)在node节点重启 kubelet 服务,master端查询已经自注册

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46069582/article/details/115099954