作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.Kubernetes调度器及调度机制
Kubernetes有一个程序名称为kube-scheduler的组件,它是负责K8S集群的调度工作,主要工作是完成Pod在哪个Node节点上运行。
kube-scheduler也是kube-apiserver的客户端,它关注kube-apiserver的Pods资源清单中的nodeName(我们在编写资源清单时可以指定Pods被调度到哪个节点上运行)的值是否为空,若为空,则k8s默认的调度器会在众多的Node节点选择一个最佳的Pod节点来运行此Pod,选定以后,他就把最初的节点名赋值给NameNode字段并提交给kube-apiserver程序(kube-apiserver会将该数据保存到etcd中)。由于kubelet也监听了kube-apiserver的pods资源,当对应的pods信息发生改变时,kube-apisever会将消息发送给对应的kebulet节点,而后kubelet通过调用本地的docker引擎来创建对应的pods资源。
kube-scheduler默认调度器工作逻辑评估一个节点的步骤分为:预选(predicate),优先(priority)和选定(select)。
预选(predicate):
K8S有很多预选器和预选程序来帮忙评估某个节点是否符合Pods的基本运行要求。这些基础要求包括但不限于存储卷过滤器(Volume Filters),CPU,内存等资源过滤器(Resource Filter),拓扑过滤器(Topology Fileters)。
比如一个20个节点集群过滤掉有污点的节点,仅剩下node102,node108,node109,node113,node117,node119,node120这7个节点。这7个节点可以进行下一步评估,那被排除掉的13个节点则不会参与下一轮评估。
优先(priority):
K8S有很多优先级选择函数,每一个节点被带入到每一个优先级选择函数,经由所有优先级选择函数得到的分值的累加结果就是该节点的最终得分。而后,基于最终得分进行虚拟排序,从中选择最高的分数节点来允许Pods。
通过预选阶段后的节点可能有多个,那么默这多个节点会有一个评分机制,会根据各节点进行评分哪个节点运行Pods的环境最佳进行打分。
如果能直接得出一个最高分的节点,那么下一步骤基本上就敲定该pods在哪个节点上运行。如果不能直接得出一个最高分,话句话说,有多个节点同时得到最高分,比如从上一步节点过滤出来的node102,node117,node120这3个节点并列第一,那么会进行下一步骤。
选定(select):
通过优先阶段后的节点也可能有多个,那么选定阶段就得从多个节点中随机选定一个节点来进行调度。
K8S的调度器也是插件化实现的,我们可以使用内建的调度器,用户也可以自定义调度器,并且在创建Pods时咱们可以指定使用什么调度器来帮我们创建Pods。如果我们编写Pods的资源清单时没有指定调度器,则K8S会使用默认的内置调度器(default scheduler)。
如果你有Golang基础,建议查看Kubernetes源码,查看源码可以看到最新发布版本的具体实现逻辑,当然你得有扎实的Go基础,具体可以参考下面给出Kubernetes的GitHub地址.
博主推荐阅读:
https://github.com/kubernetes/kubernetes/tree/master/pkg/scheduler
[root@master200.yinzhengjie.org.cn ~]# kubectl explain pods.spec.schedulerName
KIND: Pod
VERSION: v1
FIELD: schedulerName <string>
DESCRIPTION:
If specified, the pod will be dispatched by specified scheduler. If not
specified, the pod will be dispatched by default scheduler.
[root@master200.yinzhengjie.org.cn ~]#
[root@master200.yinzhengjie.org.cn ~]# kubectl explain pods.spec.schedulerName #用于定义Pods调度器的关键字
[root@master200.yinzhengjie.org.cn ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-demo 1/1 Running 0 43s
[root@master200.yinzhengjie.org.cn ~]#
[root@master200.yinzhengjie.org.cn ~]#
[root@master200.yinzhengjie.org.cn ~]# kubectl get pods pod-demo -o yaml | grep schedulerName
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"creationTimestamp":null,"name":"pod-demo","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.14-alpine","imagePullPolicy":"IfNotPresent","name":"nginx","resources":{}}],"dnsPolicy":"ClusterF
irst","enableServiceLinks":true,"priority":0,"restartPolicy":"Always","schedulerName":"default-scheduler","securityContext":{}}} schedulerName: default-scheduler
[root@master200.yinzhengjie.org.cn ~]#
[root@master200.yinzhengjie.org.cn ~]# kubectl get pods pod-demo -o yaml | grep schedulerName #定义Pods时若没有指定调度器名称,则使用默认的调度器
二.节点倾向性(Node Affinity)
节点倾向性(也可以称为关联性/亲和性)在概念上类似于nodeSelector,它允许您基于节点上的标签约束pod有资格被调度的节点。
如下所示,节点倾向性分为硬限制和软限制(我们甚至还可以自定义硬限制和软限制的标准),后缀命中的"IgnoredDuringExecution"意思是调度完成后,即使节点标签发生改变而不再符合调度条件时并不会影响到已经调度完成的结果,这类似于nodeSelector的共组逻辑。
硬限制:
requiredDuringSchedulingIgnoredDuringExecution
软限制:
preferredDuringSchedulingIgnoredDuringExecution
新的节点亲和性(Node Affinity)语法支持以下运算符(其中NotIn和DoseNotExist可实现类似node anti-affinity的效果,即节点反亲和性):
In
NotIn
Exists
DoseNotExst
Gt
Lt
Node Affinty规则的生效方式如下所示:
同时指定的nodeSelector和nodeAffinity之间存在"与"关系,即符合条件的Node需要同时满足两个条件;
为nodeAffinity同时指定多个nodeSelectorTerms时,各条目间取逻辑"或"关系,即满足其中之一即可;
同一个nodeSelectTerms中的多个matchExpression存在逻辑"与"关系,即Node需要同时满足多个条件;
如果移除或更改pod计划所在节点的标签,pod将被移除。换句话说,关联选择仅在安排pod时有效;
preferredDuringSchedulingIgnoredDuringExecution中的权重字段在1-100之间;
对于满足所有调度需求的每个节点(资源请求,RequiredDuringScheduling关联表达式等),调度程序将通过迭代此字段的元素计算总和,并在节点对应的MatchExpression匹配时将"权重"添加到总和。
[root@master200.yinzhengjie.org.cn ~]# cat required-nodeAffinity-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: with-required-nodeaffinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: zone, operator: In, values: ["foo"]}
containers:
- name: myapp
image: ikubernetes/myapp:v1
[root@master200.yinzhengjie.org.cn ~]#
[root@master200.yinzhengjie.org.cn ~]# cat required-nodeAffinity-pod.yaml
[root@master200.yinzhengjie.org.cn ~]# cat required-nodeAffinity-pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: with-required-nodeaffinity-2
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: zone, operator: In, values: ["foo", "bar"]}
- {key: ssd, operator: Exists, values: []}
containers:
- name: myapp
image: ikubernetes/myapp:v1
[root@master200.yinzhengjie.org.cn ~]#
[root@master200.yinzhengjie.org.cn ~]# cat required-nodeAffinity-pod2.yaml
[root@master200.yinzhengjie.org.cn ~]# cat required-nodeAffinity-pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: with-required-nodeaffinity-3
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: zone, operator: In, values: ["foo", "bar"]}
- {key: ssd, operator: Exists, values: []}
containers:
- name: myapp
image: ikubernetes/myapp:v1
resources:
requests:
cpu: 6
memory: 20Gi
[root@master200.yinzhengjie.org.cn ~]#
[root@master200.yinzhengjie.org.cn ~]# cat required-nodeAffinity-pod3.yaml
三.Pod倾向性(Affinity)
和节点亲相信不同,节点倾向性指的是Pod和Node之间的关系,而Pod的倾向性指的是Pod与Pod之间的关系,比如多个Pods能否运行在同一个节点,能否运行在同一个机柜,能够运行在同一个机房等。