1、调度过程说明
1.1、简介
Scheduler是kubernetes的调度器。主要的任务是把定义的pod分配到集群的节点上。听起来非常简单,但是有很多考虑的问题:
1、公平:如何保证每个节点都能被分配资源
2、资源高效利用:集群所有资源最大化被利用
3、效率:调度的性能要好,能够尽快的对大批量的pod完成调度工作
4、灵活:允许用户根据自己的需求控制调度的逻辑
Sheduler是作为单独的程序运行的,启动之后会一直坚挺API server,获取podspec,nodename为空的pod,对每个pod都会创建一个binding,表明该pod应该放到哪个节点上
1.2、调度过程
调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为predicate;然后对通过的节点按照优先级排序,这个是priority;最后从中选择优先级最高的节点,如果中间任何一步骤有错误,就直接返回错误
1.3、Predicate有一系列的算法可以使用
PodFitsResources:节点上剩余的资源是否大于pod请求的资源
PodFitsHost:如果pod指定了nodename,检查节点名称是否和nodename匹配
PodFitsHostPorts:节点上已经使用的port是否和pod申请的port冲突
PodSelectorMatches:过滤掉和pod指定的label不匹配的节点
如果在predicate过程中没有合适的节点,pod会一直在pending状态,不断重试调度,直到有节点满足条件,经过这个步骤,如果有多个节点满足条件,就继续priorities过程:按照优先级大小对节点排序
优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重(该项的重要性)。这些优先级选项包括:
1、LeastRequestedPriority:通过计算cpu和memory的使用率来决定权重,使用率越低权重越高。也就是说,这个优先级指标倾向于资源使用比例更低的节点
2、BalancedResourceAllocation:节点上cpu和memory使用率越接近,权重越高。这个应该和第一个一起使用,不应该单独使用
3、ImagelocalityPriority:倾向于已经有要使用镜像的节点,镜像总大小值越大,权重越高
2、自定义调度器
除了kubernetes自带的调度器,你也可以编写自己的调度器。通过spec:schedulername参数指定调度器的名字,可以为pod选择某个调度器进行调度。比如下面的pod选择my-scheduler进行调度,而不是默认default-scheduler
apiVersion: v1
kind: Pod
metadata:
name: annotation-second-scheduler
labels:
name: multischeduler-example
spec:
schedulername: my-scheduler
containers:
- name: nginx
image: nginx
3、集群调度——亲和性
3.1、节点亲和性
3pod.spec.nodeAffinity
preferredDuringSchedulingIgnoredDuringExecution:软策略 (可/也不可)
requiredDuringSchedulingIgnoredDuringExecution:硬策略 (必须)
requiredDuringSchedulingIgnoredDuringExecution:硬策略
示例
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node1
检查
只要kubernetes.io/hostname等于node1,pod一定不会运行在node1节点上,如果把NoIn改为In,只要kubernetes.io/hostname等于node1则pod一定会运行在node1节点上。(kubernetes.io/hostname为node的标签 可以使用kubectl get no --show-labels 查看)
preferredDuringSchedulingIgnoredDuringExecution:软策略
示例
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: nginx
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node3
检查
kubernetes.io/hostname等于node3,pod一定会运行在node3节点上,如果没有node3这个节点pod会随机运行(kubernetes.io/hostname为node的标签 可以使用kubectl get no --show-labels 查看)
键值运算关系
1、In:label的值在某个列表中
2、NotIn:label的值不在某个列表中
3、Gt:label的值大于某个值
4、Lt:label的值小于某个值
5、Exists:某个label存在
6、DoesNotExist:某个label不存在
如果“nodeSelectorTerms”下面有多个选项的话,满足任何一个条件就可以了;如果“matchExpressions”有多个选项的话,则必须同时满足这些条件才能正常调度pod
3.2、pod亲和性
pod.spec.affinity.podAffiinity/podAntiAffinity
preferredDuringSchedulingIgnoredDuringExecution:软策略 (可/也不可)
requiredDuringSchedulingIgnoredDuringExecution:硬策略 (必须)
requiredDuringSchedulingIgnoredDuringExecution:硬策略
示例
apiVersion: v1
kind: Pod
metadata:
name: pod-3
labels:
app: pod-3
spec:
containers:
- name: pod-3
image: nginx
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- node1
topologyKey: kubernetes.io/hostname
说明
如果标签app的值为node1,则这两个pod运行在同一个node节点上。如果把podAffinity改为podAntiAffinity,则这两个pod不会运行在同一个node节点上
preferredDuringSchedulingIgnoredDuringExecution:软策略
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
volumes:
- node1
4、亲和性/反亲和性调度策略比较
调度策略 | 匹配标签 | 操作符 | 拓扑域支持 | 调度目标 |
---|---|---|---|---|
nodeAffinity | 主机 | In,NotIn,Exists,DoesNotExist,Gt,Lt | 否 | 指定主机 |
podAffinity | POD | In,NotIn,Exists,DoesNotExist | 是 | POD与指定POD在同一拓扑域 |
podAnitAffinity | POD | In,NotIn,Exists,DoesNotExist | 是 | POD与指定POD不再同一拓扑域 |
5、集群调度——污点和容忍
节点亲和性是pod的一种属性,它使pod被吸引到一类特定的节点。Taint则相反,它使节点能够排斥一类特定的pod
Taint和Toleration相互配合,可以用来避免pod被分配到不合适的节点上,每个节点上都可以应用一个或多个taint,这表示对于那些不能容忍这些taint的pod,是不会被该节点接受的,如果将toleration应用于pod上,则表示这些pod可以(但不要求)被调度到具有匹配taint的节点上
6、污点(Taint)
6.1、污点(taint)的组成
使用kubectl taint命令可以给某个node节点设置污点,node被设置上污点之后就和pod之间存在了一种相斥的关系,可以让node拒绝pod的调度执行,甚至将node已经存在的pod驱逐出去
6.2、每个污点的组成如下
key=value:effect
说明:每个污点有一个key和value作为污点的标签,其中value可以为空,effect描述污点的作用。当前taint effect支持以下三个选项
1、NoSchedule:表示k8s不会将pod调度到具有污点的node上
2、PreferNoSchedule:表示k8s将尽量避免pod调度到具有该污点的Node上
3、NoExecute:表示不会将pod调度到具有该污点的node上,同时会将node上已经存在的pod驱逐出去
6.3、污点的设置、查看和去除
6.3.1、设置污点
kubectl taint node node1 check=liuchao:NoExecute
6.3.2、节点说明中,查找taint字段
kubectl describe pod pod-name
6.3.3、去除污点
kubectl taint nodes 节点名 key1:NoSechdule-
7、容忍(Tolerations)
设置了污点的node将根据taint的effect:NoSchedule、preferNoSchedule、NoExecute和pod之间产生互斥的关系,pod将在一定程度上不会被调度到node上,但是我们可以在pod上设置容忍(toleration),意思是设置了容忍的pod将可以容忍污点的存在,可以被调度到存在污点的pod上
示例
pod.spec.tolerations
apiVersion: v1
kind: Pod
metadata:
name: node1
labels:
app: node1
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: "check"
operator: "Equal" //运算关系
value: "liuchao"
effect: "NoExecute"
tolerationSeconds: 60 (60s之后pod会被清除)
检查
[root@master affi]# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node1 0/1 ContainerCreating 0 3s <none> node1 <none> <none>
[root@master affi]# kubectl get po -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node1 1/1 Running 0 7s 10.244.1.118 node1 <none> <none>
node1 1/1 Terminating 0 60s 10.244.1.118 node1 <none> <none>
字段说明
1、其中key,value,effect要与Node上设置的taint保持一致
2、operator的值为Exists将会忽略value值
3、tolerationSeconds用于描述当pod需要被驱逐时可以在pod上继续保留运行的时间
当不指定key值时,表示容忍所有的污点key
tolerations:
- operator: "Equal"
value: "liuchao"
effect: "NoExecute"
tolerationSeconds: 60
当不指定effect值时,表示容忍所有的污点作用
tolerations:
- key: "check"
operator: "Equal"
value: "liuchao"
tolerationSeconds: 60
有多个master存在时,防止资源浪费,可以加如下设置
kubectl taint nodes node名 node-role.kubernetes.io/master=:preferNoSchedule
意思是尽量不使用master资源,如果node节点资源不够时,会调度到master上
8、固定节点
指定调度节点
1、Pod.spec.nodeName将pod直接调度到指定的node节点上,会跳过Scheduler的调度策略,该撇配规则是强制匹配
示例
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 4
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
nodeName: node1
检查
[root@master affi]# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATE
nginx-75fc58ff6b-cb9k6 1/1 Running 0 28s 10.244.1.122 node1 <none> <none>
nginx-75fc58ff6b-h5xj5 1/1 Running 0 28s 10.244.1.119 node1 <none> <none>
nginx-75fc58ff6b-nxs7n 1/1 Running 0 28s 10.244.1.120 node1 <none> <none>
nginx-75fc58ff6b-trn97 1/1 Running 0 28s 10.244.1.121 node1 <none> <none>
所有的pod都在node1节点上运行
根据node的label进行选择
2、pod.spec.nodeSelector:通过kubernetes的label-selector机制选择节点,由调度器调度策略匹配label,然后调度pod到目标节点,该匹配规则属于强制约束
示例
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-web
spec:
replicas: 2
template:
metadata:
labels:
app: nginx-web
spec:
nodeSelector:
type: nginx-web
containers:
- name: nginx-web
image: nginx
ports:
- containerPort: 80
检查
[root@master affi]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-web-54df7bd47-46v7p 0/1 Pending 0 9s
nginx-web-54df7bd47-8x8m7 0/1 Pending 0 10s
pending状态
设置标签
[root@master affi]# kubectl label nodes node1 type=nginx-web
[root@master affi]# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-web-54df7bd47-46v7p 1/1 Running 0 7m39s 10.244.1.123 node1 <none> <none>
nginx-web-54df7bd47-8x8m7 1/1 Running 0 7m40s 10.244.1.124 node1 <none> <none>