我们前面的一个章节Kubernetes(k8s)-Request&Limit介绍,介绍过Request参数是决定Pod调度的一个很重要的指标,实际上在Kubernetes里面有非常多的调度算法来决定某一个Pod应该落到哪个节点上面,下面我们就来介绍下这些算法。

node标签

# 查看节点标签
kubectl get node --show-labels=true

# 添加标签 key=value
kubectl label nodes node1 node=node1

# 去除标签 key-
kubectl label nodes node1 node-

node标签选择器

如果同时指定了 nodeSelectornodeAffinity,两者必须都要满足, 才能将 Pod 调度到候选节点上。
如果指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms,满足一个 nodeSelectorTerms ,pod将可以调度到节点上。
指定了多个与 nodeSelectorTerms 关联的 matchExpressions,满足所有 matchExpressions ,Pod 才会可以调度到节点上。
由于IgnoredDuringExecution,改变labels不会影响已运行的pod.

在这里插入图片描述


nodeSelector

参考: 将 Pod 分配给节点

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  # 选择node标签为disktype=ssd的node  
  nodeSelector:
    disktype: ssd

Node亲和性调度affinity

理解 Kubernetes 的亲和性调度

官方doc-节点亲和性

K8S高级调度方式

requiredDuringSchedulingIgnoredDuringExecution: 硬策略/硬需求–必须满足
preferredDuringSchedulingIgnoredDuringExecution: 软策略/软需求–尽量满足

支持的操作符有:
In , 包含
NotIn , 不包含,一般用来做反亲和(Anti-Affinity)
Exists , 存在
DoesNotExist ,不存在
Gt , (greater than), label 的值大于某个值,int类型
Lt , (less than),label 的值小于某个值,int类型
在这里插入图片描述

name in( redis-master, redis-salve)# 匹配所有带有标签name=master或者name=salve的资源

name not in ( php)#匹配所有不具有标签name=php的资源对象

亲和度示例yaml

pod 亲和性 的示例

apiVersion: v1
kind: Pod
metadata:
  name: myapp
  labels:
    name: myapp
spec:
# 亲和性
  affinity:
    # 节点亲和度
    nodeAffinity:
      # 硬策略/硬需求
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              # 匹配所有带有标签disktype=ssd或者disktype=shd的资源
              - key: disktype
                operator: In
                values:
                  - ssd
                  - shd
      # 软策略/软需求(尽量匹配标签的资源,不满足时会找其他的资源)
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1  # 权重值/(加分项,1-100,100是最高分),能提高匹配概率,不用太关注
          preference:  # 固定语法,意为偏爱
            matchExpressions:
              # 尽可能匹配标签为disktye=ssd2的资源
              - key: disktype
                operator: In
                values:
                  - ssd2
  containers:
  - name: myapp
    image: <Image>
    resources:
      limits:
        memory: "128Mi"
        cpu: "500m"
    ports:
      - containerPort: <Port>

nodeName

参考: pod 调度到一个指定节点

nodeName不会通过调度器,即使node有污点也能直接运行pod.一般用于测试.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: node1 # 让pod运行在指定node上,nodeName不会通过调度器
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent

node调度故障诊断排查

# 显示给定节点的度量值                                            
kubectl top node my-node                                             

# 显示主控节点和服务的地址
kubectl cluster-info

# 将当前集群状态转储到标准输出                                                  
kubectl cluster-info dump

# 将当前集群状态输出到 /path/to/cluster-state                                            
kubectl cluster-info dump --output-directory=/path/to/cluster-state   

常见调度失败原因

  • CPU不足
  • 没有匹配到节点标签
  • 所有的节点有污点,但你没有配置污点容忍

pod一直是pending

参考: https://cloud.tencent.com/document/product/457/42948

当Pod处在Pending的时候,可能是由于如下哪个问题造成的。
资源不足,造成无法调度;
Pod尚未进入调度阶段;
Pod正在拉取镜像;
看kubelet日志.

