我是靠谱客的博主 轻松秋天,这篇文章主要介绍一起来学k8s 20.k8s 调度k8s 调度,现在分享给大家,希望可以做个参考。

k8s 调度

kube-scheduler 是 k8s 系统的核心组件之一,其主要职责就是通过自身的调度算法,为新创建的 Pod 寻找一个最合适的 Node。

主要包含如下几个步骤:

  • 通过一组叫做谓词 predicates 的过滤算法,先挑出满足条件的 Node;
  • 通过一组叫做优先级 priorities 的打分算法,来给上一步符合条件的每个 Node 进行打分排名;
  • 最终选择得分最高的节点,当然如果得分一样就随机一个节点,填回 Pod 的 spec.nodeName 字段。

官方流程图如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
For given pod: +---------------------------------------------+ | Schedulable nodes: | | | | +--------+ +--------+ +--------+ | | | node 1 | | node 2 | | node 3 | | | +--------+ +--------+ +--------+ | | | +-------------------+-------------------------+ | | v +-------------------+-------------------------+ Pred. filters: node 3 doesn't have enough resource +-------------------+-------------------------+ | | v +-------------------+-------------------------+ | remaining nodes: | | +--------+ +--------+ | | | node 1 | | node 2 | | | +--------+ +--------+ | | | +-------------------+-------------------------+ | | v +-------------------+-------------------------+ Priority function: node 1: p=2 node 2: p=5 +-------------------+-------------------------+ | | v select max{node priority} = node 2

scheduler 的工作看似很简单,但其实不然。考虑的问题非常多,比如要保证每个节点被公平调度,提高资源利用率,提高 pod 调度效率,提升调度器扩展能力等等。

Kubernetes的调度器以插件化形式实现的,方便用户定制和二次开发。用户可以自定义调度器并以插件形式与Kubernetes集成,或集成其他调度器,便于调度不同类型的任务。

Kubernetes调度器的源码位于kubernetes/plugin/中,大体的代码目录结构如下所示:

复制代码
1
2
3
4
5
6
7
8
9
kubernetes/plugin/pkg/ `-- scheduler //调度相关的具体实现 |-- algorithm | |-- predicates //节点筛选策略 | `-- priorities //节点打分策略 | `-- util |-- algorithmprovider | `-- defaults //定义默认的调度器 12345678

Scheduler创建和运行的过程, 对应的代码在plugin/pkg/scheduler/scheduler.go。
上面初步介绍了Kubernetes调度器,在新增Pod的过程中,调度器的调度策略被分成两个阶段:Predicates阶段和Priorities阶段

Predicates

  • CheckNodeConditionPred 检查节点是否正常
  • GeneralPred HostName(如果pod定义hostname属性,会检查节点是否匹配。pod.spec.hostname)、PodFitsHostPorts(检查pod要暴露的hostpors是否被占用。pod.spec.containers.ports.hostPort)
  • MatchNodeSelector pod.spec.nodeSelector 看节点标签能否适配pod定义的nodeSelector
  • PodFitsResources 判断节点的资源能够满足Pod的定义(如果一个pod定义最少需要2C4G node上的低于此资源的将不被调度。用kubectl describe node NODE名称 可以查看资源使用情况)
  • NoDiskConflict 判断pod定义的存储是否在node节点上使用。(默认没有启用)
  • PodToleratesNodeTaints 检查pod上Tolerates的能否容忍污点(pod.spec.tolerations)
  • CheckNodeLabelPresence 检查节点上的标志是否存在 (默认没有启动)
  • CheckServiceAffinity 根据pod所属的service。将相同service上的pod尽量放到同一个节点(默认没有启动)
  • CheckVolumeBinding 检查是否可以绑定(默认没有启动)
  • NoVolumeZoneConflict 检查是否在一起区域(默认没有启动)
  • CheckNodeMemoryPressure 检查内存是否存在压力
  • CheckNodeDiskPressure 检查磁盘IO压力是否过大
  • CheckNodePIDPressure 检查pid资源是否过大

