目录

一:K8s调度

1.1list-watch介绍(顺带一提)

1.2list-watch工作流程

二:亲和与反亲和

2.1Pod和Node

2.2硬亲和和软亲和

三:污点与容忍

3.1污点(Taint)

3.1.1污点的组成 

3.1.2污点的设置和去除

3.2容忍(Tolerations)

3.2.1Toleration 基本用法

3.2.2Toleration案例

3.3多污点与多容忍配置

一:K8s调度

  1. 调度器通过kubernetes的list-watch机制来发现集群中新创建且尚未被调度到Node上的Pod。调度器会将发现的每一个未调度的Pod调度到一个合适的Node上来运行。
  2. kube-scheduler是Kubernetes集群的默认调度器,并且是集群控制面的一部分。如果你真的希望或者有这方面的需求,kube-scheduler在设计上是允许你自己写一个调度组件并替换原有的kube-scheduler。
  3. 在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、亲和以及反亲和要求、数据局域性、负载间的干扰等等。

1.1list-watch介绍(顺带一提)

  1. Kubernetes 是通过 List-Watch 的机制进行每个组件的协作,保持数据同步的,每个组件之间的设计实现了解耦。
  2. 用户是通过 kubectl 根据配置文件,向 APIServer 发送命令,在 Node 节点上面建立 Pod 和 Container。                                                                                                                            APIServer 经过 API 调用,权限控制,调用资源和存储资源的过程,实际上还没有真正开始部署应用。这里需要 Controller Manager、Scheduler 和 kubelet 的协助才能完成整个部署过程。
  3. 在 Kubernetes 中,所有部署的信息都会写到 etcd 中保存。实际上 etcd 在存储部署信息的时候,会发送 Create事件给 APIServer,而 APIServer 会通过监听(Watch)etcd发过来的事件。其他组件也会监听(Watch)APIServer 发出来的事件。

1.2list-watch工作流程

Pod是Kubernetes的基础单元,Pod 启动典型创建过程如下

  1. 这里有三个 List-Watch,分别是 Controller Manager(运行在 Master),Scheduler(运行在Master),kubelet(运行在 Node)。他们在进程已启动就会监听(Watch)APIServer 发出来的事件。
  2. 用户通过 kubectl 或其他 API 客户端提交请求给 APIServer 来建立一个 Pod 对象副本。
  3. APIServer 尝试着将 Pod 对象的相关元信息存入 etcd 中,待写入操作执行完成,APIServer即会返回确认信息至客户端。
  4. 当 etcd 接受创建 Pod 信息以后,会发送一个 Create 事件给 APIServer。
  5. 由于 Controller Manager 一直在监听(Watch,通过http的8080端口)APIServer 中的事件。此时APIServer 接受到了 Create 事件,又会发送给 Controller Manager。
  6. Controller Manager 在接到 Create 事件以后,调用其中的 Replication Controller 来保证Node 上面需要创建的副本数量。一旦副本数量少于 RC 中定义的数量,RC 会自动创建副本。总之它是保证副本数量的Controller(PS:扩容缩容的担当)。
  7. 在 Controller Manager 创建 Pod 副本以后,APIServer 会在 etcd 中记录这个 Pod的详细信息。例如 Pod 的副本数,Container 的内容是什么。
  8. 同样的 etcd 会将创建 Pod 的信息通过事件发送给 APIServer。
  9. 由于 Scheduler 在监听(Watch)APIServer,并且它在系统中起到了“承上启下”的作用,“承上”是指它负责接收创建的Pod 事件,为其安排 Node;“启下”是指安置工作完成后,Node 上的 kubelet 进程会接管后继工作,负责 Pod生命周期中的“下半生”。 换句话说,Scheduler 的作用是将待调度的 Pod 按照调度算法和策略绑定到集群中 Node 上。
  10. Scheduler 调度完毕以后会更新 Pod 的信息,此时的信息更加丰富了。除了知道 Pod 的副本数量,副本内容。还知道部署到哪个Node 上面了。并将上面的 Pod 信息更新至 API Server,由 APIServer 更新至 etcd 中,保存起来。
  11. etcd 将更新成功的事件发送给 APIServer,APIServer 也开始反映此 Pod 对象的调度结果。
  12. kubelet 是在 Node 上面运行的进程,它也通过 List-Watch的方式监听(Watch,通过https的6443端口)APIServer 发送的 Pod 更新的事件。kubelet会尝试在当前节点上调用 Docker 启动容器,并将 Pod 以及容器的结果状态回送至 APIServer。
  13. APIServer 将 Pod 状态信息存入 etcd 中。在 etcd确认写入操作成功完成后,APIServer将确认信息发送至相关的 kubelet,事件将通过它被接受。

