5-Pod调度方式

调度方式总结

  • 指定nodeName调度pod
  • 使用节点选择器(nodeSelector)调度pod
  • NodeAffinity:Node亲和性调度
  • Pod 亲和性/反亲和性(podAffinity/podAntiAffinity)调度策略
  • Taints和Tolerations:污点与容忍
  • 自定义调度器实现Pod调度

指定nodeName调度pod

  • 在pod.spec.nodeName字段指定节点名,该方法优先级最高
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: my-nginx
    image: nginx
  nodeName: node1

使用 nodeName 来选择节点的一些限制:
1.指定的节点可能不存在
2.指定的节点没有足够的资源来容纳 pod
3.云环境中的节点名称不固定

使用节点选择器(nodeSelector)调度pod

该方式由kube-scheduler进程负责实现Pod的调度

实现NodeSelector(定向调度)需要两步
1、使用kubectl label给node节点打标签
kubectl get nodes --show-labels        # 查看所有节点标签
kubectl get node node1 --show-labels   # 查看指定节点标签
kubectl label node node2 disktype=ssd  # 添加
kubectl label node node2 disktype-     # 删除标签

2、在pod.spec.nodeSelector字段指定节点标签名
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: my-nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd

如果给多个Node都定义了相同的标签,则scheduler会根据调度算法从这组Node中挑选一个可用的Node进行Pod调度
如果指定了Pod的nodeSelector条件,但是集群中不存在包含相应标签的Node,即使集群中还有其他可供使用的Node,这个Pod也无法被成功调度

NodeAffinity:Node亲和性调度

* 两种节点亲和性表达方式,由此项声明pod.spec.affinity.nodeAffinity
preferredDuringSchedulingIgnoreDuringExecution  倾向满足,多个优先级规则还可以设置权重(weight)值,以定义执行的先后顺序
requiredDuringSchedulingIgnoreDuringExecution   必须满足

* 实现NodeAffinity(Node亲和性调度)需要两步:
    * (1)通过kubectl label命令给目标Node打上一些标签。
        * kubectl label nodes <node-name> <label-key>=<label-value>
    * (2)在Pod的定义中加上nodeAffinity的设置。

* 使用规则
1.如果同时定义了nodeSelector和nodeAffinity, 那么必须两个条件都得到满足, Pod才能最终运行在指定的Node上。
2.如果在nodeAffinity指定了多个nodeSelectorTerms(指的是nodeSelectorTerms下面有多个matchExpressions),那么其中一个能够匹配成功即可。
3.如果在nodeSelectorTerms中指定了多个matchExpressions(指的是一个matchExpressions下面有多个key=value),则一个节点必须满足所有matchExpressions才能运行该Pod

* 字段的解释:
    * key:选择器应用于的标签键。
    * operator:表示一个键与一组值的关系。有效的操作符有In、NotIn、Exists、DoesNotExist、Gt和Lt。
        In:label的值在某个列表中
        NotIn:label的值不在某个列表中
        Gt:label的值大于某个值
        Lt:label的值小于某个值
        Exists:某个label存在
        DoesNotExist:某个label不存在
    * values:
        * 如果操作符是In或NotIn,值数组必须是非空的。
        * 如果操作符是Exists或DoesNotExist,则值数组必须为空。
        * 如果运算符是Gt或Lt,则值数组必须有一个元素,该元素将被解释为整数。
        * 虽然没有节点排斥功能,但是用NotIn和DoesNotExist就可以实现排斥的功能了。
    * weight:与对应的nodeSelectorTerm相匹配的权重,范围为1-100。

* 示例
设置NodeAffinity调度规则如下:
    * requiredDuringSchedulingIgnoredDuringExecution要求只运行在有label是node-name=node1的节点上。
    * preferredDuringSchedulingIgnoredDuringExecution的要求是尽量运行在label是disk=ssd的节点上。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-nginx-deployment3
  namespace: default
spec:
  selector:
    matchLabels:
      app: test-nginx-pod
  replicas: 2
  template:
    metadata:
      labels:
        app: test-nginx-pod
    spec:
      containers:
      - name: test-nginx-container
        image: nginx:latest
        imagePullPolicy: Never
        command: ["/usr/sbin/nginx", "-g", "daemon off;"]
        ports:
        - containerPort: 80
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: node-name
                operator: In
                values:
                - node1
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: disk
                operator: In
                values:
                - ssd

Pod 亲和性/反亲和性(podAffinity/podAntiAffinity)调度策略