Priorities

  • least_requested 选择消耗最小的节点(根据空闲比率评估 cpu(总容量-sum(已使用)*10/总容量) )
  • balanced_resource_allocation 从节点列表中选出各项资源使用率最均衡的节点(CPU和内存)
  • node_prefer_avoid_pods 节点倾向
  • taint_toleration 将pod对象的spec.toleration与节点的taints列表项进行匹配度检查,匹配的条目越多,得分越低。
  • selector_spreading 与services上其他pod尽量不在同一个节点上,节点上通一个service的pod越少得分越高。
  • interpod_affinity 遍历node上的亲和性条目,匹配项越多的得分越高
  • most_requested 选择消耗最大的节点上(尽量将一个节点上的资源用完)
  • node_label 根据节点标签得分,存在标签既得分,没有标签没得分。标签越多 得分越高。
  • image_locality 节点上有所需要的镜像既得分,所需镜像越多得分越高。(根据已有镜像体积大小之和)

Scheduler

当我们想把调度到预期的节点,我们可以使用高级调度分为:

  • 节点选择器: nodeSelector、nodeName
  • 节点亲和性调度: nodeAffinity
  • Pod亲和性调度:PodAffinity
  • Pod反亲和性调度:PodAntiAffinity

NodeSelector

我们定义一个pod,让其选择带有node=ssd这个标签的节点

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vim test.yaml apiVersion: v1 kind: Pod metadata: name: pod-1 labels: name: myapp spec: containers: - name: myapp image: ikubernetes/myapp:v1 nodeSelector: node: ssd

查看信息

复制代码
1
2
kubectl apply -f test.yaml
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#get一下pod 一直处于Pending状态 $ kubectl get pod NAME READY STATUS RESTARTS AGE pod-1 0/1 Pending 0 7s #查看详细信息,是没有可用的selector $ kubectl describe pod pod-1 ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 9s (x14 over 36s) default-scheduler 0/4 nodes are available: 4 node(s) didn't match node selector. #我们给node2打上这个标签 $ kubectl label node k8s-node02 node=ssd node/k8s-node02 labeled #Pod正常启动 $ kubectl describe pod pod-1 .... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 2m (x122 over 8m) default-scheduler 0/4 nodes are available: 4 node(s) didn't match node selector. Normal Pulled 7s kubelet, k8s-node02 Container image "ikubernetes/myapp:v1" already present on machine Normal Created 7s kubelet, k8s-node02 Created container Normal Started 7s kubelet, k8s-node02 Started container

nodeAffinity

kubectl explain pod.spec.affinity.nodeAffinity

  • requiredDuringSchedulingIgnoredDuringExecution 硬亲和性 必须满足亲和性。

    • matchExpressions 匹配表达式,这个标签可以指定一段,例如pod中定义的key为zone,operator为In(包含那些),values为 foo和bar。就是在node节点中包含foo和bar的标签中调度
    • matchFields 匹配字段 和上面的意思 不过他可以不定义标签值,可以定义
  • preferredDuringSchedulingIgnoredDuringExecution 软亲和性 能满足最好,不满足也没关系。

    • preference 优先级
    • weight 权重1-100范围内,对于满足所有调度要求的每个节点,调度程序将通过迭代此字段的元素计算总和,并在节点与对应的节点匹配时将“权重”添加到总和。

运算符包含:InNotInExistsDoesNotExistGtLt。可以使用NotInDoesNotExist实现节点反关联行为。

硬亲和性:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
vim pod-affinity-demo.yaml apiVersion: v1 kind: Pod metadata: name: node-affinity-pod labels: name: myapp spec: containers: - name: myapp image: ikubernetes/myapp:v1 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: zone operator: In values: - foo - bar $ kubectl apply -f pod-affinity-demo.yaml $ kubectl describe pod node-affinity-pod ..... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 33s (x25 over 1m) default-scheduler 0/4 nodes are available: 4 node(s) didn't match node selector. # 给其中一个node打上foo的标签 $ kubectl label node k8s-node03 zone=foo $ kubectl get pods NAME READY STATUS RESTARTS AGE node-affinity-pod 1/1 Running 0 8m

软亲和性:

与requiredDuringSchedulingIgnoredDuringExecution比较,这里需要注意的是preferredDuringSchedulingIgnoredDuringExecution是个列表项,而preference不是一个列表项了。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: v1 kind: Pod metadata: name: node-affinity-pod-2 labels: name: myapp spec: containers: - name: myapp image: ikubernetes/myapp:v1 affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 50 preference: matchExpressions: - key: zone operator: In values: - foo - bar $ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE node-affinity-pod 1/1 Running 0 3h 10.244.3.2 k8s-node03 node-affinity-pod-2 1/1 Running 0 1m 10.244.3.3 k8s-node03

podAffinity

