• k8s之调度器、预选策略及优选函数


    1.调度器(scheduler)

      调度器的功能是调度Pod在哪个Node上运行,这些调度信息存储在master上的etcd里面,能够和etcd打交道的只有apiserver;

    kubelet运行在node节点上,监控着Node节点上的pod状态,并参与pod的创建等工作;

    kube-proxy也运行在node节点上,它监控着service资源的变动;

    kubelet和kube-proxy都要连接master上的apiserver去获取定义信息.

    预选步骤--default scheduler通过三个步骤实现调度

    a.预选策略(predicate):先排除那些完全不符合此pod运行法则的节点,有两个维度来排除,一个是最低资源需求,即节点必须满足此Pod的最低资源;第二个是资源限额,即当前节点最多能给pod提供的资源.

    b.优选(priority):在符合节点找到最佳匹配的节点;

    c.绑定(select):把pod绑定到优选的节点上.

    调度方式有如下几类:

    a.nodeaffinity:表示node亲和性调度,表示pod对这个节点有一定的倾向性,通过nodeselector来完成这类调度;

    b.podaffinity或podunaffinity:pod亲和性或者pod反亲和性调度,有时我们期望某些Pod运行在同一个节点上或者是相邻的节点上,或者我们期望某些Pod不能运行在某些节点上;

    c.taints和tolerations:污点和污点容忍调度,可以在某些节点上打上污点,表示这些节点不让pod在其上面运行,taints是定义在节点之上的,tolerations是定义在pod之上的.

    2.常用的预选策略:

    源码:https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/algorithm/predicates/predicates.go

    一票否决制,有一个不符合,则该节点就会被排除

    a.ChekNodeCondition:检测节点状况是否允许将pod调度上去;

    b.GeneralPredicate:通用预选策略

    1).hostname:如果某pod定义了hostname属性(pod.spec.hostname),则检查节点的名字跟pod的hostname是否匹配,如果该节点有了相同名字的pod,则不在这个节点上部署;

    2).PodFitsHostPorts:如果节点定义了hostport属性(pod.spec.containers.ports.hostPort),表示指定在节点的哪个端口上,如果这个节点的端口被占用了,那么这个节点就不适合运行这个pod;

    3).MatchNodeSelector:检查pods.spec.nodeSelector这个字段你是否定义了,运行在有这些标签选择器的节点上;

    4).PodFitsResources:检查节点是否有足够的资源来支撑这个pod运行;

    kubectl describe nodes k8s-node1

    5).NoDiskConfict:检查Pod依赖的存储卷在此节点上是否能满足需求,该调度策略默认没有启用;

    6).PodToleratesNodeTaints:如果Pod定义了Tolerates(容忍度),即pods.spec.tolerations,那么就看pod能不能容忍节点上的污点,如果能容忍,表示这个节点可以被选定;

    7).PodToleratesNodeNoExecuteTaints:检查pod是否容忍节点上有NoExecute污点.如果一个pod上运行在一个没有污点的节点上后,这个节点又被加上了污点,

    那么NoExecute表示这个新加污点的节点会驱逐其上正在运行的pod;不加NoExecute表示不会驱逐,表示接受既成事实,这是默认策略.

    8).CheckNodeLabelPresence:检查节点上指定标签的存在性,如果节点有pod指定的标签,那么这个节点就被选中,默认没有启用;

    9).CheckServceAffinity:一个service下可以有多个pod,比如这些pod都运行在1、2、3机器上,而没有运行在4、5、6机器上,那么CheckServceAffinity就表示新加入的pod都集中运行在1、2、3机器上,默认没有启用.

    3.常用的优选函数

    源码:https://github.com/kubernetes/kubernetes/tree/master/pkg/scheduler/algorithm/priorities

    1)least_requested:计算出资源空闲率最大的节点;

    2)balanced_resource_allocation:以cpu和内存占用率的相近程度作为评估标准,二者占用越接近,得分就越高;

    3)node_prefer_avoid_pods:看节点是否有注解信息"scheduler.alpha.kubernetes.io/preferAvoidPods",没有这个注解信息,说明这个节点适合运行这个pod的;

    4)toleration:将pod对象的spec.toleration与节点的taint列表项进行匹配度检查,匹配的条目越多,得分越低;

    5)selector_spreading:spreading是散开的意思,查找当前pod对象对应的标签选择器,在节点上运行的带有这样标签的pod越少得分越高,这样的节点被优先选出;

    6)interpod_affinity:遍历Pod对象亲和性的条目,并将那些能够匹配到节点权重相加,值越大的得分越高,得分高的胜出;

    7)node_affinity:根据pod对象中的nodeselector,对节点进行匹配度检查,能够成功匹配的数量越多,得分就越高;

    8)most_requested:表示尽可能的把一个节点的资源先用完,和least_requested相反,二者不能同时使用;

    9)node_label:根据节点是否拥有标签,来评估分数;

    10)image_locality:表示根据满足当前pod对象需求的已有镜像的体积大小之和来选择节点的.

    最后三个默认没有启用

    4.高级调度方式演示

    节点选择器:nodeSelector(给node打上标签,pod通过标签,预选节点),nodeName

    a.节点亲和调度:nodeAffinity

    kubectl explain pods.spec.affinity.nodeAffinity
    preferredDuringSchedulingIgnoredDuringExecution:软亲和,可以满足,也可以不满足;
    requiredDuringSchedulingIgnoredDuringExecution:硬亲和,表示必须满足.
    # 硬亲和演示
    cat pod-nodeaffinity-demo.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-node-affinity-demo
      namespace: default
      labels:
        app: myapp
    spec:
      containers: 
      - name: myapp
        image: ikubernetes/myapp:v1
      affinity:
         nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: zone
                operator: In
                values:
                - foo
                - bar
    # 因为没有任何一个节点拥有zone这个标签,所以pod-node-affinity-demo运行不起来 
    # 创建一个软亲和性的pod
    cat pod-nodeaffinity-demo2.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-node-affinity-demo-2
      namespace: default
      labels:
        app: myapp
    spec:
      containers: 
      - name: myapp
        image: ikubernetes/myapp:v1
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - preference:
              matchExpressions:
              - key: zone
                operator: In
                values:
                - foo
                - bar
            weight: 60
    

    b.pod亲和调度-一组pod(NMT是亲和的),N被调度到哪,剩下的pod跟着去

    将同一个机柜里的服务器都打上同一个标签,如果pod设置了亲和调度,则会被分到同一个机柜;

    扩大范围,这些机柜是否是同一列,也就是它们的row是否相同,如果row相同,则也符合亲和调度.

    kubectl explain pods.spec.affinity.podAffinity
    preferredDuringSchedulingIgnoredDuringExecution:软亲和,尽量满足标签
    requiredDuringSchedulingIgnoredDuringExecution:硬亲和,必须满足标签
    kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution
    topologyKey:定义row那样的键;
    labelSelector:表示选定一组资源,跟哪些pod进行亲和;
    namespaces:指定Pod属于哪个名称空间中,一般不跨名称空间去引用;
    
    cat pod-required-affnity-demo.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-first
      namespace: default
      labels:
        app: myapp
        tier: frontend
    spec:
      containers: 
      - name: myapp
        image: ikubernetes/myapp:v1
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-second
      namespace: default
      labels:
        app: db
        tier: backend
    spec:
      containers: 
      - name: busybox
        image: busybox:latest
        imagePullPolicy: IfNotPresent
        command: ["sh","-c","sleep 3600"]
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution: # 硬亲和性
          - labelSelector:
              matchExpressions: # 匹配pod,而不是匹配节点
              - {key: app, operator: In, values: ["myapp"]}
            topologyKey: kubernetes.io/hostname
    
    当前这个pod要跟一个有着标签app=myapp(要和上面pod-first的metadata里面的标签一致)的pod在一起
    

    c.pod反亲和调度

    将上面配置文件中的podAffinity改为podAntiAffinity,则两个pod会被反亲和调度
    给两个节点打一样的标签 
    kubectl label nodes k8s-node1 zone=foo
    kubectl label nodes k8s-node2 zone=foo
    将上面配置文件中的topologyKey改为zone,则第一个pod正常运行,第二个pod会挂起pending
    

    d.污点调度

    前面几种调度方式都是让pod来选择节点,污点是让节点来选择哪些pod能运行在其上面

    kubectl explain nodes.spec.taints

    effect:表示当pod不能容忍节点上污点时的行为是什么,主要有三种排斥等级:

    NoSchedule:仅影响调度过程,不影响现存pod,没调度过来的就调度不过来了,如果对节点新加了污点,那么对节点上现存的Pod没有影响;

    NoExecute:既影响调度过程,也影响现存Pod,没调度过来的就调度不过来了,如果对节点新加了污点,那么对现存的pod对象将会被驱逐;

    PreferNoSchedule:不能容忍就不能调度过来,但是实在没办法也是能调度过来的,对节点新加了污点,那么对节点上现存的pod没有影响.

    # 查看master上的污点
    kubectl describe node k8s-master
    Taints: node-role.kubernetes.io/master:NoSchedule
    # flannel和kube-proxy能运行在master上是因为,它们能容忍污点
    kubectl describe pods -n kube-system kube-flannel-ds-amd64-zwhwg
    Tolerations::NoSchedule
      node.kubernetes.io/disk-pressure:NoSchedule
    # 给node1打上污点node-type=production:NoSchedule,污点和容忍度都是自定义的键值对
    kubectl taint node k8s-node1 node-type=production:NoSchedule
    kubectl explain pods.spec.tolerations
    tolerationSeconds:表示宽限多长时间pod被驱逐;
    operator:操作符,其值有Exists-表示节点有这个污点的key,pod都能容忍;
    Equal-表示节点必须精确匹配污点的key和value才能容忍.
    
    cat pod-demo.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: myapp-deploy
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: myapp
          release: canary
      template:
        metadata:
          labels:
            app: myapp
            release: canary
        spec:
          containers:
          - name: myapp
            image: ikubernetes/myapp:v1
            ports:
            - name: http
              containerPort: 80
          tolerations: 
            - key: "node-type"
              operator: "Equal"
              value: "production"
              effect: "NoSchedule"
    # 表示pod必须精确容忍这样的节点--污点是node-type=production,且effect是NoSchedule
    tolerations: 
         - key: "node-type"
           operator: "Equal"
           value: "production"
           effect: "NoSchedule"
    
    # 表示pod容忍这样的节点--存在污点key是node-type,不管value是什么,且effect是NoSchedule
    tolerations: 
        - key: "node-type"
          operator: "Exists"
          value: ""
          effect: "NoSchedule"
    
    # 表示pod容忍这样的节点--存在污点key是node-type,不管value是什么,不管节点的effect是什么
    tolerations: 
        - key: "node-type"
          operator: "Exists"
          value: ""
          effect: ""
    

    参考博客:http://blog.itpub.net/28916011/viewspace-2215522/

  • 相关阅读:
    多线程间通信之AutoResetEvent和ManualResetEvent的原理分析和开发示例
    【推荐】基于WebActivator的改进版本KudyStudio.Web.Activating讲解与源码下载
    Visual Studio中你所不知道的智能感知
    压缩网页图片
    二叉树
    DynamicXml 动态读取操作XML (一个从XML到Object的通用实现)
    张剑微软2011 GCR MVP Open Day 之旅!【转载】
    使用Solr构建企业级的全文检索
    jQuery版仿Path菜单发布!
    使用maven进行开发过程管理之准备篇
  • 原文地址:https://www.cnblogs.com/fawaikuangtu123/p/11296493.html
Copyright © 2020-2023  润新知