• 透彻理解kube-scheduler是如何完成调度的


    kube-scheduler负责分配调度pod到集群内的节点上,它监听kube-apiserver,查询还未分配Node的pod,根据调度策略为这些pod分配节点,调度器在给pod分配节点时需要充分考虑多方面信息,需要考虑的信息如下所示:
    公平调度
    资源高效利用
    Qos
    affinity和anti-affinity
    数据本地化(data locality)
    内部负载干扰(inter-workload interference)
    deadlines等

    kube-scheduler调度分为两个阶段,predicate和priority,predicate过滤不符合条件的节点,priority选择高优先级的节点。Predicate策略有多个,
    内置的Predicate策略如下所示,除下面列举的部分策略外,还有其他策略,另外,还可以自定义Predicate策略。

    • PodFitsHostPorts:检查是否有Host Ports冲突
    • PodFitsResources:检查Node的资源是否充足,包括允许的Pod数、CPU、内存等
    • HostName:检查pod.Spec.NodeName是否与候选节点一致
    • MatchNodeSelector:检查候选节点的pod.Spec.NodeSelector是否匹配
    • PodTolerateNodeTaints:检查Pod是否容忍Node Taints
    • MatchInterPodAffinity:检查是否匹配Pod的亲和性要求

    和Predicate一样,priority也内置了很多策略,如下所示,下面列举了部分priority策略。

    • InterPodAffinityPriority:优先将pod调度到相同拓扑上(如同一个节点、Rack、Zone等)
    • LeastRequestedPriority:优先调度到请求资源少的节点上
    • BalancedResourceAllocation:优先平衡各个节点的资源使用
    • NodeAffinityPriority:优先调度到匹配NodeAffinity的节点上
    • TaintTolerationPriority:优先调度到匹配TaintToleration的节点上

    接着我们来看看实际例子,第一类例子是在定义pod的deployment文件时,可以设置pod请求的cpu/memory资源以及cpu/memory资源上限,这样kube-scheduler在调度的时候可以根据这些信息把pod分配到更合理的node节点上,具体的yaml文件如下所示:

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. name: nginx-deployment
    5. spec:
    6. replicas: 1
    7. selector:
    8. matchLabels:
    9. app: nginx
    10. template:
    11. metadata:
    12. labels:
    13. app: nginx
    14. spec:
    15. containers:
    16. - name: nginx
    17. image: nginx
    18. resources:
    19. limits:
    20. memory: 1Gi
    21. cpu: 1
    22. requests:
    23. memory: 256Mi
    24. cpu: 100m

    通过上面的文件创建pod,查看pod的信息(kubectl describe podname)可以看到启动的pod的资源设置和yaml文件中设置一致。

    除了对单个pod或者container进行资源限制设置外,还可以对namespace中所有pod或者所有container中所使用的资源进行限制。如下所示创建limitRange对象,namespace中创建的pod或者container总使用的cpu或者memory量不能大于max cpu和max memory。

    接着看第二类例子,第二类例子是设置nodeSelector或者设置pod-anti-affinity,这样kube-scheduler在调度pod的时候会根据设置的信息将pod调度到合理的node节点上。

    pod的Deployment yaml文件中设置的nodeSelector,如下所示

    创建pod,会看到pod一直是pending状态,查看pod信息,可以看到因为没有找到match的node

    给node打上label,pod从pending状态变成running状态。

    查看node节点的标签命令:kubectl get node --show-labels

    给node节点打上标签命令:kubectl label nodes nodename key=value

    删除node节点上的标签命令:kubectl label nodes nodename key-

    除了通过nodeSelector将pod分配到指定的node节点上外,还可以通过nodeAffinity来设置,下面是一个强node亲和性设置,如果集群中不存在如下标签的node节点,pod会处于pending状态

    除了强亲和性,还可以设置弱亲和性,当有满足条件的pod时,就分配到满足的node上,如果不存在则分配到任意一个node上。

    Node可以设置亲和性,pod间也可以设置亲和性和反亲和性,例如相同的一个服务,需要部署多个pod副本,为了高可用,这些pod期望分配到不同node节点上,那么可以设置pod的反亲和性达到这样的效果。下面的例子中podAffinity设置了pod部署到一个已经存在运行的pod的节点上,且这个允许的pod的label key=a,value=b。podAntiAffinity设置了pod不能部署到这样的node,node上存在了已经允许pod,pod的label的key=app,value=anti-nginx.

    上述的deployment文件创建pod,pod使用处于pending状态,因为node节点上不存在允许的pod,且pod的label key=a,value=b.删除podAffinity,只保留podAntiAffinity,再次创建pod,可以看到pod创建成功,因为replicas=2,所以会创建两个pod,且两个pod分别被创建在不同的node节点上。

     接着再看看如何通过设置污点(Taints)和容忍度(Tolerations)来控制哪些pod被部署到期望的node节点上。例如大数据的项目非常耗费资源,可能想把大数据类的应用部署到独享的某些节点上,防止其他应用占用了这些节点资源,针对这种需求,那么可以把这些节点设置Taints,其他团队在不知道节点的Taints的情况下,所有的应用就不会部署到这些节点上。

    给节点打上污点的命令:kubectl taint nodes nodename for-special-user=taintstest:NoSchedule

    取消节点上的污点命令:kubectl taint nodes nodename for-special-user=taintstest:NoSchedule-

    查看节点上的污点命令:kubectl describe nodes {Node名称}

    pod的deployment yaml文件中如果设置了tolerations,那么这个pod就会被部署到指定的node节点上,具体内容如下所示:

    以上介绍了如何设置资源limit/request,nodeSelector,podAffinity/podAntiAffinity,taints&&tolerations来影响kube-schedule,从而实现将某些pod部署到指定的node节点上。

  • 相关阅读:
    我要写整个中文互联网界最牛逼的JVM系列教程 | 「类加载子系统」章节:类的加载过程之三:Initialization
    2、MYSQL之InnoDB一次数据更新流程
    CTF 全讲解:[SWPUCTF 2022 新生赛]webdog1__start
    ThreadLocal for Golang
    Stable Diffusion 是否使用 GPU?
    JVM学习-Class文件结构
    SpringBoot 统一异常处理
    PMP考点有哪些啊?
    小蚂蚁过河
    常见的最优化方法
  • 原文地址:https://blog.csdn.net/qiaotl/article/details/125600029