1. 核心概念

  • Pod 亲和性(Affinity)与反亲和性(Anti-Affinity)用于控制 Pod 之间的调度关系,解决 Pod 应该或不应该与哪些 Pod 部署在同一个拓扑域中的问题。
  • Pod 亲和性 (PodAffinity):让 Pod 倾向于与符合条件的其他 Pod 部署在一起(例如:将 Web 服务和缓存服务部署在同一节点)。
  • Pod 反亲和性 (PodAntiAffinity):让 Pod 避免与符合条件的其他 Pod 部署在一起(例如:将同一个应用的多个副本分散在不同节点以实现高可用)。

2. 调度规则类型

  • 规则分为“硬性要求”和“软性倾向”两种,通过 pod.spec.affinity 字段配置。
  • 硬性要求 requiredDuringSchedulingIgnoredDuringExecution 必须满足。只有满足条件,Pod 才会被调度到该节点;否则 Pod 将处于 Pending 状态。
  • 软性倾向 preferredDuringSchedulingIgnoredDuringExecution 尽量满足。调度器会尝试满足条件,但如果无法满足,Pod 仍然会被调度。可为多个规则设置 weight(权重)来定义优先级。
  • IgnoredDuringExecution 的含义:无论是硬性还是软性规则,一旦 Pod 被成功调度并运行起来,即使后续集群状态发生变化导致规则不再满足,已运行的 Pod 也不会被驱逐或重新调度。

3. 实现原理与关键配置

  • 实现 Pod 亲和/反亲和性需要同时匹配两个条件:
    • 目标 Pod 的条件 (Y):通过 labelSelector 定义,用于找到集群中已经存在的、作为参照物的 Pod。
    • 拓扑域的范围 (X):通过 topologyKey 定义,用于指定在哪个范围内进行亲和或反亲和。
  • 调度逻辑: 如果在具有标签 X 的 Node 上,运行了一个或多个符合 labelSelector 条件 Y 的 Pod,那么新的 Pod 就应该(亲和)或拒绝(反亲和)被调度到这个 Node 上。

关键字段说明

  • topologyKey:节点的标签键(Key),代表一个拓扑域,如节点、机架、区域等。
    • kubernetes.io/hostname:表示单个节点。
    • topology.kubernetes.io/zone:表示一个可用区。
    • topology.kubernetes.io/region:表示一个地理区域。
  • 注意:failuredomain.beta.kubernetes.io/zone 和 failuredomain.beta.kubernetes.io/region 是已被废弃的旧标签。
  • labelSelector:一个标签选择器,用于匹配目标 Pod。
  • namespaces:一个命名空间列表,用于限定 labelSelector 的搜索范围。
  • 如果省略,则默认为定义亲和性规则的 Pod 所在的命名空间。
  • 如果设置为空字符串 "",则表示在所有命名空间中搜索。

4. topologyKey 配置规则与限制

  • topologyKey 是一个节点标签的键(Key)。Kubernetes 调度器会读取集群中所有节点的标签,根据这个键对应的值,把节点划分到不同的“拓扑域”中。有它指定的标签的节点,才有资格称为pod被调度的候选节点
  • 对于硬性要求(requiredDuringScheduling):topologyKey 不允许为空。
  • 如果集群启用了 LimitPodHardAntiAffinityTopology 准入控制器,那么 topologyKey 被强制限制为 kubernetes.io/hostname。若想使用自定义的 topologyKey,需要修改或禁用该控制器。
  • 如果 topologyKey 为空,它会被解释为 kubernetes.io/hostname、topology.kubernetes.io/zone 和 topology.kubernetes.io/region 的组合。

5. 操作符

  • 与节点亲和性类似,labelSelector 支持以下操作符:
    • In
    • NotIn
    • Exists
    • DoesNotExist
    • Gt (大于)
    • Lt (小于)
* 示例

# 如下是新建立的pod,这里使用的亲和标签是app=nginx-pod,该pod会被尽量调度到有相同标签的pod所在的节点上,topologyKey的值被设置为“kubernetes.io/hostname”
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: mysql-pod
spec:
  containers:
  - name: mysql
    image: mysql
  affinity:
    podAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
        - labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - nginx-pod
          topologyKey: kubernetes.io/hostname
          namespace: xxxxxx

# 如下是新建立的pod,这里使用的亲和标签是app=nginx-pod,该pod一定要调度到有相同标签的pod所在的节点上,topologyKey的值被设置为“kubernetes.io/hostname”
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx-pod
        topologyKey: kubernetes.io/hostname
        namespace: xxxxxxx

# 如下是新建立的pod,这里使用的互斥标签是app=nginx-pod,该pod会被尽量调度到有相同标签的pod所在的节点上,topologyKey的值被设置为“kubernetes.io/hostname”
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoreDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - pod-2
          topologyKey: kubernetes.io/hostname
          namespace: xxxxxxx

# 如下是新建立的pod,这里使用的互斥标签是app=nginx-pod,该pod不能调度到有相同标签的pod所在的节点上,topologyKey的值被设置为“kubernetes.io/hostname”
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx-pod
        topologyKey: kubernetes.io/hostname
        namespace: xxxxxxx