注意:在创建 Pod 的工作就已经完成了后,为什么 kubelet 还要一直监听呢?原因很简单,假设这个时候 kubectl 发命令,要扩充 Pod 副本数量,那么上面的流程又会触发一遍,kubelet 会根据最新的 Pod 的部署情况调整 Node 的资源。又或者 Pod 副本数量没有发生变化,但是其中的镜像文件升级了,kubelet 也会自动获取最新的镜像文件并且加载。


二:亲和与反亲和

亲和性的原理其实很简单,主要利用label标签结合nodeSelector选择器来实现

2.1Pod和Node

  • 从pod出发,可以分成亲和性和反亲和性,分别对应podAffinity和podAntiAffinity。
  • 从node出发,也可以分成亲和性和反亲和性,分别对应nodeAffinity和nodeAntiAffinity。
  • 从操作指令来讲,可以有ln、Notln、Exists、DoesNotExist等等。
针对亲和性来讲,in代表我要调度到有这个标签的位置
针对反亲和性来讲,in代表我不要调度到有这个标签的位置

2.2硬亲和和软亲和

软亲和:preferredDuringSchedulingIgnoredDuringExecution 

软策略:结合下面的 “operator: NotIn”,意思就是尽量不要将 pod 调度到匹配到的节点,但是如果没有不匹配的节点的话,也可以调度到匹配到的节点。

硬亲和:requiredDuringSchedulingIgnoredDuringExecution

 硬策略:结合下面的 “operator: In”,意思就是必须调度到满足条件的节点上,否则就等着 Pending。

不管哪种方式,最终还是要依赖 label 标签!!!!!

kubectl get pods -n company ai-action-statistic-gray-86465f9c4b-hdfk4 -oyaml | grep nodeSelector -B 5 -A 5
  uid: ed47f094-f70a-45ed-b7dd-d46f2d01986f
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:   #硬策略
        nodeSelectorTerms:
        - matchExpressions:
          - key: node-role.kubernetes.io/gray
            operator: In
            values:
            - gray
      preferredDuringSchedulingIgnoredDuringExecution:  #软策略
          - weight: 1
            preference:
              matchExpressions:
              - key: pc-app
                operator: NotIn
                values:
                - luna

三:污点与容忍

K8s 每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod 上,则表示这些 pod 可以(但不要求)被调度到具有相应 taint 的节点上。

3.1污点(Taint)

如果一个节点被标记为有污点,那么意味着不允许pod调度到该节点,除非pod也被标记为可以容忍污点节点。
在使用kubeadm部署的k8s集群的时候应该会发现,通常情况下,应用是不会调度到master节点的。因为kubeadm部署的k8s集群默认给master节点加了Taints(污点)。

3.1.1污点的组成 

使用kubectl taint命令可以给某个Node节点设置污点,Node被设置上污点之后就和Pod之间存在了一种相斥的关系,可以让Node拒绝Pod的调度执行,甚至将Node已经存在的Pod驱逐出去。

每个污点的组成如下:

key=value:effect

每个污点有一个key和value作为污点的标签,其中value可以为空,effect描述污点的作用。

污点有三种策略: 

  • PreferNoSchedule:NoSchedule的软策略版本,表示尽量不调度到污点节点上去。
  • NoExecute:该选项意味着一旦Taint生效,如该节点内正在运行的Pod没有对应容忍(Tolerate)设置,则会直接被逐出。
  • NoSchedule:表示k8s将不会将Pod调度到具有该污点的Node上

NoExecute和NoSchedule的区别:

  • NoSchedule只是不调度,但并不影响已经调度好的容器,即使给宿主机新增了污点,这些Pod依然会正常运行。同样PreferNoSchedule也是。
  • NoExecute就不一样了,会将Pod驱逐到其他宿主,除非该Pod容忍。

3.1.2污点的设置和去除

使用kubectl设置和去除污点的命令示例如下:

