kubernetes学习笔记九(调度)

kubernetes学习笔记九(调度)

Scroll Down

1、简介

Scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分配到集群的节点上。调度的实现其实有很多要考虑的问题:

公平:如何保证每个节点都能被分配资源

资源高效利用:集群所有资源最大化被使用

效率:调度的性能要好,能够尽快地对大批量的 pod 完成调度工作

灵活:允许用户根据自己的需求控制调度的逻辑

Sheduler 是s作为单独的程序运行的,启动之后会一直监听 API Server(即持续连接API Server),获取PodSpec.NodeName为空的 pod(如果PodSpec.NodeName不为空,值为某一个节点的名称,那么意思就是该Pod指定要在该Node上运行),对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上。Scheduler调度到指定Node上,对应Node上的kubelet也将会获取到该监听信息,按照指定要求创建pod。

2、调度过程

调度分为几个部分:

首先是过滤掉不满足条件的节点,这个过程称为predicate( 可以理解为预选 );

然后对通过的节点按照优先级排序,这个是priority( 这个理解为优选 );

最后从中选择优先级最高的节点。

如果中间任何一步骤有错误,就直接返回错误

Predicate有一系列的算法可以使用 ( 部分罗列 ):

PodFitsResources:节点上剩余的资源是否大于 pod 请求的资源,如果节点上剩余资源不满足pod请求的资源则该结点不会被选择

PodFitsHost:如果 pod 指定了 NodeName( 即指定了要被调度在哪个Node上执行 ),检查节点名称是否和 NodeName 匹配

PodFitsHostPorts:节点上已经使用的 port 是否和 pod 申请的 port 冲突( pod申请的端口在Node上是否已被占用 )

PodSelectorMatches:过滤掉和 pod 指定的 label 不匹配的节点

NoDiskConflict:已经 mount 的 volume 和 pod 指定的 volume 不冲突,除非它们都是只读

如果在 predicate 过程中没有合适的节点,pod 会一直在pending状态,不断重试调度,直到有节点满足条件。经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程:按照优先级大小对节点排序

优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重(该项的重要性)。这些优先级选项包括:

LeastRequestedPriority:通过计算 CPU 和 Memory 的使用率来决定权重,使用率越低权重越高。也就是说,这个优先级指标倾向于资源使用比例更低的节点

BalancedResourceAllocation:节点上 CPU 和 Memory 使用率越接近,权重越高( 也就是说这个优先级指标倾向于CPU、Memory使用比例较接近的节点,这样证明调度性更好。比例接近举例来说就是一个节点cpu使用了10%,内存使用了50%,另一个节点cpu使用了30%,内存35%,那这个指标就更倾向于选择后者 )。这个指标应该和LeastRequestedPriority一起使用,不应该单独使用

ImageLocalityPriority:倾向于已经有要使用镜像的节点,镜像总大小值越大,权重越高

3、自定义调度器

除了 kubernetes 自带的调度器,你也可以编写自己的调度器。通过spec:schedulername参数指定调度器的名字,可以为 pod 选择某个调度器进行调度。比如下面的 pod 选择my-scheduler进行调度,而不是默认的default-scheduler

apiVersion: v1
kind: Pod
metadata:  
name: annotation-second-scheduler
labels:
 name: multischeduler-example
spec:
schedulername: my-scheduler
containers:
  - name: pod-with-second-annotation-container
    image: gcr.io/google_containers/pause:2.0

4、节点亲和性

用通俗的语言来说,节点亲和性就是pod比较倾向于某个节点,更愿意被调度到该节点执行。而节点亲和性又分为软策略和硬策略,软策略就是说pod比较倾向于该节点,但也不是必须要被调度到该节点;而硬策略则是必须要被调度到该节点。node亲和性的软策略可以定义一个权重值,权重值更大的则倾向性更强烈。

pod.spec.affinity.nodeAffinity:( nodeAffinity 即节点亲和性 )

preferredDuringSchedulingIgnoredDuringExecution:软策略

