ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

k8s 调度器

2021-09-05 22:06:36  阅读:253  来源: 互联网

标签:master1 node 调度 affinity pod k8s root 节点


目录

一 、调度说明

简介

调度过程

自定义调度器

二、调度亲和性

pod跟node节点亲和性

pod 跟pod亲和性

三、污点和容忍

Taint 和 Toleration

污点(Taint)

Ⅰ、 污点 ( Taint ) 的组成

Ⅱ、污点的设置、查看和去除

容忍(Tolerations)

四、固定节点


一 、调度说明

简介

Scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分配到集群的节点上。听起来非常简单,但有很多要考虑的问题:

公平:如何保证每个节点都能被分配资源

资源高效利用:集群所有资源最大化被使用

效率:调度的性能要好,能够尽快地对大批量的 pod 完成调度工作

灵活:允许用户根据自己的需求控制调度的逻辑

我们的Scheduler就是根据上面的设计出来的

Sheduler 是作为单独的程序运行的,启动之后会一直监听API Server(这里的监听其实就是持续连接的状态),获取 PodSpec.NodeName 为空的 pod,也就是说这个字段里面有值的话,我们就不需要对Sheduler进行调度的,因为PodSpec.NodeName 其实就是指定我们的pod要去哪个地方运行,都指定了也就不需要进行调度了,对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上。。。

调度过程

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

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

PodFitsResources :节点上剩余的资源是否大于 pod 请求的资源

PodFitsHost :如果 pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配

PodFitsHostPorts :节点上已经使用的 port 是否和 pod 申请的 port 冲突

PodSelectorMatches :过滤掉和 pod 指定的 label 不匹配的节点

NoDiskConflict :已经 mount 的 volume 和 pod 指定的 volume 不冲突,除非它们都是只读

如果在 predicate 过程中没有合适的节点,pod 会一直在  pending  状态,不断重试调度,直到有节点满足条件。经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程: 按照优先级大小对节点排序。

优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重(该项的重要性)。这些优先级选项包括:

1. LeastRequestedPriority :通过计算 CPU 和 Memory 的使用率来决定权重,使用率越低权重越高。换句话说,这个优先级指标倾向于资源使用比例更低的节点

2. BalancedResourceAllocation :节点上 CPU 和 Memory 使用率越接近,权重越高。这个应该和上面的一起使用,不应该单独使用

3. 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

二、调度亲和性

什么是调度亲和性?

生活中的示例,张三一定要去3班和张三想去3班,前者是必须去,后者是可去可不去,前者是硬的,后者是软的。

pod跟node节点亲和性

在我们k8s中,我们的节点亲和是通过pod下面的spec下面的nodeAffinity去实现的。

pod.spec.nodeAffinity(下面的是两种类型)

1. preferredDuringSchedulingIgnoredDuringExecution:软策略

2. requiredDuringSchedulingIgnoredDuringExecution:硬策略

下面通过实验测试一下

首先是requiredDuringSchedulingIgnoredDuringExecution(硬策略)

apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
   image: busybox:alpine
  affinity:                        #亲和性
   nodeAffinity:                    #node的亲和性
     requiredDuringSchedulingIgnoredDuringExecution:    #硬亲和性
       nodeSelectorTerms:
       - matchExpressions:
         - key: kubernetes.io/hostname
           operator: NotIn
           values:
           - master2

分析:上面的简单分析一下,我们的NotIn的含义是,只要我们的hostname不等于master2即可,也就是说我们的pod不会运行在master2这个节点中,而运行在其他节点中,我们通过下面的查看labels的命令可以看到kubernetes.io/hostname等于哪个节点名字。

上面的案例中key其实就是我们node节点的标签,如下我们可以看到每个node的标签:

preferredDuringSchedulingIgnoredDuringExecution 软策略

 软亲和性性需要加上权重这个参数,权重越大越亲和,即越可能被调度

apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
   image: hub.atguigu.com/library/myapp:v1
 affinity:
   nodeAffinity:
     preferredDuringSchedulingIgnoredDuringExecution:
     - weight: 1               #权重为1,权重越大越亲和
       preference:
         matchExpressions:
         - key: kubernetes.io/hostname
           operator: In
           values:
           - master3