# 查看pod详情
kubectl describe po pod名
## 显示pod已经调度到node2,但一直是pending

查看node资源是否足够
# 查看node资源是否足够
kubectl describe node <node-name>

# 或kubectl top node

在返回信息中,请注意关注以下内容:
Allocatable:表示此节点能够申请的资源总和。
Allocated resources:表示此节点已分配的资源(Allocatable 减去节点上所有 Pod 总的 Request)。

Pod的调度

Pod 的调度是 Kubernetes 中将 Pod 放置在合适节点上运行的过程。调度器是 Kubernetes 控制平面的一部分,它负责根据调度算法和当前集群的状态选择最佳节点。以下是 Pod 调度的主要步骤和考虑因素:

  1. 调度需求:首先,定义你的 Pod 需要什么样的资源和条件。这可以通过资源请求、限制和 Pod 亲和性规则来指定。
  2. 资源请求和限制:在 Pod 的定义中,可以为每个容器指定 resources.requests(最小资源需求)和 resources.limits(资源使用上限)。调度器会确保 Pod 分配到的节点有足够的资源来满足其请求。在真正的生产集群应该为每个Pod配置对应的资源需求和资源限制,并让服务器留有足够的冗余,当某节点故障的时候,确保还有足够的剩余资源满足故障Pod的创建。
  3. 标签和选择器:通过标签(Labels)和选择器(Selectors)可以控制 Pod 应该调度到哪些节点上。节点亲和性(node affinity)和反亲和性(node anti-affinity)规则允许 Pods 被吸引或排斥于具有特定标签的节点。
  4. 污点和容忍度:节点上的污点(Taints)阻止某些 Pod 调度到这些节点上,除非这些 Pod 有匹配的容忍度(Tolerations)。
  5. Pod 亲和性和反亲和性:Pod 可以通过 Pod 亲和性规则被调度到运行特定 Pod 的节点上,或者通过 Pod 反亲和性规则避免被调度到运行特定 Pod 的节点上。
  6. 节点选择器:通过节点选择器(nodeSelector),可以将 Pod 分配给具有特定标签的节点。
  7. PVC关联性: 某些Pod是带有PVC资源的,而部分PVC资源是绑定在某一个节点的,那么这个Pod则只能落到某一个固定节点上面。

调度器在决定将 Pod 放置在何处时,遵循以下基本流程:

  • 预选(Predicates):调度器筛选出符合 Pod 资源请求、节点选择器、容忍度等要求的节点。排除那些不满足基本前提条件的节点。
  • 优选(Priorities):对于通过预选的节点,调度器会评分,优先考虑那些资源利用率最高、最能满足 Pod 亲和性/反亲和性规则的节点。
  • 绑定(Binding):一旦选择了最佳节点,调度器会创建一个绑定操作,将 Pod 和选定的节点关联起来。

Pod 调度是一个复杂的过程,它涉及到多种不同的策略和算法。了解这些概念有助于优化 Pod 的调度策略,使得 Kubernetes 集群能够更高效、稳定地运行。它是由管控组kube-scheduler来完成的。

下面的日志就是我测试集群节点的演示日志