Taints和Tolerations:污点与容忍

  • Taint的作用是让Node拒绝Pod的在其上运行,除非Pod明确声明能够容忍这污点。

污点格式

key=value:effect

1.污点由一个key和value构成,value可以为空,effect描述污点的作用。
2.effect选项包括:
    NoSchedule:新pod不会被调度到具有该污点的Node上,如果node上已经有pod不会驱逐
    PreferNoSchedule:k8s尽量避免将pod调度到具有该污点的node上
    NoExecute:新pod不会被调度到具有该污点的Node上,如果node上已经有pod不会驱逐。除非pod有设置tolerations

操作污点

设置污点

  • Key 应表达"节点属性"而非"业务需求"
    • GPU 专用节点 hardware-type=gpu
    • 金融合规节点 compliance=pci-dss
    • 高内存节点 resource-tier=high-mem
kubectl taint node node名称 键名=键值:选项

# 在节点"k8s-node"添加污点,键为"dedicated",值为"special-user",效果为"NoSchedule"。
kubectl taint nodes k8s-node dedicated=special-user:NoSchedule

# 在标签有mylabel=X的节点上添加一个键为'dedicated'的污点
kubectl taint node -l myLabel=X  dedicated=foo:PreferNoSchedule

查看污点

  • 需要查看节点的说明,在其中查找taints字段
# 查看node01的污点
kubectl get nodes node01 -o go-template={{.spec.taints}}

# 或者
kubectl describe node node01 | grep -A 5 Taint

# 找到pod所在节点,再查找节点的污点
kubectl get node $(kubectl get pod <pod名称> -o jsonpath='{.spec.nodeName}') -o jsonpath='{.spec.taints}' | jq .

去除污点

kubectl taint node node名称 key:effect-(注意effect后的减号)(value可以省略)

# 从节点'k8s-node'中删除键为'dedicated'并效果为'NoSchedule'的污点(如果存在的话)
kubectl taint nodes k8s-node dedicated:NoSchedule-

# 从节点"k8s-node"中删除键为'dedicated'的所有污点
kubectl taint nodes k8s-node dedicated-

容忍(Tolerations)

  • 设置了容忍的pod将可以容忍污点的存在,可以被调度到存在污点的node上

实现容忍

  • tolerations的语法。kubectl explain pods.spec.tolerations可以查看结构
  • key:匹配污点键。空值配合 operator: Exists 可匹配所有键
  • value:匹配污点值
  • effect:匹配污点效果。可选值:NoSchedule、PreferNoSchedule、NoExecute。空值表示匹配所有效果
  • operator:可选值有Equal、Exists。如果不指定则默认值为Equal。此时需要key、value、effect完全相等。如果设置为Exists无需指定 value,key 和 effect 匹配即可。
  • tolerationSeconds:仅对 NoExecute 有效,指定容忍时间(秒)。未设置或负值视为永久容忍。
# pod可以在有污点key2=value1:NoExecute的节点上运行3600s。超时间会被驱逐。如果在此期间node的污点被移除,pod可以继续在node上运行
pod.spec.tolerations
tolerations:
- key: "key2"
  value: "value1"
  operator: "Equal"
  effect: "NoExecute"
  tolerationSeconds: 3600

# pod可以容忍节点上有键为key3,效果为NoSchedule的污点
tolerations:
- key: "key3"
  operator: "Exists"
  effect: "NoSchedule"
  • Master节点不参与调度是因为Master节点在创建时有以下污点:
    node-role.kubernetes.io/control-plane:NoSchedule
  • 有多个Master存在时,为防止资源浪费,可以设置如下污点:
    kubectl taint node node名称 node-role.kubernetes.io/master=:PreferNoSchedule

多个Taints和Tolerations的使用

  • 同一个Node可以设置多个Taint,同一个Pod也可以设置多个Toleration
  • Kubernetes调度器处理多个Taint和Toleration的逻辑顺序为:首先列出节点中所有的Taint,然后忽略Pod的Toleration能够匹配的部分,剩下的没有忽略的Taint就是对Pod的效果了。

自定义调度器实现Pod调度

  • 通过spec.schedulername参数指定调度器的名字,可以为pod选择my-scheduler进行调度,而不是默认的default-scheduler:
apiVersion: v1
kind: Pod
metadata:
  name: annotation-second-scheduler
  labels:
    name: multischeduler-example
spec:
  schedulername: my-scheduler
  containers:
  - name: pod-with-second-annotation-container
    image: gcr.io/google_containers/pause:2.0
posted @ 2024-05-10 10:13  立勋  阅读(20)  评论(0)    收藏  举报