k8s之pod资源调度

k8s之pod资源调度

调度器概述

​ 调度器kube-scheduler负责将pod调度到合适的节点上,然后由该节点上的kubelet运行该pod,

​ 调度器有多种,k8s内置的默认的调度器,也是最常用的,叫default-scheduler,

​ 默认调度器的调度步骤:

  1. 预选:从所有节点中,过滤掉不符合pod定义要求的节点,如pod需要ssd类型磁盘的节点
  2. 排序:过滤后的节点,按照优先级排序
  3. 选中:排序后,选中优先级最高的,若多个最高优先级,则随机选一个

预选策略

https://kubernetes.io/docs/reference/scheduling/policies/#predicates

​ 预选即根据pod定义的需求,先过滤掉一批不符合要求的节点,如:

  • 节点的剩余资源不满足pod要求
  • pod要求的hostport,某些节点已经被占用
  • 节点的标签不满足pod要求
  • 节点有pod不能容忍的污点
  • ...

优选函数

https://kubernetes.io/docs/reference/scheduling/policies/#priorities

​ 根据一系列优选函数,考虑其各个因子的权重得出

节点亲和调度

​ 节点亲和调度是指利用pod的节点特性选择器和节点的既定标签将节点调度到特定特征节点上的机制;

​ 亲和度有软硬之分:即硬亲和为找不到需要的节点pod就一直处于pending状态,软亲和为尽量找到特征节点,如果找不到也会可以正常调度,找个其他节点;

节点硬亲和性

​ nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution定义节点的硬亲和性,

1、语法:在亲和性定义字段,有节点亲和、pod间亲和、pod间反亲和三个子字段;

[root@client ~]# kubectl explain pods.spec.affinity
KIND:     Pod
VERSION:  v1

RESOURCE: affinity <Object>

DESCRIPTION:
     If specified, the pod's scheduling constraints

     Affinity is a group of affinity scheduling rules.

FIELDS:
   nodeAffinity	<Object>
     Describes node affinity scheduling rules for the pod.

   podAffinity	<Object>
     Describes pod affinity scheduling rules (e.g. co-locate this pod in the
     same node, zone, etc. as some other pod(s)).

   podAntiAffinity	<Object>
     Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod
     in the same node, zone, etc. as some other pod(s)).

2、示例:

​ 通过匹配表达式匹配了zone在foo或bar里且带有ssd磁盘的节点,若集群没有该节点,则调度失败;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVerion: v1
kind: Pod
metadata:
 name: require-nodeAffinity
spec:
 affinity:
  nodeAffinity:
   requiredDuringSchuedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchExpressions:
      - {key: zone, operator: In, values: ["foo","bar"]}
      - {key: ssd, operator: Exists, values: []}
      
...      

节点软亲和性

​ nodeAffinity.perferredDuringSchedulingIgnoredDuringExecution定义节点的硬亲和性,

1、语法:

[root@client ~]# kubectl explain pods.spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution
KIND:     Pod
VERSION:  v1

FIELDS:
   preference	<Object> -required-
     A node selector term, associated with the corresponding weight.

   weight	<integer> -required-
     Weight associated with matching the corresponding nodeSelectorTerm, in the
     range 1-100.

2、示例:

​ 子字段,preference定义匹配节点的表达式,weight定义该表达式的权重,如下示例中,若pod定义副本够大的情况下,假设集群中存在,1-同时有ssd和zone是foo的节点、2-只是zone在foo的节点,3-只有ssd的三类节点,那么调度pod数量比例应该是9:6:3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVerion: v1
kind: Pod
metadata:
 name: require-nodeAffinity
spec:
 affinity:
  nodeAffinity:
   preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 60
      preference:
       matchExpressions:
        - {key: zone,operator:In,values: ["foo"]}
    - weight: 30
      perference:
       matchExpressions:
       - {key: ssd,operator: Exists,values:[]}
...       

pod间亲和调度

​ 出于网络通信高效的需要:有时需要相关pod被调度到相近的位置,此时需要pod间亲和调度;

​ 出于安全或异地多活高可用的需要:有时需要相同pod的副本调度到不同的机架、机房、地区等,此时需要pod间反亲和调度;

​ pod间亲和调度也有“软”和“硬”之分;