requiredDuringSchedulingIgnoredDuringExecution:硬策略

节点亲和性软策略测试:

apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
 app: node-affinity-pod
spec:
containers:
  - name: with-node-affinity
    image: nginx
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference: 
          matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - k8s-node1
      - weight: 2
        preference:
          matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - k8s-node2

prefered_node_affinity.jpg

prefered_node_affinity_weight.jpg

节点亲和性硬策略测试:(图里的强策略即硬策略~)

apiVersion: v1
kind: Pod
metadata:
name: affinity
labels: 
 app: node-affinity-pod
spec:
containers:
  - name: with-node-affinity
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - k8s-master1
            - k8s-node1
            - k8s-node2

require_node_affinity.jpg

require_node_appinity_no_node.jpg

operator

这个运算符不单单又一个IN,还有NotInGt等等一系列的,他们的作用分别是:

In:label 的值在某个列表中

NotIn:label 的值不在某个列表中

Gt:label 的值大于某个值

Lt:label 的值小于某个值

Exists:某个 label 存在

DoesNotExist:某个 label 不存在

节点亲和性的硬策略、软策略是可以放在一起使用的,当硬策略不满足的时候就看一下软策略是否满足

5、Pod亲和性

Pod亲和性和节点亲和性原理是一样的,不同的是:当特定的Pod1在某节点被调度了之后,"我"(指定了与Pod1亲和性的新Pod2)更倾向于被调度在Pod1所在的节点。当然,Pod 亲和性也有软硬之分,硬策略即为“我Pod2”必须要跟Pod1在一个节点上,软策略则为“我Pod2”可以跟Pod1在一起,也可以不在一起。pod亲和性的软策略也可以定义一个权重值,权重值更大的则倾向性更强烈。

官方.

pod 间亲和与反亲和性可以基于已经在节点上运行的 pod 的标签来约束新的 pod 可以调度到的节点,而不是基于节点的标签。 “ 如果 X 节点上已经运行了一个或多个 满足规则 Y 的pod,则新的 pod 应该(在反亲和的情况下为不应该)运行在 X 节点 ” 规则 Y表示一个具有可选的关联命令空间列表的 LabelSelector,因为node属于集群级别的资源,而pod则属于名称空间级别资源。X 是一个拓扑域,如同一个节点,同一个机架,同一个云供应商地区,同一个云供应商区域等, X 在资源清单中用topologyKey

( 我们这里演示测试topologyKey则使用的是节点,即kubernetes.io/hostname )

pod.spec.affinity.podAffinity/podAntAffinity:

preferredDuringSchedulingIgnoredDuringExecution:软策略

requiredDuringSchedulingIgnoredDuringExecution:硬策略

pod 亲和性硬策略测试:

首先在某一个节点上已经有了一个pod,

然后基于已存在Pod创建一个pod亲和性硬策略的新pod( 拓扑域为同一node ),

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

required_pod_affinity.jpg

如果pod亲和性硬策略匹配不到pod,那么新的pod直接会成为pending,直到匹配到该pod

require_affinity_pod_not.jpg

我们将上面的labelSelector下的标签换为一个不存在的:

require_affinity_edit_label.jpg

pod 反亲和性硬策略测试:

同样首先在某一个节点已经有了一个pod,

然后基于已存在Pod创建一个pod反亲和性硬策略的新pod( 拓扑域同样指定为同一node ),

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

required_pod_anti_affinity.jpg

6、亲和性/反亲和性调度策略比较:

名称调度策略匹配标签操作符拓扑域支持调度目标
节点亲和性nodeAffinity主机In,NotIn, Exists,DoesNotExist, Gt, Lt指定主机
pod亲和性podAffinityPodIn, NotIn, Exists,DoesNotExistPod与指定Pod同一拓扑域
pod反亲和性podAnitAffinityPodIn, NotIn, Exists,DoesNotExistPod与指定Pod不在同一拓扑域

同一拓扑域的意思是:

同一个节点,机架,云供应商地区,云供应商区域等。在yaml资源清单中,拓扑域用键topologyKey来表示

