Kubernetes的Pod调度策略详解及实战操作【建议收藏】

科技   2024-11-28 07:30   广东  

前一篇文章已经带你们深入了解kubernetes中调度、抢占和驱逐的相关概念。这篇文章主要详细介绍Pod的几种常用调度策略,并根据实战操作来加深原理理解,在生产环境也经常使用。

Pod 的调度策略主要包括:

  • nodeSelector
  • 亲和性与反亲和性
  • nodeName
  • Pod 拓扑分布约束
  • 污点与容忍性

1. Pod调度概述

调度器通过 Kubernetes 的监测(Watch)机制来发现集群中新创建且尚未被调度到节点上的 Pod。调度的主要任务是将Pod分配到集群中的合适的节点上。调度器根据Pod的需求(如CPU、内存、存储等)和节点的资源状况(如可用CPU、内存、节点标签等)来决定Pod部署在哪个节点上。

调度已经在前面文章讲解过了,就不详细展开了。下面就详细介绍一下具体的调度策略

2. 调度策略详解

2.1 nodeSelector

nodeSelector 是 Kubernetes 中最简单、最直观的调度机制,它基于节点标签进行 Pod 调度。节点标签是 Kubernetes 用于标识节点属性的键值对,调度器会根据这些标签来决定将 Pod 调度到哪个节点。

工作原理:

每个 Kubernetes 节点可以具有多个标签(labels)。标签是 key: value 的形式,通常表示节点的特征,如硬件类型、地区、环境等。

Pod 的 nodeSelector 字段指定一组标签,调度器会筛选出具有这些标签的节点,然后将 Pod 调度到这些节点。

使用场景:

  • 环境隔离:比如,你有一些节点专门用于生产环境,其他节点用于测试环境,使用 nodeSelector 来确保 Pod 只在生产节点上运行。
  • 硬件要求:例如,某些应用需要 SSD 磁盘或特定的 CPU 类型,你可以使用 nodeSelector 来确保 Pod 调度到符合这些硬件要求的节点。

实战操作:

1、给节点打上标签

# 给k8s-node2节点打上ssd标签
kubectl label node  k8s-node2 disktype=ssd

# 查看标签
kubectl get node k8s-node1 --show-labels

2、编写yaml文件

【温馨提示】生产环境不要直接运行pod,这里只是为了演示效果

vim nodeSelector.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeSelector:
    disktype: ssd

  containers:
  - name: nginx
    image: docker.m.daocloud.io/nginx:1.25

运行pod

kubectl apply -f nodeSelector.yaml

3、查看pod调度情况

[root@k8s-master data]# kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          60s   10.224.169.149   k8s-node2   <none>           <none>

已经根据节点标签将pod调度到node2节点。

nodeSelector的优缺点:

  • 优点:简单高效。
  • 缺点:灵活性差,无法处理复杂的调度需求。

2.2 亲和性与反亲和性

亲和性(Affinity)和反亲和性(Anti-Affinity)是比 nodeSelector 更强大、更灵活的调度策略。它们允许用户根据更多的条件进行节点选择,比如节点的标签、Pod 的存在与否等。

亲和性(Affinity)用于指定 Pod 需要尽量调度到某些节点上,基于节点标签、Pod 与节点的关系等。 

反亲和性(Anti-Affinity)用于指定 Pod 不应该调度到某些节点,或者应该尽量避免和其他 Pod 调度到同一个节点上。

Kubernetes 中有两种亲和性:

  • 节点亲和性(Node Affinity)
  • Pod 亲和性与反亲和性(Pod Affinity & Anti-Affinity)。

节点亲和性

节点亲和性是 nodeSelector 的增强版,允许基于更复杂的规则选择节点。

实战操作

1、编写yaml文件

vim nodeAffinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx2
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd

  containers:
  - name: nginx2
    image: docker.m.daocloud.io/nginx:1.25

确保 Pod 只会调度到具有 disktype=ssd标签的节点。

2、运行pod

kubectl apply -f nodeAffinity.yaml

3、查看pod调度情况

[root@k8s-master data]kubectl get pod -o wide
NAME     READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
nginx    1/1     Running   0          27m     10.224.169.149   k8s-node2   <none>           <none>
nginx2   1/1     Running   0          3m16s   10.224.169.154   k8s-node2   <none>           <none>

已经将pod调度到预期的node上

