K8S 调度机制

30. 调度机制

30.1 Pod调度流程

1.通过命令kubectl发送命令创建pod发送给api-server
2.api-server把信息写入到etcd
3.kube-Scheduler会从etcd中获取事件就是创建信息,找到之后在返回给api-server,kube-Scheduler会选择一个node把调度结果返回给api-server,这个过程称之为绑定事件,在把这个事件写入到etcd,kube-Scheduler只负责调度,不负责创建容器
4.kubelet获取绑定的事件kubelet通过一个本地的socker来调用运行时docker,kubelet
5.然后再创建容器

30.2 nodeSelector

nodeSelector基于node标签选择器,将Pod调度的指定的目的节点上
可用于基于服务类型干预Pod调度结果,如对磁盘I/O要求高的Pod调度到SSD节点,对内存要求比较高的Pod调度的内存较高的节点,也可以用于区分不同项目的Pod,如将node添加不同项目的标签,然后区分调度
  • 给节点打标签
#将Pod调度到目的node,yaml文件中指定的key与value必须精确匹配
kubectl label node 10.0.0.101 project=demo
#删除label标签,只需要在命令行最后指定label的key名,并加一个减号就可以了
kubectl label node k8s-node1 project-
#显示标签
kubectl get node --show-labels

30.3 nodeName

精确调度到主机
使用场景:例如数据库把这个pod精确调度到某个主机上

30.4 node affinity节点亲和性

affinity是kubernetes 1.2版本后引入的新特性,类似于nodeSelector,允许使用者指定一些Pod在Node间调度的约束,目前支持两种形式:

requiredDuringSchedulinglgnoredDuringExecution #必须满足pod调度匹配条件,如果不满足则不进行调度
preferredDuringSchedulinglgnoredDuringExecution #倾向满足pod调度匹配条件,不满足的情况下会调度的不符合条件的Nodc上
lgnoreDuringExecution #表示如果在Pod运行期间Node的标签发生变化,导致亲和性策略不能满足,也会继续运行当前的Pod.
Affinity与anti-affinity的目的也是控制pod的调度结果,但是相对于nodeSelector,Affinity(亲和)与anti-affinityg(反亲和)的功能更加强大
  • affinity与nodeSelector对比
1.亲和与反亲和对目的标签的选择匹配不仅仅支持and还支持In、Notln、Exists、DoesNotExist、Gt、Lt。
In:标签的值存在匹配列表中(匹配成功就调度到目的node,实现node亲和)
Notln:标签的值不存在指定的匹配列表中(不会调度到目的node,实现反亲和)
Gt:标签的值大于某个值(字符串)
Lt:标签的值小于某个值(字符串)
Exists:指定的标签存在
2.可以设置软匹配和硬匹配,在软匹配下如果调度器无法匹配节点,仍然将pod调度到其它不符合条件的节点
3.还可以对pod定义亲和策略,比如允许那些pod可以或者不可以被调度至同一台node
  • 例:硬限制多个匹配条件
  • 多个matchExpressions匹配其中一个就可以
spec:
      containers:
      - name: tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        nodeAffinity:
#硬限制必须满足
          requiredDuringSchedulingIgnoredDuringExecution:
#节点筛选条件
            nodeSelectorTerms:
#匹配条件1,有一个key但是有多个values、则只要匹配成功一个value就可以调度 
            - matchExpressions: 
#标签的key
              - key: disktype
#操作符是IN还是NOTIN
                operator: In
                values:
#只有一个value是匹配成功也可以调度,满足一个条件即可
                - ssd 
                - xxx
#匹配条件1,有一个key但是有多个values、则只要匹配成功一个value就可以调度 
            - matchExpressions:
              - key: project
                operator: In
#即使这俩条件都匹配不上也可以调度,即多个matchExpressions只要有任意一个能匹配任何一个value就可以调用。
                values:
                - mmm  
                - nnn
  • 例:硬限制多个key值
spec:
      containers:
      - name: magedu-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions: #匹配条件1,同一个key的多个value只有有一个匹配成功就认为当前key匹配成功 
              - key: disktype
                operator: In
                values:
                - ssd
                - hddx
              - key: project #匹配条件2,当前key也要匹配成功一个value,即条件1和条件2必须同时每个key匹配成功一个value,否则不调度
                operator: In
                values:
                - demo
  • 例:软限制
spec:
      containers:
      - name: magedu-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80 #软亲和条件1,weight值越大优先级越高,越优先匹配调度 
            preference:
              matchExpressions:
              - key: project
                operator: In
                values:
                  - magedu
          - weight: 60 #软亲和条件2,在条件1不满足时匹配条件2
            preference:
              matchExpressions:
              - key: disktype
                operator: In
                values:
                  - ssd
  • 例:硬限制与软限制结合
  • 用硬限制排除一部分主机在用软限制进行匹配 这个NotIn就相当于反亲和了