分析:上面的的话就是期望运行在我们的master3,有的话最好,没有的话就去其他的node。

软策略和硬策略合并

[root@master1 affinity]# cat pod5.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: busybox:apline
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - master1
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: source
            operator: In
            values:
            - test

[root@master1 affinity]# 
[root@master1 affinity]# kubectl get pod  -o wide
NAME       READY   STATUS         RESTARTS   AGE   IP           NODE      NOMINATED NODE   READINESS GATES
affinity   0/1     ErrImagePull   0          49s   10.244.1.3   master2   <none>           <none>
[root@master1 affinity]# 

必须先满足我们的硬策略,才能去执行我们的软策略。分析一下上面的yaml文件,我们的运算关系是NotIn,所以我们的运行的节点可能是node-01,node-03......,然后在这些节点中如果再满足source等于test的节点,则优先调度。

键值运算关系

In:label 的值在某个列表中

NotIn:label 的值不在某个列表中

Gt:label 的值大于某个值

Lt:label 的值小于某个值

Exists:某个 label 存在

DoesNotExist:某个 label 不存在

注意:如果nodeSelectorTerms下面有多个选项的话,满足任何一个条件即可;如果matchExpressions有多个选项的话,则必须同时满足这些条件才能正常调度pod。

Pod 跟pod亲和性

pod.spec.affinity.podAffinity/podAntiAffinity(在这个下面声明)

preferredDuringSchedulingIgnoredDuringExecution:软策略

requiredDuringSchedulingIgnoredDuringExecution:硬策略

我们先创建一个pod

[root@master1 affinity]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: master1
  labels:
    app: master1
spec:
  containers:
  - name: with-node-affinity
    image: nginx:alpine
[root@master1 affinity]# kubectl apply -f pod.yaml 
pod/master1 created
[root@master1 affinity]# 
[root@master1 affinity]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP             NODE      NOMINATED NODE   READINESS GATES
master1   1/1     Running   0          7s    10.244.0.186   master1   <none>           <none>
[root@master1 affinity]# 

然后先创建我们的硬策略pod

[root@master1 affinity]# cat  pod2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-3
  labels:
    app: pod-3
spec:
  containers:
  - name: pod-3
    image: nginx:alpine
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - master1
        topologyKey: kubernetes.io/hostname
[root@master1 affinity]# 
[root@master1 affinity]# 
[root@master1 affinity]# kubectl apply -f   pod2.yaml 
pod/pod-3 created
[root@master1 affinity]# 
[root@master1 affinity]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE     IP             NODE      NOMINATED NODE   READINESS GATES
master1   1/1     Running   0          3m30s   10.244.0.186   master1   <none>           <none>
pod-3     1/1     Running   0          7s      10.244.0.187   master1   <none>           <none>

分析:当我们的集群中的某个pod有app=master1这个标签的时候,我们 -o wide得到该pod所处的node节点,由于这里是硬策略,所以我们上面创建出来的pod-3就会运行在这个node节点上的,判断是否在同一个node的标准就是topologyKey字段了,即kubernetes.io/hostname要是一样的。

即如果想要pod运行在同一个node上,就用podAffinity;

如果不想在同一节点的话,就用podAntiAffinity。案例如下:

我们先删除之前创建的pod

[root@master1 affinity]# kubectl delete -f pod2.yaml 
pod "pod-3" deleted
[root@master1 affinity]#

增加yaml文件podAntiAffinity字段

[root@master1 affinity]# cat  pod2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-3
  labels:
    app: pod-3
spec:
  containers:
  - name: pod-3
    image: nginx:alpine
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - master1
        topologyKey: kubernetes.io/hostname