# 设置污点
kubectl taint nodes node1 key1=value1:NoSchedule
# 去除污点
kubectl taint nodes node1 key1:NoSchedule-

接下来看一个具体的例子,使用kubeadm部署和初始化的Kubernetes集群,master节点被设置了一个node-role.kubernetes.io/master:NoSchedule的污点,可以使用kubectl describe node 命令查看。这个污点表示默认情况下master节点将不会调度运行Pod,即不运行工作负载。

对于使用二进制手动部署的集群设置和移除这个污点的命令如下:

kubectl taint nodes <node-name> node-role.kubernetes.io/master=:NoSchedule
kubectl taint nodes <node-name> node-role.kubernetes.io/master:NoSchedule-

3.2容忍(Tolerations)

设置了污点的Node将根据taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,Pod将在一定程度上不会被调度到Node上。 但我们可以在Pod上设置容忍(Toleration),意思是设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的Node上。

3.2.1Toleration 基本用法

pod 的 Toleration 声明中的 key 和 effect 需要与 Taint 的设置保持一致,并且满足以下条件之一:

  1. operator 的值为 Exists,这时无需指定 value
  2. operator 的值为 Equal 并且 value 相等
  3. 如果不指定 operator,则默认值为 Equal。

另外还有如下两个特例:

  1. 空的 key 配合 Exists 操作符能够匹配所有的键和值
  2. 空的 effect 匹配所有的 effect

上面的例子中 effect 的取值为 NoSchedule,下面对 effect 的值作下简单说明:

  1. NoSchedule:如果一个 pod 没有声明容忍这个 Taint,则系统不会把该 Pod 调度到有这个 Taint 的 node 上
  2. PreferNoSchedule:NoSchedule 的软限制版本,如果一个 Pod 没有声明容忍这个Taint,则系统会尽量避免把这个 pod 调度到这一节点上去,但不是强制的。
  3. NoExecute:定义 pod 的驱逐行为,以应对节点故障。

NoExecute 这个 Taint 效果对节点上正在运行的 pod 有以下影响:

  • 没有设置 Toleration 的 Pod 会被立刻驱逐
  • 配置了对应 Toleration 的 pod,如果没有为 tolerationSeconds 赋值,则会一直留在这一节点中
  • 配置了对应 Toleration 的 pod 且指定了 tolerationSeconds 值,则会在指定时间后驱逐

3.2.2Toleration案例

tolerations:
 - key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
tolerationSeconds: 3600
 - key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
 - key: "key2"
operator: "Exists"
effect: "NoSchedule"
  • 其中key, vaule, effect要与Node上设置的taint保持一致
  • operator的值为Exists将会忽略value值
  • tolerationSeconds用于描述当Pod需要被驱逐时可以在Pod上继续保留运行的时间

下面看一下在Pod上设置容忍的两个特例:

示例1: 当不指定key值时,表示容忍所有的污点key:

tolerations:
- operator: "Exists"

示例2:当不指定effect值时,表示容忍所有的污点作用:

tolerations:
- key: "key"
operator: "Exists"

注意:  在节点故障情况下,为了保持现存的 pod 驱逐的限速设置,系统将会以限速的模式逐步给 node 设置 Taint,这就能防止在一些特定情况下(比如 master 暂时失联)造成的大量 pod 被驱逐的后果。这一功能兼容于 tolerationSeconds,允许 pod 定义节点故障时持续多久才被逐出。

3.3多污点与多容忍配置

系统允许在同一个 node 上设置多个 taint,也可以在 pod 上设置多个 Toleration。**Kubernetes 调度器处理多个 Taint 和 Toleration 能够匹配的部分,剩下的没有忽略掉的 Taint 就是对 Pod 的效果了。下面是几种特殊情况:

  • 如果剩余的 Taint 中存在 effect=NoSchedule,则调度器不会把该 pod 调度到这一节点上。
  • 如果剩余的 Taint 中没有 NoSchedule 的效果,但是有 PreferNoSchedule 效果,则调度器会尝试不会 pod指派给这个节点
  • 如果剩余 Taint 的效果有 NoExecute 的,并且这个 pod已经在该节点运行,则会被驱逐;如果没有在该节点运行,也不会再被调度到该节点上。
kubectl taint nodes node1 key1=value1:NoSchedule  
kubectl taint nodes node1 key1=value1:NoExecute  
kubectl taint nodes node1 key2=value2:NoSchedule
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