spec:
      containers:
      - name: magedu-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution: #硬亲和
            nodeSelectorTerms:
            - matchExpressions: #硬匹配条件1
              - key: "kubernetes.io/role"
                operator: NotIn
                values:
                - "master" #硬性匹配key 的值kubernetes.io/role不包含master的节点,即绝对不会调度到master节点(node反亲和)
          preferredDuringSchedulingIgnoredDuringExecution: #软亲和
          - weight: 80
            preference:
              matchExpressions:
              - key: project
                operator: In
                values:
                  - magedu
          - weight: 60
            preference:
              matchExpressions:
              - key: disktype
                operator: In
                values:
                  - hdd
  • 反亲和
#硬亲和的反亲和 下面的values的值必须是反着写类似排除的方式
 spec:
      containers:
      - name: magedu-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions: #匹配条件1
              - key: disktype
                operator: NotIn #调度的目的节点没有key为disktype且值为hdd的标签
                values:
                - hdd 
#绝对不会调度到含有label的key为disktype且值为hdd的hdd的节点,即会调度到没有key为disktype且值为hdd的hdd的节点

30.5 pod Affinity亲和性

  • 概述 亲和就是pod都在一块 反亲和就都不在一个主机 分开
Pod亲和性与反亲和性可以基于已经在node节点上运行的pod的标签来约束新创建的pod可以调度到的目的节点,注意不是基于node上的标签而是使用的已经运行在node上的pod标签匹配

其规则的格式为如果node节点A已经运行了一个或多个满足调度新创建的pod B的规则,那么新的Pod B在亲和的条件下会调度到A节点之上,而在反亲和性的情况下则不会调度到A节点至上

其中规则表示一个具有可选的关联命名空间列表的LabelSelector,只所以Pod亲和与反亲和需可以通过LabelSelector选择namespace,是因为Pod是命名空间限定的而node不属于任何namespace所以node的亲和与反亲和不需要namespace,因此作用于pod标签的标签选择算符必须指定选择算符应用在那个命名空间

从概念上讲,node节点是一个拓扑域(具有拓扑结构的域),比如k8s集群中的单台node节点,一个机架、云供应商可用区,云供应商地理区域等,可以使用topologykey来定义亲和或者反亲和的颗粒度是node级别还是可用区级别,以便kubernetes调度系统用来识别并选择正确的目的拓扑域。
  • 软亲和 软亲和就算匹配失败他也会自行调度
spec:
      containers:
      - name: magedu-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        podAffinity:  #Pod亲和
          #requiredDuringSchedulingIgnoredDuringExecution: #硬亲和,必须匹配成功才调度,如果匹配失败则拒绝调度。
          preferredDuringSchedulingIgnoredDuringExecution: #软亲和,能匹配成功就调度到一个topology,匹配不成功会由kubernetes自行调度。
          - weight: 100
            podAffinityTerm:
              labelSelector: #标签选择
                matchExpressions: #正则匹配
                - key: project
                  operator: In
                  values:
                    - python
              topologyKey: kubernetes.io/hostname
              namespaces:
                - demo
  • 硬亲和 匹配成功之后才会被调度 匹配失败就显示为pending
spec:
      containers:
      - name: magedu-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution: #硬亲和
          - labelSelector:
              matchExpressions:
              - key: project
                operator: In
                values:
                  - python
            topologyKey: "kubernetes.io/hostname"
            namespaces:
              - demo
  • 硬反亲和
  • 个人理解:pod affinity的调度范围为topology
spec:
      containers:
      - name: magedu-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: project
                operator: In
                values:
                  - python
            topologyKey: "kubernetes.io/hostname"
            namespaces:
              - demo

30.6 维护节点三兄弟

  • 概述
在1.2之前,由于没有相应的命令支持,如果要维护一个节点,只能stop该节点上的kubelet将该节点退出集群,是集群不在将新的pod调度到该节点上。如果该节点上本身就没有pod在运行,则不会对业务有任何影响。如果该节点上有pod正在运行,kubelet停止后,master会发现该节点不可达,而将该节点标记为notReady状态,不会将新的节点调度到该节点上。同时,会在其他节点上创建新的pod替换该节点上的pod。

如此虽能够保证集群的健壮性,但可能还有点问题,如果业务只有一个副本,而且该副本正好运行在被维护节点上的话,可能仍然会造成业务的短暂中断。
  • 设置节点不可调度
kubectl cordon xxx-node-01
  • 驱逐节点上的pod,逐步进行
kubectl drain xxx-node-01 --force --ignore-daemonsets
  • 恢复节点
kubectl uncordon xxx-node-01

30.7 污点

  • 污点
污点(taints)用于node节点排斥pod调度,与亲和的作用是完全相反的,即taint的node和pod是排斥调度关系
  • 容忍
容忍:用于Pod容忍node节点的污点信息,即node有污点信息也会将新的pod调度到node
tolerations容忍:
	定义Pod的容忍度(可以接受node的那些污点)容忍后可以将Pod调度至含有该污点的node
基于operator的污点匹配:
	如果operator是Exists,则容忍度不需要value而是直接匹配污点类型
	如果operator是Equal,则需要指定value并且value的值需要等于tolerations的key
  • 污点类型
