kubernetes13(kubernetes的调度器)

kubernetes13(kubernetes的调度器)

一.引子

在master节点上,有一个非常重要的组件,资源调度器(schedule)。负责资源的调度,按照预定的调度策略将新建立的 Pod 进行节点 (node) 选择(即分配机器)。就像把糖果奖励给幼儿园小朋友一样,按照一定的策略进行分配糖果,然而pod就是我们要分配出去的糖果。

二.kubernetes的调度器

(一).调度器的基本概念

当Scheduler通过API server 的watch接口监听到新建Pod副本的信息后,它会检查所有符合该Pod要求的Node列表,开始执行Pod调度逻辑。调度成功后将Pod绑定到目标节点上。Scheduler在整个系统中承担了承上启下的作用,承上是负责接收创建的新Pod,为安排一个落脚的地(Node),启下是安置工作完成后,目标Node上的kubelet服务进程接管后继工作,负责Pod生命周期的后半生。具体来说,Scheduler的作用是将待调度的Pod安装特定的调度算法和调度策略绑定到集群中的某个合适的Node上,并将绑定信息传给API server 写入etcd中。整个调度过程中涉及三个对象,分别是:待调度的Pod列表,可以的Node列表,以及调度算法和策略。
当然调度过程中仍有很多要考虑的问题:

  • 公平:如何保证每个节点都能被分配资源
  • 资源高效利用:集群所有资源最大化被使用
  • 效率:调度的性能要好,能够尽快地对大批量的 pod 完成调度工作
  • 灵活:允许用户根据自己的需求控制调度的逻辑
    在这里插入图片描述

(二).调度器的调度策略及调度过程

调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为 predicate;然后对通过的节点按照优先级排序,这个是 priority;最后从中选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误

Kubernetes Scheduler 提供的调度流程分三步:

  • 预选策略(predicate) 遍历nodelist,选择出符合要求的候选节点,Kubernetes内置了多种预选规则供用户选择。如果在 predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有节点满足条件。经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程: 按照优先级大小对节点排序。
  • 优选策略(priority) 在选择出符合要求的候选节点中,采用优选规则计算出每个节点的积分,最后选择得分最高的。
  • 选定(select) 如果最高得分有好几个节点,select就会从中随机选择一个节点。
    在这里插入图片描述
预选策略
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资源是否过大
预选节点的源码

自定义调度器:

优选策略
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 节点上有所需要的镜像既得分,所需镜像越多得分越高。(根据已有镜像体积大小之和)
优选节点源码
https://github.com/kubernetes/kubernetes/blob/v1.17.0/pkg/scheduler/algorithm/priorities/优选节点源码地址

除了 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: pod-with-second-annotation-container
    image: gcr.io/google_containers/pause:2.0
[root@k8s-master01 yml]# vim sche.yaml
[root@k8s-master01 yml]# kubectl apply -f sche.yaml --validate=false
pod/annotation-second-scheduler created

(三).调度器的高级调度方式

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

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

1.NodeSelector:节点选择器
我们定义一个pod,让其选择带有node=hlqlinux这个标签的节点

apiVersion: v1
kind: Pod
metadata:
  name: pod-1
  labels:
    name: myapp
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
  nodeSelector:
    node: hlqlinux

2.nodeAffinity:node节点亲和性调度
kubectl explain pod.spec.affinity.nodeAffinity

(1).requiredDuringSchedulingIgnoredDuringExecution 硬亲和性 必须满足亲和性。

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

(2).preferredDuringSchedulingIgnoredDuringExecution 软亲和性 能满足最好,不满足也没关系。

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

运算符包含:In,NotIn,Exists,DoesNotExist,Gt,Lt。可以使用NotIn和DoesNotExist实现节点反关联行为。

硬亲和

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.

软亲和

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

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
# 给其中一个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

3.PodAffinity Pod:Pod亲和性调度
Pod亲和性场景,我们的k8s集群的节点分布在不同的区域或者不同的机房,当服务A和服务B要求部署在同一个区域或者同一机房的时候,我们就需要亲和性调度了。
kubectl explain pod.spec.affinity.podAffinity 和NodeAffinity是一样的,都是有硬亲和性和软亲和性

硬亲和性:

  • labelSelector 选择跟那组Pod亲和
  • namespaces 选择哪个命名空间
  • topologyKey 指定节点上的哪个键
apiVersion: v1
kind: Pod
metadata:
  name: pod-3
  labels:
    app: pod-3
spec:
  containers:
  - name: pod-3
    image: wangyanglinux/myapp:v1
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - pod-1
        topologyKey: kubernetes.io/hostname
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - pod-2
          topologyKey: kubernetes.io/hostname

4.podAntiAffinity:反亲和性调度
Pod反亲和性场景,当应用服务A和数据库服务B要求尽量不要在同一台节点上的时候。
kubectl explain pod.spec.affinity.podAntiAffinity 也分为硬反亲和性和软反亲和性调度(和podAffinity一样的配置)

 #首先把两个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状态)

$ 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和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将被驱逐。
node 打 taint

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 节点调度后的操作
创建一个容忍

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”

以上就是关于kuubernetes的调度器及调度策略的介绍和分析。感谢大家的浏览。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值