K8s-调度器
K8s-调度器
引入:Scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分 配到集群的节点上。听起来非常简单,但有很多要考虑的问题:
公平:如何保证每个节点都能被分配资源
资源高效利用:集群所有资源最大化被使用
效率:调度的性能要好,能够尽快地对大批量的pod完成调度工作
灵活:允许用户根据自己的需求控制调度的逻辑
调度过程
调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称 为 预选;然后对通过的节点按照优先级排序,这个是 优选;最后从中 选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误
预选算法
PodFitsResources:节点上剩余的资源是否大于 pod 请求的资源
PodFitsHost:如果 pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配
PodFitsHostPorts:节点上已经使用的 port 是否和 pod 申请的 port 冲突
PodSelectorMatches:过滤掉和 pod 指定的 label 不匹配的节点
NoDiskConflict:已经 mount 的 volume 和 pod 指定的 volume 不 冲突,除非它们都是只读
注意:如果在 预选 过程中没有合适的节点,pod 会一直在 pending 状态,不 断重试调度,直到有节点满足条件。经过这个步骤,如果有多个节点满 足条件,就继续 优选 过程: 按照优先级大小对节点排序 优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重 (该项的重要性)。这些优先级选项包括:
LeastRequestedPriority:通过计算 CPU 和 Memory 的使用率 来决定权重,使用率越低权重越高。换句话说,这个优先级指标倾向于资源使用比例更低的节点
BalancedResourceAllocation:节点上 CPU 和 Memory 使用率 越接近,权重越高。这个应该和上面的一起使用,不应该单独使用
ImageLocalityPriority:倾向于已经有要使用镜像的节点,镜像总 大小值越大,权重越高 通过算法对所有的优先级项目和权重进行计算,得出最终的结果
自定义调度器
除了 kubernetes 自带的调度器,你也可以编写自己的调度器。通 过 spec:schedulername 参数指定调度器的名字,可以为 pod 选择某 个调度器进行调度。比如下面的 pod 选择 my-scheduler 进行调度, 而不是默认的 default-scheduler
apiVersion: v1
kind: Pod
metadata:
name: test-scheduler
labels:
name: test-scheduler
spec:
schedulername: tets-scheduler
containers:
- name: pod-with-second-annotation-container
image: chenxiyanglinux/myapp:v1
调度亲和性
节点亲和性
pod亲和性
节点亲和性
pod.spec.nodeAffinty
软策略: preferredDuringSchedulingIgnoredDuringExecution--软亲和
硬策略: requiredDuringSchedulingIgnoredDuringExecution--硬亲和
键值运算关系
In:label 的值在某个列表中
NotIn:label 的值不在某个列表中
Gt:label 的值大于某个值
Lt:label 的值小于某个值
Exists:某个 label 存在
DoesNotExist:某个 label 不存在
注意: 如果nodeSelectorTerms
下面有多个选项的话,满足任何一个 条件就可以了;如果matchExpressions
有多个选项的话,则必须同时 满足这些条件才能正常调度 POD
硬亲和演示,基于以下模块完成
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: chenxiyanglinux/myapp:v1
affinity:
nodeAffinity:
requireDuringSchedulingIgnoreDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kuberbetes.io/hostname
operator: NotIn
values:
- k8s-node02
# 基于此文件允许,一定会被调度到node01节点
测试,将NotIn改为In,node02改为03,看是否一直处于pending状态(并没有node03机器)
软亲和演示,基于以下模块完成
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: chenxiyanglinux/myapp:v1
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: source
operator: In
values:
- qikqiak
# 由于K:V值表示的是主机标签,所以如果没有此标签,则随机调度
$ kubectl get node --show-labels #可查看节点标签
由于主机没有该标签值,所以根据优选算法随机调度
现在测试,将两node节点标签分别更改,完成下面测试
kubectl label node k8s-node02 disktype=ssd
kubectl label node k8s-node01 disktype=hdd
验证,基于以下模板完成
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: chenxiyanglinux/myapp:v1
affinity:
nodeAffinity:
requireDuringSchedulingIgnoreDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: NotIn
values:
- ssd
# 按照模板--应该运行在hdd才符号要求--node01
软硬亲和结合
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: chenxiyanglinux/myapp:v1
affinity:
nodeAffinity:
requireDuringSchedulingIgnoreDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: NotIn
values:
- k8s-master01
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
#因目前环境只有两台环境所以一定在node02上运行,
结论:
无论是软亲和的K:V还是硬亲和的K:V,它都代表的是主机的标 签
硬亲和使用,看性能是否达到不可用状态,否则一般采用软亲和 两者结合先看硬亲和,再看软亲和
如果nodeSelectorTerms
下面有多个选项的话,满足任何一个条件 就可以了;如果matchExpressions
有多个选项的话,则必须同时满足 这些条件才能正常调度 POD
pod亲和性
软策略: preferredDuringSchedulingIgnoredDuringExecution-- 软亲和
硬策略: requiredDuringSchedulingIgnoredDuringExecution-- 硬亲和
注意:pod亲和性通过pod标签去确定,--- 拓扑域决定pod在哪运行
以下面模板测试硬亲和
apiVersion: v1
kind: Pod
metadata:
name: pod-3
labels:
app: pod-3
spec:
containers:
- name: pod-3
image: chenxiyanglinux/myapp:v1
affinity:
podAffinity:
requireDuringSchedulingIgnoreDuringExecution:
- labelSelector:
mathExpressions:
- key: app
operator: In
values:
- node-affinity-pod
topologyKey: kuberbetes.io/hostname
# 若运行在node02节点,则证明验证成功
因指定的拓扑域是node-affinity-pod是在node02节点运行,所以 pod-3一定是在node02节点运行
现在再基于下面模板创建,测试如果拓扑域两个节点都有,它会在哪个 节点运行
先修改两节点标签
基于以下模板验证
apiVersion: v1
kind: Pod
metadata:
name: pod-4
labels:
app: pod-4
spec:
containers:
- name: pod-4
image: chenxiyanglinux/myapp:v1
affinity:
podAffinity:
requireDuringSchedulingIgnoreDuringExecution:
- labelSelector:
mathExpressions:
- key: app
operator: In
values:
- node-affinity-pod
topologyKey: level
为了方便我们抓到在哪个节点运行,我们执行以下命令
kubectl apply -f pod4.yaml && kubectl get pod -o wide && kubectl delete -f pod4.yaml
这就能看到,拓扑域如果一样就随机调度了,还是会基于优选算法去调度
测试反亲和性--podAntiAffinity
基于以下模板完成
apiVersion: v1
kind: Pod
metadata:
name: pod-4
labels:
app: pod-4
spec:
containers:
- name: pod-4
image: chenxiyanglinux/myapp:v1
affinity:
podAntAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector
matchExpressions:
- key: app
operator: In
values:
- node-affinity-pod
topologyKey: kuberbetes.io/hostname
# 按照要求,则不会在node02节点运行,那只能在node01节点运行了
亲和性/反亲和性调度策略比较如下
调度策略 | 匹配 标签 | 操作符 | 拓扑域 支持 | 调度目标 |
---|---|---|---|---|
nodeAffinity | 主机 | In, NotIn, Exists, DoesNotExist, Gt, Lt | 否 | 指定主机 |
podAffinity | POD | In, NotIn, Exists, DoesNotExist | 是 | POD与指定POD同一拓扑域 |
podAnitAffinity | POD | In, NotIn, Exists, DoesNotExist | 是 | POD与指定POD不在同一 拓扑域 |
Taint(污点)和Toleration(容忍)
节点亲和性,是 pod 的一种属性(偏好或硬性要求),它使 pod 被吸引到一类特定的节点。Taint 则相反,它使 节点 能够 排斥 一类特 定的 pod
Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合 适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那 些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod 上,则表示这些 pod 可以(但不要求)被调度 到具有匹配 taint 的节点上
污点(taint)
使用 kubectl taint 命令可以给某个 Node 节点设置污点,Node 被 设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去
- 污点组成
key=value:effect
说明: 每个污点有一个 key 和 value 作为污点的标签,其中 value 可以 为空,effect 描述污点的作用。当前 taint effect 支持如下三个选项
NoSchedule:表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上
PreferNoSchedule:表示 k8s 将尽量避免将 Pod 调度到具有该污 点的 Node 上
NoExecute:表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去,适合升级使用
-
污点的设置、查看、去除
-
设置污点:value1值可以没有
-
kubectl taint node node1 key1=value1:NoSchedule
eg: kubectl taint node k8s-master01 noderole.kubernetes.io/master=:PreferNoSchedule
-
-
节点说明中,查找Tains字段
- kubectl describe node node-name
-
去除污点
-
kubectl taint node node1 key1:NoSchedule-
kubectl taint node k8s-master01 noderole.kubernetes.io/master:NoSched-
-
容忍(Tolerations)
设置了污点的 Node 将根据 taint 的 effect:NoSchedule、 PreferNoSchedule、NoExecute 和 Pod 之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。 但我们可以在 Pod 上设置容 忍 ( Toleration ) ,意思是设置了容忍的 Pod 将可以容忍污点的存在, 可以被调度到存在污点的 Node 上
Tolerations写法,即在创建pod时指定说明要在哪个污点的节点运行 pod.spec.tolerations,以下三种写法都可以
tolerations:
- key: "key1" ---此种方法最精确,完全匹配
operator: "Equal" ---运算符
value: "value1" ---值
effect: "NoSchedule" ---策略
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600 ----清理pod的限期
- key: "key2"
operator: "Exists"
effect: "NoSchedule"
说明:
当不指定key值时,表示容忍所有的污点key
tolerations:
- operator: "Exists"
当不指定effect值时,表示容忍所有的污点作用
tolerations:
- key: "key"
operator: "Exists"
有多个Master存在时,防止资源浪费,可以做如下设
kubectl taint node Node-Name noderole.kubernetes.io/master=:PreferNoSchedule
eg:kubectl taint node k8s-master01 noderole.kubernetes.io/master=:PreferNoSchedule
实例:污点、亲和性、容忍的结合使用
如何指定在node01运行key为gpu值的deployment实例,参照以下 模板,基于node01节点已经创建了关于gpu的污点,
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 100
selector:
matchLabels:
app: nginx
template:
matadata:
labels:
app: nginx
spec:
affinity:
nodeAffinity:
requireDuringSchedulingIgnoreDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: computeengine
operator: In
values:
- gpu
tolerations:
- key: "computeengine"
operator: "Equal"
values: "GPU"
effect: "NoSchedule"
# 如果不容忍污点,则不会被调度,如果容忍污点,则不会被污点所干扰,若结合亲和性使用,则可达到在指定的污点节点运行具体的实例
固定节点调度
pod.spec.nodeName将pod直接调度到指定的Node节点上,会跳 过Scheduler的调度策略,该匹配规则是强制匹配 基于以下模板完成
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myweb
spec:
replicas: 7
template:
metadata:
labels:
app: myweb
spec:
nodeName: k8s-node01
containers:
- name: myweb
image: chenxiyanglinux/myqpp:v1
ports:
- containerPort: 80
Pod.spec.nodeSelector:通过 kubernetes 的 label-selector (标签 选择器)机制选择节点,由调度器调度策略匹配 label,而后调度 Pod 到 目标节点,该匹配规则属于强制约束
基于以下模板完成
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mywe1
spec:
replicas: 10
template:
metadata:
labels:
app: myweb
spec:
nodeSelector:
type: backEndNode1
containers:
- name: myweb
image: chenxiyanglinux/myqpp:v1
ports:
- containerPort: 80
注:因指定的标签选择器不存在,所以一直处于pending状态,正验证了此实验
或着将node01节点的标签改一下,做此次实验
再将模板中的标签替换成刚该的标签
验证完成