#硬限制
NoSchedule:表示k8s将不会将Pod调度到具有该污点的Node上
#软限制
PreferNoSchedule:表示k8s将尽量避免将pod调度到具有该污点的node上
NoExecute:表示k8s将不会将pod调度到具有该污点的node上,同时会将node上已经存在的pod强制驱逐出去
  • 污点命令
#设置污点
kubectl taint node 10.0.0.101 key1=value1:NoSchedule

#查看污点
kubectl describe node 10.0.0.101

#取消污点
kubectl taint node 10.0.0.101 key1:NoSchedule-
  • 例:污点容忍
#设置污点
kubectl taint node 10.0.0.101 key1=value1:NoSchedule

tolerations:
      - key: "key1"
        operator: "Equal"
        value: "value1"
        effect: "NoSchedule"

30.8 kubelet pod驱逐

  • 节点压力驱逐简介
#kubelet是基于node负责、资源利用率等进行pod驱逐
节点压力驱逐是由各kubelet进程主动终止Pod,以回收节点上的内存、磁盘空间等资源的过程,kubelet监控当前node节点CPU、内存、磁盘空间和文件系统的inode等资源,当这些资源中的一个或者多个达到特定的消耗水平,kubelet就会主动地将节点上一个或者多个Pod强制驱逐,以防止当前node节点资源无法正常分配而引发的OOM(OutOfMemory)
  • 配置
#宿主机内存
memory.available #node节点可用内存,默认<100Mi

#nodefs是节点的主要文件系统,用于保存本地磁盘卷,emptyDir、日志存储等数据,默认是/var/lib/kubelet/,或者是通过kubelet通过--root-dir所指定的磁盘挂载目录
nodefs.inodesFree	#nodefs的可用inode,默认<5%
nodefs.available	#nodefs的可用空间,默认<10%

#imagesfs是可选文件系统,用于给容器提供运行时存储容器镜像和容器可写层
imagefs.inodesFree	#imagefs的inode可用百分比
imagefs.available	#imagefs的磁盘空间可用百分比,默认<15%
pid.available		#可用pid百分比

#示例:
evictionHard:
	imagefs.inodesFree: 5%
	imagefs.available: 15%
	memory.available: 300Mi
	nodefs.available: 10%
	nodefs.indesFree: 5%
	pid.available: 5%
  • 宕机驱逐
kube-controller-manager实现 eviction
node宕机后的驱逐
  • 驱逐简介
节点驱逐,用于当node节点资源不足的时候自动将pod进行强制驱逐,以保证当前node节点的正常运行。Kubernetes基于是QoS(服务质量等级)驱逐Pod,Qos等级包括目前包括以下三个:

Guaranteed: #limits和request的值相等,等级最高、最后被驱逐
  resources:
    limits:
    cpu: 500m
    memory: 256Mirequests:
    cpu: 500m
    memory: 256Mi
Burstable: #limit和request不相等,等级折中、中间被驱逐
  resources:
    limits:
    cpu: 500m
    memory: 256Mirequests:
    cpu: 256m
    memory: 128Mi

BestEffort:		#没有限制,即resources为空,等级最低,最先被驱逐
  • 驱逐条件
eviction-signal: kubelet捕获node节点驱逐触发信号,进行判断是否驱逐,比如通过cgroupfs获取memory.available的值来进行下一步匹配

operator: 操作符,通过操作符对比条件是否匹配资源量是否触发驱逐

quantity:  使用量,即基于指定的资源使用值进行判断,如memory.available:300Mi、nodefs.available:10%等
比如:nodefs.available<10%
当node节点磁盘空间可用率低于10%就会触发驱逐信号
  • 软驱逐
软驱逐不会立即驱逐pod,可以自定义宽限期,在条件持续到宽限期还没有恢复,,kubelet再强制杀死pod并触发驱逐:
软驱逐条件:
	eviction-soft:软驱逐触发条件,比如memory.available < 1.5Gi,如果驱逐条件持续时长超过指定的宽限期,可
以触发Pod驱逐。
	eviction-soft-grace-period:软驱逐宽限期,如memory.available=1m30s,定义软驱逐条件在触发Pod驱逐之前
必须保持多长时间。
	eviction-max-pod-grace-period:终止pod的宽限期,即在满足软驱逐条件而终止Pod时使用的最大允许宽限期
(以秒为单位)。
  • 硬驱逐
硬驱逐条件没有宽限期,当达到硬驱逐条件时,kubelet会强制立即杀死pod并驱逐:
kubelet具有以下默认硬驱逐条件(可以自行调整):
memory.available<100Mi
nodefs.available<10%
imagefs.available<15%
nodefs.inodesFree<5%(Linux节点)
kubelet service文件:
	vim /etc/systemd/system/kubelet.service
kubelet配置文件
evictionHard:
  imagefs.available: 15%
  memory.available: 30OMi
  nodefs.available: 10%
  nodefs.inodesFree: 5%
posted @ 2023-01-02 11:43  YIDADA-SRE  阅读(123)  评论(0编辑  收藏  举报