1. 简介
Scheduler 是 Kubernetes 的调度器,主要任务是把定义的Pod分配到集群的节点上,要考虑以下几点:
- 公平:如何保证每个节点都能分配到资源;
- 资源高效利用:集群所有资源最大化被使用;
- 效率:调度性能要好,能够尽快的对大批量的Pod完成调度工作;
- 灵活:允许用户根据自己的需求控制调度的流程;
Scheduler 是作为单独的服务运行的,启动之后会一直监听API Server,获取podSpec.NodeName 为空的 Pod,对每个 Pod 都会创建一个buiding,表明该 Pod 应该放在哪个节点上。
2. 调度过程
- 首先过滤掉不满足条件的节点,这个过程称为 predicate;
- 然后对通过的节点按照优先级的顺序,这个是 priority;
- 最后从中选择优先级最高的节点。
- 如果中间有任何一步报错,则直接返回错误信息。
2.1 Predicate算法:
- PodFitsResources: 节点剩余资源是否大于Pod请求的资源
- PodFitsHost: 如果Pod指定了nodeName,检查节点名称是否和nodeName匹配
- PodFitsHostPort: 节点上已经使用的port是否和Pod申请的port冲突
- PodSelectorMatches: 过滤和Pod指定的label不匹配的节点
- NoDiskConfict: 已经mount的volume和Pod指定的volume不冲突,除非它们都是只读
如果在predicate过程中没有适合的节点,Pod会一直处理Pending状态,不断重新调度,直到有节点满足条件,经过这个步骤,如果有多节点满足条件,就会进入priority过程;
priority过程, 按照优先级大小对节点排序,优先级由一系列键值对组成,键是该优先级的名称,值是它的权重,优先级选项包括:
- LeastRequestedPriority: 通过计算CPU和Memory的使用率来决定权重,使用率越低权重越高
- BalanceResourceAllocation: 节点上CPU和Memory使用率的相近程度,比如:Node1的CPU和Memory使用率一个是48%一个50%,Node2的CPU和Memory使用率都是50%,则选择Node2
- ImageLocalityPriority: 倾向于已经要使用镜像的节点,镜像的总大小值越大,权重越高
3. 自定义调度器
除了Kubernetes自带的调度器,也可以编写自己的调度器,通过spec.schedulername参数指定调度器的名字,可以为Pod选择某个调度器进行调度。
比如下边的Pod选择my-scheduler进行调度,而不是默认的default-scheduler
apiVersion: v1kind: Podmetadata:name: scheduler-testlabels:name: example-schedulerspec:schedulername: my-schedulercontainers:- name: Pod-testimage: nginx:v1
Kubernetes的调度方式有以下几种:
- 亲和性:包括Node的亲和性和Pod的亲和性
- 污点(Taint)和容忍(Toleration)
- 固定调度策略
4. 亲和性
4.1 节点(Node)亲和性
pod.spec.affinity.nodeAffinity
preferredDuringSchedulingIgnoreDuringExecution: 软策略
- 软策略是偏向于,更想(不)落在某个节点上,但如果没有,落在其他节点也可以
requiredDuringSchedulingIgnoredDuringExecution: 硬策略
- 硬策略是必须(不)落在指定的节点上,如果不符合条件,则一直处于Pending状态
4.1.1 硬策略-演示
apiVersion: v1
kind: Pod
metadata:
name: affinity-required
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-required
image: nginx:1.2.1
imagePullPolicy: IfNotPresent
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoreDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname // 节点名称
operator: NotIn // 不是
values:
- testcentos7 // node节点名称
以上策略表示:此Pod不要落在node名称为testcentos7的节点上
4.1.2 软策略-演示
apiVersion: v1
kind: Pod
metadata:
name: affinity-required
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-required
image: nginx:1.2.1
imagePullPolicy: IfNotPresent
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoreDuringExecution:
- weight: 100 // 权重为100,软策略中权重越高匹配到机会越大
preference: // 更偏向于
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- testcentos7
以上策略表示:此Pod更想落在node节点为testcentos7的node中
4.1.3 软硬策略合体
apiVersion: v1
kind: Pod
metadata:
name: affinity-required
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-required
image: nginx:1.2.1
imagePullPolicy: IfNotPresent
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoreDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- k8s-node2
preferredDuringSchedulingIgnoreDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: source
operator: In
values:
- hello
软硬结合达到一个更为准确的node选择,以上文件意思为此Pod必须不存在k8s-node2节点中,其他的节点都可以,但最好落在label中source的值为hello的节点中
4.1.4 键值运算关系
- In: label的值在某个列表里
- NotIn: label的值不在某个列表中
- Gt: label的值大于某个值
- Lt: label的值小于某个值
- Exists: 某个label存在
- DoseNotExist: 某个label不存在
注意:如果nodeSelectorTerms下面有多个选项,满足任何一个条件就可以了;如果matchExpressions有多个选项,则必须满足这些条件才能正常调度
4.2 Pod亲和性
pod.spec.affinity.podAffinity/podAntiAffinity
preferredDuringSchedulingIgnoreDuringExecution: 软策略
- 软策略是偏向于,更想(不)落在某个节点上,但如果没有,落在其他节点也可以
requiredDuringSchedulingIgnoredDuringExecution: 硬策略
- 硬策略是必须(不)落在指定的节点上,如果不符合条件,则一直处于Pending状态
4.2.1 Pod硬策略
apiVersion: v1
kind: Pod
metadata:
name: affinity-required
labels:
app: pod-3
spec:
containers:
- name: with-pod-required
image: nginx:1.2.1
imagePullPolicy: IfNotPresent
affinity:
podAffinity: // 在同一域下
requiredDuringSchedulingIgnoreDuringExecution:
- labelSelector:
matchExpressions:
- key: app // 标签key
operator: In
values:
- nginx // 标签value
topologyKey: kubernetes.io/hostname // 域的标准为node节点的名称
以上文件策略为:此Pod必须要和包含label为app:nginx的pod在同一node下
将podAffinity改为podAnitAffinity,使它们不再用于node节点下
apiVersion: v1
kind: Pod
metadata:
name: required-pod2
labels:
app: pod-3
spec:
containers:
- name: with-pod-required
image: nginx:1.2.1
imagePullPolicy: IfNotPresent
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
此策略表示,必须要和label为app:nginx的pod在不用的node节点上
4.2.2 Pod软策略
apiVersion: v1
kind: Pod
metadata:
name: affinity-required
labels:
app: pod-3
spec:
containers:
- name: with-pod-required
image: nginx:1.2.1
imagePullPolicy: IfNotPresent
affinity:
podAntiAffinity: // 不在同一域下
preferredDuringSchedulingIgnoreDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- pod-2
topologyKey: kubernetes.io/hostname
软策略和硬策略的方法基本类似,只是添加了权重,表示更喜欢而已,也可以接受其他。
4.2 亲和性/反亲和性调度策略比较:
| 调度策略 | 匹配标签 | 操作符 | 拓扑域支持 | 调度目标 |
|---|---|---|---|---|
| nodeAffinity | 主机 | In, NotIn, Exists, DoseNotExists, Gt, Lt | 否 | 指定主机 |
| podAffinity | Pod | In, NotIn, Exists, DoseNotExists, Gt, Lt | 是 | pod与指定pod在一拓扑域 |
| podAnitAffinity | Pod | In, NotIn, Exists, DoseNotExists, Gt, Lt | 是 | pod与指定pod不在一拓扑域 |
5. 污点(Taint)和容忍(Toleration)
节点亲和性,是Pod的一种属性(偏好或硬性要求),它使Pod被吸引到一类特定的节点,Taint则相反,它使节点能够 排斥 一类特定的Pod。
Taint与Toleration相互配合,可以用来避免Pod被分配到不合适的节点上,每个节点上都可以应用一个或两个taint,这表示对那些不能容忍这些污点的pod是不会被该节点接受的,如果将toleration应用于pdo,则表示这些pod可以(但不要求)被调度到具有匹配taint节点上。
5.1 污点(Taint)
5.1.1 污点的组成
使用kubectl taint命令可以给某个node节点设置污点,Node被设置上污点之后就和Pod之间存在了一种相斥的关系,可以让Node拒绝Pod的调度执行,甚至将已经存在的Pod驱逐出去
每个污点的组成如下:
key=value:effect
每个污点有一个key和value作为污点标签,其中value可以为空,effect描述污点的作用,当前effect支持如下三个选项:
- NoSchedule: 表示k8s不会将Pod调度到具有该污点的Node上;
- PreferNoSchedule:表示k8s将尽量避免将Pod调度到具有该污点的Node上;
- NoExecute:表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已有的Pod驱逐出去
5.1.2 污点的设置、查看和去除
k8s的master节点本身就带有effect类型为NoSchedule的污点;具体查看:
kubectl describe node centos8
Taints: node-role.kubernetes.io/master:NoSchedule
设置污点:
kubectl taint nodes [node name] key1=value:NoSchedule
去除污点:
kubectl taint nodes [node name] key1:NoSchedule-
5.2 容忍(Toleration)
设置了污点的Node将根据taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,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、value、effect要与Node中的taint保持一致
- operator是的值为Exists将会忽略value的值,值为Equal时则必须匹配相同的value
- tolerationSeconds用于描述当Pod需要驱逐时可以在Node上继续保留运行的时间
- 当不指定key时,表示容忍所有污点的key:
tolerations:
- operator: "Exists"
effect: "NoSchedule"
- 当不指定effect值时,表示容忍所有的污点类型
tolerations:
- key: "key1"
value: "value1"
operator: "Exists"