字段解释:

  • nodeAffinity 是定义节点选择规则的字段。通过 requiredDuringSchedulingIgnoredDuringExecution(必须满足调度时条件)和 preferredDuringSchedulingIgnoredDuringExecution(调度时首选,但不强制)来定义硬性和软性约束。
  • matchExpressions 支持使用 In、NotIn、Exists 等操作符,这些操作符使得你可以做更复杂的条件匹配。

operator 字段操作符说明:

操作符说明
In指定值必须在给定的列表中
NotIn指定值不在给定的列表中
Exists指定键存在,不关心值
DoesNotExist指定键不存在

Pod 亲和性

Pod 亲和性允许你指定 Pod 希望与其他 Pod 一起调度的偏好,而反亲和性则表示 Pod 希望避免与某些 Pod 一起调度。

1、给前面创建的pod打上app=nginx1的标签

# 给使用nodeSelector创建的nginx打上标签
kubectl label pod nginx app=nginx1

2、编写yaml文件

vim podAffinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx3
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:   # 满足条件才调度
      - labelSelector:
          matchExpressions:
            - key: app
              operator: In
              values:
                - nginx1
        topologyKey: "kubernetes.io/hostname"

  containers:
  - name: nginx3
    image: docker.m.daocloud.io/nginx:1.25

3、运行pod

kubectl apply -f podAffinity.yaml

4、查看调度情况

[root@k8s-master data]kubectl get pod  -o wide
NAME     READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
nginx    1/1     Running   0          4h32m   10.224.169.149   k8s-node2   <none>           <none>
nginx2   1/1     Running   0          4h8m    10.224.169.154   k8s-node2   <none>           <none>
nginx3   1/1     Running   0          14s     10.224.169.153   k8s-node2   <none>           <none>

可见pod已经调度到node2上,现在3个都运行在node2上,接下来测试一下反亲和性

Pod 反亲和性

要求 Pod 不与特定的 Pod 调度到同一节点上,通常用于防止某些类型的 Pod 集中到同一节点上,避免单点故障。

1、编写yaml文件

vim podAntiAffinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx4
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions: # 不要和具有app=nginx1标签的Pod在同一节点
            - key: app
              operator: In
              values:
                - nginx1

        topologyKey: "kubernetes.io/hostname"
  containers:
  - name: app
    image: docker.m.daocloud.io/nginx:1.25

2、运行pod

kubectl apply -f podAntiAffinity.yaml

3、查看调度情况

[root@k8s-master data]# kubectl get pod -o wide
NAME     READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
nginx    1/1     Running   0          4h37m   10.224.169.149   k8s-node2   <none>           <none>
nginx2   1/1     Running   0          4h13m   10.224.169.154   k8s-node2   <none>           <none>
nginx3   1/1     Running   0          5m26s   10.224.169.153   k8s-node2   <none>           <none>
nginx4   1/1     Running   0          10s     10.224.36.69     k8s-node1   <none>           <none>

可以看到新建的nginx4避免与标签为 app=nginx1的 Pod 调度到同一节点上,所以被调度到node1上,验证了pod的反亲和性

亲和性和反亲和性优缺点:

优点:

  • 灵活性强:支持多条件、复杂的调度规则,可以基于节点标签、Pod 标签、拓扑结构等进行细粒度控制。
  • 支持跨节点调度:可以控制 Pod 在集群中的分布,增强应用的可用性和容错性。

缺点:

  • 配置复杂:调度规则更加复杂,理解和配置起来需要更多的时间。
  • 可能影响调度效率:当使用大量的亲和性和反亲和性规则时,调度器需要更多时间来评估每个节点的匹配情况。

2.3 nodeName

nodeName 是 Kubernetes 中一种最简单且强制性的调度方式,它允许你直接指定一个节点来运行 Pod,而无需依赖调度器的调度决策。nodeName 适用于一些特殊场景,比如需要将 Pod 调度到特定的节点(例如硬件节点,或特定的节点上有特定设备,如 GPU)。

实战操作:

1、编写yaml

vim nodeName.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx5
spec:
  nodeName: k8s-node1
  containers:
  - name: nginx5
    image: docker.m.daocloud.io/nginx:1.25

2、运行pod

kubectl apply -f nodeName.yaml

3、查看调度情况

[root@k8s-master data]# kubectl get pod nginx5 -o wide
NAME     READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
nginx5   1/1     Running   0          47s   10.224.36.70   k8s-node1   <none>           <none>