I0204 08:25:52.832631       1 resource_allocation.go:73] "Listing internal info for allocatable resources, requested resources and score" pod="default/nginx-deployment-c5cbddb86-66ggl" node="node01" resourceAllocationScorer="LeastAllocated" allocatableResource=map[cpu:2000 memory:3890135040] requestedResource=map[cpu:750 memory:1258291200] resourceScore=64
I0204 08:25:52.832649       1 resource_allocation.go:73] "Listing internal info for allocatable resources, requested resources and score" pod="default/nginx-deployment-c5cbddb86-66ggl" node="node01" resourceAllocationScorer="NodeResourcesBalancedAllocation" allocatableResource=map[cpu:2000 memory:3890135040] requestedResource=map[cpu:250 memory:0] resourceScore=93
I0204 08:25:52.832661       1 resource_allocation.go:73] "Listing internal info for allocatable resources, requested resources and score" pod="default/nginx-deployment-c5cbddb86-66ggl" node="node02" resourceAllocationScorer="LeastAllocated" allocatableResource=map[cpu:2000 memory:3890126848] requestedResource=map[cpu:450 memory:629145600] resourceScore=80
I0204 08:25:52.832670       1 resource_allocation.go:73] "Listing internal info for allocatable resources, requested resources and score" pod="default/nginx-deployment-c5cbddb86-66ggl" node="node02" resourceAllocationScorer="NodeResourcesBalancedAllocation" allocatableResource=map[cpu:2000 memory:3890126848] requestedResource=map[cpu:250 memory:0] resourceScore=93
I0204 08:25:52.832722       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="NodeResourcesFit" node="node01" score=64
I0204 08:25:52.832728       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="NodeResourcesFit" node="node02" score=80
I0204 08:25:52.832732       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="VolumeBinding" node="node01" score=0
I0204 08:25:52.832736       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="VolumeBinding" node="node02" score=0
I0204 08:25:52.832740       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="PodTopologySpread" node="node01" score=200
I0204 08:25:52.832744       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="PodTopologySpread" node="node02" score=200
I0204 08:25:52.832748       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="InterPodAffinity" node="node01" score=0
I0204 08:25:52.832752       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="InterPodAffinity" node="node02" score=0
I0204 08:25:52.832756       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="NodeResourcesBalancedAllocation" node="node01" score=93
I0204 08:25:52.832760       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="NodeResourcesBalancedAllocation" node="node02" score=93
I0204 08:25:52.832764       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="ImageLocality" node="node01" score=3
I0204 08:25:52.832768       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="ImageLocality" node="node02" score=0
I0204 08:25:52.832772       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="TaintToleration" node="node01" score=300
I0204 08:25:52.832777       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="TaintToleration" node="node02" score=300
I0204 08:25:52.832781       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="NodeAffinity" node="node01" score=0
I0204 08:25:52.832785       1 generic_scheduler.go:434] "Plugin scored node for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" plugin="NodeAffinity" node="node02" score=0
I0204 08:25:52.832791       1 generic_scheduler.go:491] "Calculated node's final score for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" node="node01" score=660
I0204 08:25:52.832795       1 generic_scheduler.go:491] "Calculated node's final score for pod" pod="default/nginx-deployment-c5cbddb86-66ggl" node="node02" score=673

1. 资源分配评分插件

这个打分过程包括
在这里插入图片描述

a. NodeResourcesFit(资源适配度)
  • 作用:检查节点资源是否能满足 Pod 需求。
b. NodeResourcesBalancedAllocation(资源平衡分配)
  • 作用:确保 CPU 和内存资源的分配平衡,避免某一资源耗尽。

2. 存储相关插件

VolumeBinding(卷绑定)
  • 作用:检查节点是否满足 Pod 的卷绑定需求(如 PVC 绑定状态)。

3. 拓扑与亲和性插件

a. PodTopologySpread(Pod 拓扑分布)
  • 作用:确保 Pod 在指定拓扑域(如节点、区域)中均匀分布。
b. InterPodAffinity(Pod 间亲和性/反亲和性)
  • 作用:检查 Pod 与其他 Pod 的亲和性/反亲和性规则。
c. NodeAffinity(节点亲和性)
  • 作用:检查节点标签是否匹配 Pod 的亲和性规则。

4. 镜像与污点容忍插件

a. ImageLocality(镜像本地性)
  • 作用:优先选择已存在 Pod 所需镜像的节点。
b. TaintToleration(污点容忍)
  • 作用:检查节点污点是否被 Pod 容忍。

5. 最终得分计算

6. 调度结果

  • 得分对比:node02 总分 673 > node01 总分 660。
  • 调度决策:调度器会将 Pod nginx-deployment-c5cbddb86-66ggl 绑定到 node02
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