Pod亲和性场景,我们的k8s集群的节点分布在不同的区域或者不同的机房,当服务A和服务B要求部署在同一个区域或者同一机房的时候,我们就需要亲和性调度了。

kubectl explain pod.spec.affinity.podAffinity 和NodeAffinity是一样的,都是有硬亲和性和软亲和性

硬亲和性:

  • labelSelector 选择跟那组Pod亲和
  • namespaces 选择哪个命名空间
  • topologyKey 指定节点上的哪个键

样例

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: v1 kind: Pod metadata: name: node-affinity-pod1 labels: name: podaffinity-myapp tier: service spec: containers: - name: myapp image: ikubernetes/myapp:v1 --- apiVersion: v1 kind: Pod metadata: name: node-affinity-pod2 labels: name: podaffinity-myapp tier: front spec: containers: - name: myapp image: ikubernetes/myapp:v1 affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: name operator: In values: - podaffinity-myapp topologyKey: kubernetes.io/hostname

查看

复制代码
1
2
3
4
5
kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE node-affinity-pod1 1/1 Running 0 12s 10.244.2.6 k8s-node02 node-affinity-pod2 1/1 Running 0 12s 10.244.2.5 k8s-node02

podAntiAffinity

Pod反亲和性场景,当应用服务A和数据库服务B要求尽量不要在同一台节点上的时候。

kubectl explain pod.spec.affinity.podAntiAffinity 也分为硬反亲和性和软反亲和性调度(和podAffinity一样的配置)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#首先把两个node打上同一个标签。 kubectl label node k8s-node02 zone=foo kubectl label node k8s-node03 zone=foo #反硬亲和调度 apiVersion: v1 kind: Pod metadata: name: node-affinity-pod1 labels: name: podaffinity-myapp tier: service spec: containers: - name: myapp image: ikubernetes/myapp:v1 --- apiVersion: v1 kind: Pod metadata: name: node-affinity-pod2 labels: name: podaffinity-myapp tier: front spec: containers: - name: myapp image: ikubernetes/myapp:v1 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: name operator: In values: - podaffinity-myapp topologyKey: zone

查看一下(因为zone这个key在每个node都有会,所以第二个Pod没有办法调度,所以一直Pending状态)

复制代码
1
2
3
4
5
$ kubectl get pod NAME READY STATUS RESTARTS AGE node-affinity-pod1 1/1 Running 0 11s node-affinity-pod2 0/1 Pending 0 11s

Taint And Toleration

前两种方式都是pod选择那个pod,而污点调度是node选择的pod,污点就是定义在节点上的键值属性数据。举要作用是让节点拒绝pod,拒绝不合法node规则的pod。Taint(污点)和 Toleration(容忍)是相互配合的,可以用来避免 pod 被分配到不合适的节点上,每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。

Taint

Taint是节点上属性,我们看一下Taints如何定义

kubectl explain node.spec.taints(对象列表)

  • key 定义一个key
  • value 定义一个值
  • effect pod不能容忍这个污点时,他的行为是什么,行为分为三种:NoSchedule 仅影响调度过程,对现存的pod不影响。PreferNoSchedule 系统将尽量避免放置不容忍节点上污点的pod,但这不是必需的。就是软版的NoSchedule NoExecute 既影响调度过程,也影响现存的pod,不满足的pod将被驱逐。
复制代码
1
2
3
4
5
6
kubectl taint NODE NAME KEY_1=VAL_1:TAINT_EFFECT_1 ... KEY_N=VAL_N:TAINT_EFFECT_N [options] 增加taint kubectl taint node k8s-node02 node-type=prod:NoSchedule 删除taint kubectl taint node k8s-node02 node-type:NoSchedule-

tolerations

  • key 被容忍的key
  • tolerationSeconds 被驱逐的宽限时间,默认是0 就是立即被驱逐
  • value 被容忍key的值
  • operator Exists只要key在就可以调度,Equal(等值比较)必须是值要相同
  • effect 节点调度后的操作

创建一个容忍

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deploy namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: dev template: metadata: labels: app: myapp release: dev spec: containers: - name: myapp-containers image: ikubernetes/myapp:v2 ports: - name: http containerPort: 80 tolerations: - key: "node-type" operator: "Equal" value: "prod" effect: "NoSchedule"

最后

以上就是轻松秋天最近收集整理的关于一起来学k8s 20.k8s 调度k8s 调度的全部内容,更多相关一起来学k8s内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部