何为pod的位置

​ pod间亲和或反亲和就是考虑pod之间处于远或近,或相同节点位置,pod的位置就是节点,节点的位置可以靠节点的标签指定,节点的位置:(同位置可能是同节点、同机架、同机房,靠topoloyKey 字段定义)可能是:

  • 同节点
  • 不同节点
    • 不同机架
    • 不同机房
    • 不同地区

pod间硬亲和

1、先定义一个“基准”pod,默认调度器正常调度

kubectl run tomcat -l app=tomcat --image tomcat:alpine

2、定义第一个pod,依赖基准pod的位置,调度到和其相同的节点

​ 由于亲和性,第二个pod应该必须调度到和tomcat节点一样的“位置”,而这个位置的标准是同一个节点,由toppologyKey定义,其值kubernetes.io/hostname是k8s内建的节点标签,

​ 也可以定义自己的代表位置的“位置标签”,如rack机架、zone可用区等;查找时,只要节点带有相同的rack标签或zone标签,就视为同一个位置,可调度;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: v1
kind: Pod
metadata:
 name: affinity-tomcat
spec:
 affinity:
  podAffinity:
   requiredDuringSchedulingIgnoreDuringExecution:
   - labelSelctor:
      matchExpressions:
      - {key: app,operator: In,values: ["tomcat"]}
     topologyKey: kubernetes.io/hostname 

pod间软亲和

​ 软亲和是在根据定义找不到特定的pod所在位置做“同位置”调度时,也可以找个别的地儿调度

示例:

​ weight定义权重、podAffinityTerm定义选择要亲和的pod的标准

​ 其中在调度时,调度器会将集群节点分为4类:cache pod和db pod都在的zone,cache pod单独在的zone,db pod单独在的zone,以及其他zone,若这几种zone都存在,且副本样本数够大,调度比例约为:10:8:2;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
kind: Pod
metadata:
 name: preferred-affinity
spec:
 affinity:
  podAffinity:
   preferredDuringSchedulingIgnoreDuringExecution:
- weight: 80
  podAffinityTerm:
   labelSelector:
    matchExpressions:
    - {key: app,operator: In,values: ["cache"]}
    topologyKey: zone
- weight: 20
  podAffinityTerm:
   labelSelector:
    matchExpressions:
    - {key: app,operator: In,values: ["db"]}
    topologyKey: zone
...    

pod间反亲和

示例:

​ 调度时,3个副本的pod,会被调度到不同的节点上;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: apps/v1
kind: Deployment
metadata:
 name: pod-anti-affinity
spec:
 replicas: 3
 selector: 
  matchLabels:
   app: myapp
 template:
  metadata:
   name: myapp
   labels:
    app: myapp
  spec:
   affinity:
    podAntiAffinity:
     requiredDuringSchedulingIgnoredDuringExecution:
     - labelSelector:
        matchExpressions:
        - {key: app, operator: In,values: ["myapp"]}
        topologyKey: kubernets.io/hostname
...        

污点和容忍度

​ 污点taint为节点上的键值对型数据;容忍度tolerations为pod上定义的键值对型数据;

​ 定义pod时,nodeselector,和nodeaffinity都是提供了pod选择节点的能力,而taint而是提供了节点拒绝pod被调度到自己上的能力;

​ pod要想调度到一个具有一些污点的节点上时,其必须定义对应每个污点的容忍度,才可调度到该节点;如控制端节点定义的污点,可以让pod不被调度到其上;

​ k8s使用podtoleratenodetaints预选策略和tainttorerationpriority优选函数来完成此类型调度机制;

定义污点和容忍度

​ 污点taints定义在节点的nodespec中;容忍度tolerations定义在podspce中,都是键值对型数据;**另外支持一个effect标记,**effect共有3种:

  • NoSchedule:不能容忍该节点的pod,就不用调度了,但节点上现有pod不受影响
  • PreferNoSchedule:在没有其他节点可用时,也是可以忍忍节点的污点,然后调度
  • NoExecute:不能容忍该节点污点的pod,不调度,且节点已经存在的不能容忍该污点的pod会被驱逐

定义污点整体的语法格式:key=value:effect;