[root@master1 affinity]# kubectl apply -f  pod2.yaml 
pod/pod-3 created
[root@master1 affinity]# kubectl get pod 
NAME      READY   STATUS              RESTARTS   AGE
master1   1/1     Running             0          8m27s
pod-3     0/1     ContainerCreating   0          2s
[root@master1 affinity]# kubectl get pod  -o wide
NAME      READY   STATUS              RESTARTS   AGE     IP             NODE      NOMINATED NODE   READINESS GATES
master1   1/1     Running             0          8m36s   10.244.0.191   master1   <none>           <none>
pod-3     0/1     ContainerCreating   0          11s     <none>         master2   <none>           <none>
[root@master1 affinity]# 

上面的 “同一个node” 其实不规范,应该是同一个拓扑域,即根据我们的topologyKey来决定的,例如上面的yaml中kubernetes.io/hostname,这个是具有唯一性,所以同一个拓扑域就是同一个节点了。

关于同一个拓扑域的解释说明如下:‘

例如我们有以下三个node,其中两个node的标签一样,都有disk=1,当我们把topologyKey改成disk的时候,此时我们的pod放在node01和node02都可以,这个就叫做同一拓扑域

亲和性/反亲和性调度策略比较如下:

官方解释:

如果该X已经在运行一个或多个满足规则Y的Pod,则该Pod应该(或者在非亲和性的情况下不应该)在X中运行

Y表示为LabelSelector规则

X是一个拓扑域,例如节点,机架,云提供者区域,云提供者区域等。您可以使用topologyKey这是系统用来表示这种拓扑域的节点标签的密钥。

关于topologyKey字段可参考https://www.jianshu.com/p/d906e819245c

这里补充一个有意思的玩法:k8s每节点相同服务只部署一个进程

三、污点和容忍

Taint 和 Toleration

节点亲和性,是 pod 的一种属性(偏好或硬性要求),它使 pod 被吸引到一类特定的节点。Taint 则相反,它使节点 能够 排斥 一类特定的 pod。

Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod上,则表示这些 pod 可以(但不要求)被调度到具有匹配 taint 的节点上。

举例来说,我们去相亲的话,女方的要求是,不能容忍是抽烟的,那么打上抽烟这一类标签的人就不可能成功;反过来说,女方可以接受抽烟的,那么天下那么多抽烟的,只能有一个。即,我们的污点和容忍的概念就是,如果能容忍这个污点,可能发生故事,但不一定会发生故事;如果不能容忍的话,那么只要那个node有一个污点的话,就不会被调度到这个node上去。

污点(Taint)

Ⅰ、 污点 ( Taint ) 的组成

使用 kubectl taint 命令可以给某个 Node 节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去。

每个污点的组成如下:

key=value:effect

每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。当前 taint effect 支持如下三个选项:

NoSchedule :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上

PreferNoSchedule :表示 k8s 将尽量避免将 Pod 调度到具有该污点的 Node 上

NoExecute :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去。。即把该Node上的Pod全部排出出去,如果是静态pod的话,驱逐就不会被创建了,相当于delete命令,如果是控制器控制的pod,则会进入到其他的Node上去,因为要维持副本的数目。

Ⅱ、污点的设置、查看和去除

# 设置污点
kubectl taint nodes node1 key1=value1:NoSchedule
# 节点说明中,查找 Taints 字段
kubectl describe pod pod-name
# 去除污点
kubectl taint nodes node1 key1:NoSchedule-

举例:下面的是我们的一个master节点的信息(kubectl describe node k8s-master)

这个的意思是,k8s不会将Pod调度到该节点上,也就是为什么我们的pod永远不会在master节点上。(这里省略了value)

容忍(Tolerations)

设置了污点的 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"

如果我们设置tolerationSeconds的时候,必须effect为NoExecute,如下图

其中 key, value, effect 要与 Node 上设置的 taint 保持一致,operator 的值为 Exists 将会忽略 value 值

tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Pod 上继续保留运行的时间,我们之前说过,有个NoExecute 的驱逐机制,如果我们设置了这里的时间的话,虽然pod会被驱逐,但是在设置的时间之后才会被驱逐,例如上面的3600s之后被驱逐。

注意以下几个点

Ⅰ、当不指定 key 值时,表示容忍所有的污点 key:

tolerations:
- operator: "Exists"