且,如果不同的node被不同的标签所划分,则拥有相同标签的node也可以被当成是一个拓扑域,如果想要通过这个标签来指定拓扑域的话,topologyKey就要设定为特定的标签值了

7、Taint(污点) 和 Toleration(容忍度)

节点亲和性,是pod的一种属性(偏好或硬性要求),它使pod被吸引到一类特定的节点。Taint(污点)则相反,它使节点能够排斥一类特定的pod

Tainttoleration相互配合,可以用来避免pod被分配到不合适的节点上。每个节点上都可以应用一个或多个taint,这表示:对于不能容忍节点上现有的这些taint的pod,不会被调度到该节点。如果将toleration应用于pod上,则表示:这些pod可以(但不是必须)被调度到具有匹配taint的节点上

( 简单来说就是,如果 node 上被打了一个或多个污点,不能接受这些污点的 pod 在调度时不会被调度到该node;如果pod在定义时,标明了可以容忍某些污点,那么该pod就能够被调度到具有这些污点的node上 )

Taint(污点)

Ⅰ、污点(Taint)的组成

使用kubectl taint命令可以给Node节点设置污点,Node被设置污点之后就和Pod之间存在一种相斥的关系,可以让Node拒绝Pod的调度执行,甚至将Node已经存在的Pod驱逐出去( 根据Node的taint effect 来决定 )

每个污点的组成如下:

key=value:effect

每个污点有一个key和value作为污点的标签,其中value可以为空,effect描述污点的作用。当前 taint effect 支持如下三个选项:
NoSchedule:表示 k8s 将不会把 Pod 调度到具有该污点的 Node 上
PreferNoSchedule:表示 k8s 会尽量避免将 Pod 调度到具有该污点的 Node 上
NoExcute:表示 k8s 不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去

Ⅱ、污点的设置、查看和去除

# 设置污点
kubectl  taint  nodes  node名称  key1=value1:effect(污点选项)

# 可以通过节点描述查找Taints字段,来查看节点是否被打了污点以及污点的选项是什么
kubectl  describe  pod    pod-name

# 去除污点(其实就是加污点命令后边加个“-”)
kubectl  taint  nodes  node名称  key1:NoSchedule-

taint_node.png

Tolerations(容忍)

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

Pod.spec.tolerations

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 上继续保留运行的时间

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

tolerations:
- operator: "Exists"

Ⅱ、当不指定 effect 值时,表示容忍所有的污点作用

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

Ⅲ、有多个 Master 存在时,防止资源浪费,可以如下设置

kubectl  taint  nodes  Node-Name  node-role.kubernetes.io/master=:PreferNoSchedule

简单示例:

apiVersion: v1
kind: Pod
metadata:
  name: 
spec:
  comtainers:
    name: tolerationstest
    image: nginx
  tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoSchedule"
    tolerationSeconds: 3600

8、指定调度节点

Ⅰ、Pod.spec.nodeName 将Pod直接调度到指定的Node节点上,会跳过Scheduler的调度策略,该匹配规则是强制匹配

apiVersion: v1
kind: Deployment
metadata:
name: myweb
spec: 
replicas: 7
template:
 metadata:
   labels:
     app: myweb
 spec:
   nodeName: k8s-node1
   containers:
      - name: myweb
        image: nginx
        ports:
        - containers: 80

Ⅱ、Pod.spec.nodeSelector:通过kubernetes的label-selector机制选择节点,由调度器调度策略匹配label,而后调度Pod到目标节点,该匹配规则属于强制约束

apiVersion: v1
kind: Deployment 
metadata:
  name: myweb
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: myweb
    spec:
      nodeSelector:
        type: backEndNode1  
        # 这里的键名key是type,键值value是backEndNode1,即当节点的标签键值对是type:backEndNode1时,pod才会被调度到该节点上,如果没有节点的标签键值对时type:backEndNode1,那么Pod直接Pending
      containers:
      - name: myweb
        image: nginx
        ports:
        - containerPort: 80