可以看到Pod nginx5 会被直接调度到 node1节点上。

nodeName优缺点:

  • 优点:简单、直观,适用于需要特定硬件或设备的场景。
  • 缺点:失去调度器的灵活性,不适用于动态环境。

2.4 Pod 拓扑分布约束

Pod 拓扑分布约束用于保证 Pod 在多个节点、区域或故障域中的均衡分布。通过设置 topologySpreadConstraints,可以确保 Pod 在集群中分布更加均衡,避免 Pod 集中到某个节点或某个区域,从而增强集群的高可用性和容灾能力。

apiVersion: v1
kind: Pod
metadata:
  name: nginx6
spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: nginx

  containers:
  - name: nginx6
    image: docker.m.daocloud.io/nginx:1.25
[root@k8s-master data]# kubectl get pod nginx6 -o wide
NAME     READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
nginx6   1/1     Running   0          37s   10.224.36.71   k8s-node1   <none>           <none>

使用deployment来演示可能效果更明显

topologySpreadConstraints 保证 nginx Pod 在不同的主机上均匀分布。maxSkew 控制 Pod 在各个节点之间的最大不平衡度,而 topologyKey 是表示分布维度的关键字段,kubernetes.io/hostname 表示按主机名进行分布。

优缺点:

  • 优点:保证 Pod 在多个节点、区域的均衡分布,提高高可用性。
  • 缺点:配置较复杂,可能对调度性能产生影响。

2.5 污点与容忍性

污点(Taints)和容忍性(Tolerations)是 Kubernetes 的一对调度机制,用于控制 Pod 是否能调度到带有某些特定条件的节点。节点可以加上污点,只有设置了相应容忍性的 Pod 才能调度到这些节点。

污点(Taints) 是对节点的标记,表示该节点不希望接受不符合条件的 Pod。容忍(Tolerations) 是 Pod 上的标记,表示 Pod 能够“容忍”某些污点。

实战操作:

1、给节点加污点:

# 在节点1上添加污点
kubectl taint nodes k8s-node1 key=value:NoSchedule

【温馨提示】设置污点后,新建的pod如果没有设置容忍,都无法调度到该节点,已存在的pod不受影响。

2、Pod 上设置容忍性:

vim tolerations.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx7
spec:
  tolerations: # 配置容忍规则,需要完全匹配才可以调度到有污点的节点
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"

  containers:
  - name: nginx7
    image: docker.m.daocloud.io/nginx:1.25

3、查看调度情况

[root@k8s-master data]kubectl get pod nginx7 -o wide
NAME     READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
nginx7   1/1     Running   0          32s   10.224.36.72   k8s-node1   <none>           <none>

nginx7被调度到设置了污点的节点,说明tolerations生效了,容忍了污点。

4、去除污点(taint)

kubectl taint node k8s-node1 key-

优缺点:

  • 优点:提供了灵活的节点隔离和调度控制,适用于隔离特定类型的工作负载或维护节点。
  • 缺点:配置复杂,滥用污点可能导致资源浪费或 Pod 调度错误。

总结

Kubernetes 提供了多种调度策略,可以根据不同的需求灵活选择:

  • nodeSelector:简单的节点标签匹配调度。
  • 亲和性与反亲和性:更灵活的调度控制,基于节点和 Pod 之间的关系进行调度。
  • nodeName:直接指定节点进行调度。
  • Pod 拓扑分布约束:确保 Pod 在集群中的均衡分布,增强高可用性。
  • 污点与容忍性:通过污点和容忍性控制哪些 Pod 可以调度到哪些节点。

通过合理组合这些调度策略,你可以优化 Pod 的资源分配、提升集群的可靠性和性能。



有缘相遇,不妨点个关注!


END


往期推荐


1

万字长文:K8S命令详解汇总【自用珍藏版】

2

安装部署K8S集群环境(实测有效版本)

3

K8S重要概念区分:Ingress 和 Service 的异同点

4

【Docker系列知识】常用命令大全汇总

5

部署Docker的三种常用方法【值得收藏】

6

Linux的150个常用命令汇总,运维大神不一定全部掌握!

运维李哥不背锅
专注于各种运维技术、,分享Linux基础知识,服务器,数据库,云原生和网络安全等相关技术,各种进阶知识等着你,助你成为技术达人!
 最新文章