概述
kubernetes的资源调度机制,包括kubernetes常用调度器和调度策略,调度优先级和抢占机制
描述什么是kubernetes资源调度
列举常用的kubernetes资源调度策略
描述kubernetes的资源抢占机制
目录
- Kubernetes资源管理
- Kubernetes调度器
- Kubernetes调度策略
- Kubernetes调度优先级和抢占机制
1. Kubernetes资源管理
1.1 查看node的资源管理信息
Kubernetes管理的资源所管理的集群中的每一台计算节点都包含一定的资源,我们通过kubectl get node xxx -o yaml得到节点有关资源的描述
[root@k8s-master ~]# k get node k8s-node1 -o yaml
apiVersion: v1
kind: Node
metadata:
annotations:
......
allocatable:
cpu: "2"
ephemeral-storage: "18561997179"
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 2796836Ki
pods: "110"
capacity:
cpu: "2"
ephemeral-storage: 19669Mi
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 2899236Ki
pods: "110"
.....
1.2 Capacity资源数据的获取
由于capacity反映的是这台机器的资源真实数量,所以确认这个信息的任务理所应当交给运行在每台机器上面的 kubelet上。kubelet目前把cadvisor的大量代码直接作为vendor引入。在kubelet启动后,这个内部的cadvisor子模块也会相应启动,并且获取这台机器上面的各种信息。其中就包括了有关这台机器的资源信息,而这个信息也自然作为这台机器的真实资源信息,通过kubelet再上报给 apiserver。
1.3 Kubernetes资源管理
- 实际上,Qos划分的主要应用场景,是当宿主机资源紧张的时候,kubelet对Pod进行Eviction(资源回收)时需要用到的。
- 当kubernetes所管理的不可压缩资源短缺时,就有可能触发Eviction,此类不可压缩资源包括:可用内存(memory.available),可用的宿主机磁盘nodefs.available),容器运行镜像存储空间(imagefs.available)等
- 在kubernetes,设置的eviction默认阈值为
memory.available<100Mi
nodefs.available<10%
nodefs.inodesFree<5%
imagefs.available<15%
1.4 Kubernetes资源管理
- 可以通过如下命令配置Evciton触发的阈值
kubelet --eviction�hard=imagefs.available<10%,memory.available<500Mi,nodefs.available<5%,no
defs.inodesFree<5% --eviction�soft=imagefs.available<30%,nodefs.available<10% --eviction-soft-grace�period=imagefs.available=2m,nodefs.available=2m --eviction-max-pod�grace-period=600
- Evciton分为以下两种模式
Soft模式:允许为某一项参数设置一个“优雅时间”,这段时间是为了给Pod预留出退出时间,当达到阈值之后一定时间之后,kubelet才会启动Eviction过程
Hard模式:当某一项参数达到阈值之后立刻触发,直接杀掉Pod
1.5 Kubernetes资源管理
原则:
1.出现资源紧张时,先对资源不足节点进行隔离
2.按照优先级,删除不重要的pod进行资源回收
- 当宿主机的Eviction阈值达到之后,就会进入MemoryPressure或DiskPressure的状态,从而避免新的Pod被调度到该节点上(通过给节点打上“污点”的方式实现)。
首先被删除的是Besteffort类别的Pod
其实是Burstable类别的Pod,并且使用的某一项缺少资源超出了requests值 最后是Guaranteed类别的Pod,并且Kubernetes会保证只有当该类型的Pod使用资源量超过了limits的限制,才会被Eviction选中
对于同类别Qos的Pod,kubernetes会根据优先级来选择移除的顺序
2 .Kubernetes调度器
- API Server在接受客户端提交Pod对象创建请求后,然后是通过调度器(kube�scheduler)从集群中选择一个可用的最佳节点来创建并运行Pod。而这一个创建Pod对象,在调度的过程当中有3个阶段:节点预选、节点优选、节点选定,从而筛选出最佳的节点。
节点预选:基于一系列的预选规则对每个节点进行检查,将那些不符合条件的节点过滤,
从而完成节点的预选。
节点优选:对预选出的节点进行优先级排序,以便选出最合适运行Pod对象的节点。
节点选定:从优先级排序结果中挑选出优先级最高的节点运行Pod,当这类节点多于1个时,则进行随机选择。 - 节点预选:在具体的调度流程中,默认调度器会首先调用一组叫做Predicate的算
法,来检查每个Node。 - 节点优选:然后再调用一组叫做Priority的调度算法,来给上一步预选到的每个Node
打分 - 最终得分最高的那个Node就是调度结果,当调度器对一个Pod调度成功,就会在
它的spec.nodeName字段填写上调度结果的名字
2.1 Kubernetes调度策略
- 预选策略(Predicates)实际上就是节点过滤器,例如节点标签必须能够匹配到Pod资源的标签选择器(PodMatchNodeSelector实现的规则),以及Pod容器的资源请求量不能大于节点上剩余的可分配资源(PodFitsResource规则)等等。
执行预选操作,调度器会逐一根据规则进行筛选,如果预选没能选定一个合适的节点,此时Pod会一直处于Pending状态,直到有一个可用节点完成调度。其常用的预选策略如下
CheckNodeCondition:检查是否可以在节点报告磁盘、网络不可用或未准备好的情况下将Pod对象调度其上。
CheckNodeLabelPresence:仅检查节点上指定的所有标签的存在性,要检查的标签以及其可否存在取决于用户的定义。
2.2 Predicates常用策略
CheckNodeCondition:检查是否可以在节点报告磁盘、网络不可用或未准备好的情况下将Pod对象调度其上。
PodToleratesNodeTaints:如果Pod对象中定义了spec.tolerations属性,则需要检查该属性值是否可以接纳节点定义的污点(taints)。
CheckServiceAffinity:根据当前Pod对象所属的Service已有其他Pod对象所运行的节点调度,目前是将相同的Service的Pod对象放在同一个或同一类节点上。
CheckVolumeBinding:检查节点上已绑定和未绑定的PVC是否满足Pod对象的存储卷需求。
PodFitsResources:检查节点上的CPU和内存资源是否满足Pod的requests字段。
2.3 Predicates常用策略
CheckNodeMemoryPressure:在给定了节点已经上报了存在内存资源压力过大的状态,则需要检查该Pod是否可以调度到该节点上。
CheckNodePIDPressure:如果给定的节点已经报告了存在PID资源压力过大的状态,则需要检查该Pod是否可以调度到该节点上。
CheckNodeDiskPressure:如果给定的节点存在磁盘资源压力过大,则检查该Pod对象是否可以调度到该节点上。
MatchInterPodAffinity:检查给定的节点能否可以满足Pod对象的亲和性和反亲和性条件,用来实现Pod亲和性调度或反亲和性调度。
2.4 Priorities常用策略
- 预选策略筛选出一个节点列表就会进入优选阶段(Priorities),在这个过程调度器会向每个通过预选的节点传递一系列的优选函数来计算其优先级分值,优先级分值介于0-10之间,其中0表示不适用,10表示最适合托管该Pod对象。
-
另外,调度器还支持给每个优选函数指定一个简单的值,表示权重,进行节点优先级分值计算时,它首先将每个优选函数的计算得分乘以权重,然后再将所有优选函数的得分相加,从而得出节点的最终优先级分值。权重可以让管理员定义优选函数倾向性的能力。
2.5 Priorities常用策略
LeastRequested: 最低要求,(CPU((capacity�sum(requested))10/capacity)+memory((capacity-sum(requested))10/capacity))
得数越高,得分越高
BalancedResourceAllocation: 以CPU和内存资源占用比率相近的得分越高
NodePreferAvoidPods:(优先级很高 得分位10 权重10000)根据节点注解信息
annotations是否有 "scheduler.alpha.kubernetes.io/preferAvoidePods" 如果有 则
不能运行
TaintToleration: Pod对象的spec.tolerations与节点的taints的进行匹配都检查,匹配
度越高,得分越低
SelectorSpreading: 标签选择器分散度,查找与当前pod对象同属一个标签选择器运行的pod的节点越少的得分越高
2.6 Priorities常用策略
InterPodAffinity: 在节点对Pod所需的资源等进行匹配,匹配的越多得分越高
NodeAffinity: 根据Pod中的nodeSelector对节点进行匹配都检查,匹配数量越多得分
越高
MostRequested: (CPU((capacity�sum(requested))10/capacity)+memory((capacity-sum(requested))10/capacity)),
用来替换 LeastRequestedPriority,给使用多资源的节点,更高的调度优先级,即尽量将资源利用率最大化。
NodeLabel: 检查节点是否拥有特定标签,无论标签值是否有值,只要存在就得分,条数越多分数越高
ImageLocality: 检查节点已有Pod所需镜像体积大小之和进行判断,存在的镜像体积越大,得分越高
4 Kubernetes调度优先级和抢占机制
- 正常情况下,当一个Pod被调度失败时,它就会进入Pending状态,直到Pod被更新,或者集群状态发生变化,调度器才会对这个Pod进行重新调度。但某些高优先级的Pod在调度失败后,并不会Pending,而是会驱逐某个Node上一些低优先级的Pod,这样就可以保证这个高优先级的Pod调度成功。
- 优先级(Priority)和抢占(Preemption)这两种机制是为了解决Pod调度失败之后该如何处理的问题,而非在Pod最开始的调度阶段被触发
4.1 PriorityClass
- 而在kubernetes中,优先级和抢占机制是在1.10版本后才逐步可用的。要使用这个机制,首先需要在kubernetes里提交一个Priorityclass的定义
apiVersion:
scheduling.k8s.io/v1beta1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
- 上述yaml文件中的globalDefault被设置成true的话,那就意味着这个PriorityClass的值会成为系统的默认值。false表示的是只希望声明使用该PriorityClass的Pod拥有值为1000000的优先级,而对于没有声明Priority的Pod来说,优先级就是0
4.2 Priorityclass
- kubernetes规定,优先级是一个32bit的整数,最大值不超过1000000000(10亿),并且值越大优先级越高。超过10亿的,是被kubernetes保留下来分配给系统pod使用的。目的是保证系统pod不会被用户抢占掉
[root@k8s-master ~]# k get priorityclasses.scheduling.k8s.io
NAME VALUE GLOBAL-DEFAULT AGE
system-cluster-critical 2000000000 false 88d
system-node-critical 2000001000 false 88d
[root@k8s-master ~]# k get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-584795fc57-76l7g 1/1 Running 303 103d
coredns-584795fc57-9nk6q 1/1 Running 303 104d
etcd-k8s-master 1/1 Running 75 104d
kube-apiserver-k8s-master 1/1 Running 75 104d
kube-controller-manager-k8s-master 1/1 Running 75 104d
kube-flannel-ds-amd64-6zdr2 1/1 Running 76 104d
kube-flannel-ds-amd64-hp2k7 1/1 Running 55 104d
kube-flannel-ds-amd64-wbbrw 1/1 Running 53 104d
kube-proxy-bcc2z 1/1 Running 74 104d
kube-proxy-c7kf4 1/1 Running 55 104d
kube-proxy-qpttz 1/1 Running 54 104d
kube-scheduler-k8s-master 1/1 Running 75 104d
[root@k8s-master ~]# k -n kube-system get pod kube-apiserver-k8s-master -o yaml | grep -i pri -A 5 -B 5
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.227.10
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
--
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-cluster-ip-range=10.96.0.0/12
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
image: k8s.gcr.io/kube-apiserver:v1.14.10
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
--
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
hostNetwork: true
nodeName: k8s-master
priority: 2000000000
priorityClassName: system-cluster-critical
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
tolerations:
[root@k8s-master ~]#
4.3 Priorityclass
- 创建完成后就可以在Pod创建过程中引用该对象
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
priorityClassName: high-priority
4.4 示例
- 创建pri class
[root@k8s-master ~]# cat pr.yaml
apiVersion: scheduling.k8s.io/v1beta1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false <== 设置该class是否为默认class,如果建立pod时没有指priclass,则使用默认class
description: "This priority class should be used for XYZ service pods only."
[root@k8s-master ~]# k apply -f pr.yaml
priorityclass.scheduling.k8s.io/high-priority created
[root@k8s-master ~]# k get priorityclasses.scheduling.k8s.io
NAME VALUE GLOBAL-DEFAULT AGE
high-priority 1000000 false 8s
system-cluster-critical 2000000000 false 104d
system-node-critical 2000001000 false 104d
确认创建结果
[root@k8s-master ~]# k describe priorityclasses.scheduling.k8s.io high-priority
Name: high-priority
Value: 1000000
GlobalDefault: false
Description: This priority class should be used for XYZ service pods only.
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"scheduling.k8s.io/v1beta1","description":"This priority class should be used for XYZ service pods only.","globalDefault":false,"kind":"PriorityClass","metadata":{"annotations":{},"name":"high-priority"},"value":1000000}
Events:
- 部署Pod,声明使用该PriorityClass对象
**编辑pod yaml文件
[root@k8s-master ~]# cat ~/ppod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx1
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
priorityClassName: high-priority
**应用ppod
[root@k8s-master ~]# k apply -f ppod.yaml
pod/nginx1 created
[root@k8s-master ~]# k get pod
NAME READY STATUS RESTARTS AGE
cm-test-pod 1/1 Running 57 21d
cmpod2 1/1 Running 55 21d
httpd-deployment-859778b7b6-5rwrn 1/1 Running 27 71d
httpd-deployment-859778b7b6-hfw9t 1/1 Running 27 71d
httpd-deployment-859778b7b6-l7vwd 1/1 Running 26 70d
nginx1 1/1 Running 0 5s
spod 1/1 Running 51 21d
**验证应用结果
[root@k8s-master ~]# k describe pod nginx1
Name: nginx1
Namespace: default
Priority: 1000000
Priority Class Name: high-priority