pod上定义容忍度的语法格式有2种:

  • 等值判断:即和节点定义的污点key value effect完全一致
  • 存在判断:即和节点定义的污点key effect完全一致,value要为空

示例:

​ kubeadm部署集群时,master节点定义了一个污点,且一般创建的pod没有对应的容忍度,因此调度时,master节点就不会被调度到普通的pod,而管理型pod如k8s组件,kube-proxy,kube-flannel这种需要在master节点运行的pod,则会添加对应的容忍度,以实现调度到master节点;

master节点的污点:

[root@client ~]# kubectl describe nodes/master
Name:               master
Roles:              master

#污点,键值数据为 node-role.kubernetes.io/master,效果effect是noschedule,
#未定义相应容忍度的就不能调度到master节点
Taints:             node-role.kubernetes.io/master:NoSchedule

​ 一般pod的容忍度:

[root@client ~]# kubectl describe pods/limit-pod1
Name:               limit-pod1
Namespace:          default

Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
#普通pod,并未有对master那个键值的相应容忍度

k8s组件的容忍度

[root@client ~]# kubectl describe pods/kube-apiserver-master -n kube-system

Tolerations:       :NoExecute
# api-server的pod有容忍所有的noexecute

管理节点的污点

​ 节点上的污点通常用于描述具体的部署规划,键名有如:node-type,node-role,node-project等

添加:

​ kubectl taint可以管理节点的污点,键值对数据,语法:添加时,effect不同,就是不同的污点

kubectl taint nodes <node-name> <key>=<value>:<effect> ...

例如:
kubectl taint nodes node1.bo.com node-type=production:NoSchedule


删除:

​ 删除某key下所有的污点,如node-type

kubectl taint nodes node1 node-type-

​ 删除某key下某个effcet的污点,

kubectl taint nodes node1 nodt-type:NoSchedule-

​ 删除节点上的全部污点

kubectl patch nodes node1 -p '{"spec":{"taints":[]}}'

节点的污点变动,会影响后续新建pod的调度结果,且若effect是NoExecute,还会影响节点上现有对象

管理pod的容忍度

​ 定义pod的容忍度时,有2种方式,在spec.tolerations中定义;

1、等值判断

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExcute"
  tolerationSeconds: 3600  #定义污点变化时,驱逐当前pod的延时时长
  

2、存在判断

tolerations:
- key: "key1"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 3600

ps:实践中,若集群中有专为运行非生产型容器(测试,开发环境)准备,可以添加相应污点,运行测试和开发pod时,添加对应容忍度即可,还有,针对特殊硬件,如高性能ssd或gpu的节点,可以添加相应污点,然后在特殊需求的pod上添加对应的容忍度;

标识问题节点

​ k8s自1.6后,支持使用污点,自动标识问题节点,它通过节点控制器,在监测到节点到了某特定状态时,自动为其添加相应的污点,都使用noexecute标识,即节点现有的pod也会被驱逐;

​ 常用内建污点:

  • node.kubernetes.io/not-ready:节点进入not-ready状态时自动添加
  • node.alpha.kubernets.io/unreachable:节点进入notreachable时自动添加
  • node.kubernetes.io/out-of-disk
  • node.kubernetes.io/disk-pressure
  • node.kubernetes.io/network-unavailable
  • node.cloudprovider.kuberntes.io/unintitialized
  • 以上均为node进入到相应状态后,由节点控制其监测到变化,并添加污点
  • 但,k8s核心组件,管理型附件,一般需要容忍此类污点,以确保这些pod能被部署上去,如kube-proxy,kube-flannel这种必须的

pod优先级和抢占式调度

​ k8s自1.8后,支持pod的资源优选,即区分了pod对象的重要程序,一个高优先级重要的pod无法被调度时,(如它能调度的节点,却资源不足了)调度器会驱逐节点上比它优先级低的pod,来调度它这个优先级高的;

​ 默认禁用,需要在api-server、schduler、kubelet的启动参数中添加PodPriority=true才行;

​ 优先级定义由pod.spec.priorityClassName定义

示例:

[root@client ~]# kubectl describe pods/kube-apiserver-master -n kube-system
Name:               kube-apiserver-master
Namespace:          kube-system
Priority:           2000000000
PriorityClassName:  system-cluster-critical
updatedupdated2020-12-012020-12-01
加载评论