Ⅱ、当不指定 effect 值时,表示容忍所有的污点作用

tolerations:
- key: "key"
  operator: "Exists"

Ⅲ、有多个 Master 存在时,防止资源浪费,可以如下设置

kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoSchedule

分析:PreferNoSchedule,这个的含义是“尽可能不在这个node上运行”,当我们后边所有的pod出现资源不够用的情况,这样的话,就可以在我们的master节点上运行对应的pod了。

总结:上面就有个运维的关系,就是假如有一天,我们的某个node需要维护或者是更新的话,但是该node上去已经运行了很多的pod,如果我们直接把node关闭的话,就会造成我们的网路灯访问的影响,这个时候我们可以对该node打上一个污点,就用NoExecute,让所有的pod被驱逐出去,去别的node上面去运行,这样就可以更新该node了。

四、固定节点

即调度到指定的节点中上

Ⅰ、Pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配。

[root@master1 affinity]# cat pod4.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myweb
spec:
  replicas: 7
  template:
    metadata:
      labels:
        app: myweb
    spec:
      nodeName: master1
      containers:
      - name: myweb
        image: nginx:alpine
        ports:
        - containerPort: 80
[root@master1 affinity]# 
[root@master1 affinity]# kubectl apply -f  pod4.yaml
deployment.extensions/myweb created
[root@master1 affinity]# 

分析:上面的七个pod全部运行在我们的master2上 

Ⅱ、Pod.spec.nodeSelector:通过 kubernetes 的 label-selector 机制选择节点,由调度器调度策略匹配 label,而后调度 Pod 到目标节点,该匹配规则属于强制约束。

[root@master1 affinity]# cat pod4.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myweb
spec:
  replicas: 7
  template:
    metadata:
      labels:
        app: myweb
    spec:
      nodeSelector: 
        disk: ssd
      containers:
      - name: myweb
        image: nginx:alpine
        ports:
        - containerPort: 80
[root@master1 affinity]# 
[root@master1 affinity]# kubectl apply -f  pod4.yaml 
deployment.extensions/myweb created
[root@master1 affinity]# 
[root@master1 affinity]# kubectl get pod 
NAME                     READY   STATUS    RESTARTS   AGE
myweb-74b45c5575-4h9hm   0/1     Pending   0          4s
myweb-74b45c5575-5mjjk   0/1     Pending   0          4s
myweb-74b45c5575-hsvlf   0/1     Pending   0          4s
myweb-74b45c5575-l59fr   0/1     Pending   0          4s
myweb-74b45c5575-mcf8c   0/1     Pending   0          4s
myweb-74b45c5575-v6kzb   0/1     Pending   0          4s
myweb-74b45c5575-w58lk   0/1     Pending   0          4s
[root@master1 affinity]# 

开始我们node的标签不是disk=ssd,所有一直处于Pending状态,后来打上了标签就好了

[root@master1 affinity]# kubectl label node master1 disk=ssd
node/master1 labeled
[root@master1 affinity]#
[root@master1 affinity]# kubectl get pod  -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP             NODE      NOMINATED NODE   READINESS GATES
myweb-74b45c5575-4h9hm   1/1     Running   0          54s   10.244.0.203   master1   <none>           <none>
myweb-74b45c5575-5mjjk   1/1     Running   0          54s   10.244.0.200   master1   <none>           <none>
myweb-74b45c5575-hsvlf   1/1     Running   0          54s   10.244.0.199   master1   <none>           <none>
myweb-74b45c5575-l59fr   1/1     Running   0          54s   10.244.0.205   master1   <none>           <none>
myweb-74b45c5575-mcf8c   1/1     Running   0          54s   10.244.0.201   master1   <none>           <none>
myweb-74b45c5575-v6kzb   1/1     Running   0          54s   10.244.0.202   master1   <none>           <none>
myweb-74b45c5575-w58lk   1/1     Running   0          54s   10.244.0.204   master1   <none>           <none>
[root@master1 affinity]# 

标签:master1,node,调度,affinity,pod,k8s,root,节点
来源: https://blog.csdn.net/m0_49023005/article/details/120121741

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有