k8s调度器Scheduler

k8s调度器Scheduler

Scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分配到集群的节点上。

Scheduler:

  • 通过调度算法为待调度Pod列表的每个Pod从Node列表中选择一个最适合的Node,并将信息写入etcd中
  • kubelet通过API Server监听到kubernetes Scheduler产生的Pod绑定信息,然后获取对应的Pod清单,下载Image,并启动容器。
Sheduler 是作为单独的程序运行的,启动之后会一直监听(持续连接) API Server,获取 PodSpec.NodeName 为空的 pod,
对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上

调度流程

  • 预选调度过程,即遍历所有目标Node,筛选出符合要求的候选节点,kubernetes内置了多种预选策略(xxx Predicates)供用户选择
  • 确定最优节点,在第一步的基础上采用优选策略(xxx Priority)计算出每个候选节点的积分,取最高积分。调度流程通过插件式加载的“调度算法提供者”(AlgorithmProvider)具体实现,一个调度算法提供者就是包括一组预选策略与一组优选策略的结构体。

预选策略

说明:返回true表示该节点满足该Pod的调度条件;返回false表示该节点不满足该Pod的调度条件。

Predicate 有一系列的算法可以使用:

  • PodFitsResources :节点上剩余的资源是否大于 pod 请求的资源
  • PodFitsHost :如果 pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配
  • PodFitsHostPorts :节点上已经使用的 port 是否和 pod 申请的 port 冲突
  • PodSelectorMatches :过滤掉和 pod 指定的 label 不匹配的节点
  • NoDiskConflict :已经 mount 的 volume 和 pod 指定的 volume 不冲突,除非它们都是只读
如果在 predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有节点满足条件。
经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程: 按照优先级大小对节点排序
优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重(该项的重要性)。这些优先级选项包括:
LeastRequestedPriority :通过计算 CPU 和 Memory 的使用率来决定权重,使用率越低权重越高。换句话
说,这个优先级指标倾向于资源使用比例更低的节点
BalancedResourceAllocation :节点上 CPU 和 Memory 使用率越接近,权重越高。这个应该和上面的一起
使用,不应该单独使用
ImageLocalityPriority :倾向于已经有要使用镜像的节点,镜像总大小值越大,权重越高
通过算法对所有的优先级项目和权重进行计算,得出最终的结果

自定义调度器

除了 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

2.调度亲和性

亲和性分为

  • 节点亲和性
  • pod亲和性

节点亲和性

例:比如举个例子,今天我们要分班了,那么我更倾向于去张三老师的班级。如果我是个pod,张三老师带的班级是个node,这就是一个节点亲和性

pod亲和性

例:我的原来同桌叫李四,我们关系很好,我能不能和他去同一个班级。这就是一个典型的pod亲和。

1.节点亲和性

pod.spec.nodeAffinity

  • preferredDuringSchedulingIgnoredDuringExecution:软策略
  • requiredDuringSchedulingIgnoredDuringExecution:硬策略

requiredDuringSchedulingIgnoredDuringExecution 硬策略:(如果有我就去,如果没有我就不运行了,保持pending状态)

apiVersion: v1
kind: Pod
metadata:
  name: affinity      #pod名称
  labels:
    app: node-affinity-pod   #标签
spec:
  containers:   #容器
  - name: with-node-affinity     #容器名称
    image: hub.atshooter.com/k8s/nginx:v1.0   #镜像
  affinity:   #亲和性
    nodeAffinity:   #node(节点)的亲和性
      requiredDuringSchedulingIgnoredDuringExecution:   #硬亲和性
        nodeSelectorTerms:   #亲和方案 
        - matchExpressions:
          - key: kubernetes.io/hostname     #键名 这里的key是node节点的标签,可以通过 kubectl get node --show-labels 查看到
            operator: NotIn     #不在
            values:
            - k8s-node2

img(域)键:值

上面案例含义:只要键不是kubernetes.io/hostname键名,并且他的键值不等于k8s-node2即可

img

他去了node1

如果把operator的值改为 In 那么他无论怎样都会去node2

preferredDuringSchedulingIgnoredDuringExecution 软策略:(如果有我就去,没有就算了)

apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: hub.atshooter.com/k8s/nginx:v1.0
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - k8s-node3

上面的是软策略案例,含义是,如果有k8s-node3节点就去node3 ,没有的话就算了。

img

因为没有node3所以他随机去了node2

如果上面的values 值是 k8s-node02 那么一定就回去k8s-node2

软硬合体:(需要先满足硬策略以后,才能去满足软策略)

apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: hub.atshooter.com/k8s/nginx:v1.0
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - k8s-node2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - k8s-node1

上面这个软硬合体策略是说,硬[如果不在k8s-node2节点],软[则就去k8s-node1,如果k8s-node1没有,就去其他节点]

Pod 亲和性(pod与pod的亲和性)

pod.spec.affinity.podAffinity/podAntiAffinity

  • preferredDuringSchedulingIgnoredDuringExecution:软策略
  • requiredDuringSchedulingIgnoredDuringExecution:硬策略

pod亲和硬策略:

apiVersion: v1
kind: Pod
metadata:
  name: pod-3
  labels:
    app: pod-3
spec:
  containers:
  - name: pod-3
    image: hub.atshooter.com/k8s/nginx:v1.0
  affinity:
    podAffinity:    #想要pod与指定pod运行在同一node上,官方说同一拓扑域
      requiredDuringSchedulingIgnoredDuringExecution:   #硬策略
      - labelSelector:
          matchExpressions:
          - key: app      #如果有app=node1  那么就在这个节点上创建pod-3
            operator: In
            values:
            - node1       #如果有app=node1  那么就在这个节点上创建pod-3
        topologyKey: kubernetes.io/hostname

img

上面这个案例的意思是,如果在某个节点上发现有app=node1标签,那么就在这个节点上创建pod-3,否则就停止,pending状态 (因为是硬策略)

下面看个pod亲和软策略:

apiVersion: v1
kind: Pod
metadata:
  name: pod-3
  labels:
    app: pod-3
spec:
  containers:
  - name: pod-3
    image: hub.atshooter.com/k8s/nginx:v1.0		
  affinity:
    podAntiAffinity:    #不想POD与指定POD运行在同一node上,官方说同一拓扑域
      preferredDuringSchedulingIgnoredDuringExecution:  #软策略
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app   #如果有app=node1  那么就不在这个节点上创建pod-3
              operator: In
              values:
              - node1    #如果有app=node1  那么就不在这个节点上创建pod-3
          topologyKey: kubernetes.io/hostname

上面这个案例的意思是,如果在某个节点上发现有app=node1标签,那么就不在这个节点上创建pod-3

img

这位大佬写的也不错,值得借鉴
https://blog.csdn.net/qq_34246164/article/details/103837001