Kubernetes Pod 调度实战:nodeSelector、亲和性与 taint/toleration 把 Pod 放到指定节点

Kubernetes Pod 调度实战:nodeSelector、亲和性与 taint/toleration 把 Pod 放到指定节点

集群里混着 GPU 节点、普通节点、还有几台专供网关的机器。你部署了个训练任务,结果它被调度到了普通节点上,GPU 节点空着;或者你想让某几台机器只跑核心服务,别人的测试 Pod 却一直往上挤。

这些都是调度控制没配好。这篇把 Kubernetes 控制 Pod 落到哪个节点的三套机制讲透:nodeSelector、亲和性(affinity)、污点与容忍(taint/toleration),并说清楚它们各自解决什么问题、什么时候该用哪个。

先看默认行为:调度器凭什么选节点

不加任何约束时,kube-scheduler 会过滤掉资源不够的节点,再按打分选最优的。你无法控制它偏好哪台机器。要干预,就得给节点打标签、给 Pod 加约束。

先给节点打标签,这是所有调度控制的基础:

bash 复制代码
# 标记 GPU 节点
kubectl label nodes node-gpu-01 hardware=gpu
# 标记专供网关的节点
kubectl label nodes node-gw-01 role=gateway

# 查看节点标签
kubectl get nodes --show-labels

nodeSelector:最简单的硬性指定

nodeSelector 是最直白的方式:Pod 只会调度到带指定标签的节点上。

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: gpu-trainer
spec:
  nodeSelector:
    hardware: gpu   # 只往带 hardware=gpu 标签的节点上放
  containers:
  - name: trainer
    image: my-trainer:latest

它的局限也很明显:只能做等值匹配、多个条件是「与」关系、没有软约束(找不到符合的节点 Pod 就一直 Pending)。稍微复杂点的需求它就不够用了,这时候上亲和性。

nodeAffinity:带「或」和「软偏好」的节点选择

节点亲和性比 nodeSelector 强在两点:支持 In/NotIn/Exists 等操作符(能表达「或」),以及区分硬约束软偏好

  • requiredDuringSchedulingIgnoredDuringExecution:硬约束,不满足不调度。
  • preferredDuringSchedulingIgnoredDuringExecution:软偏好,满足最好,不满足也能调度到别处。
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels: { app: web }
  template:
    metadata:
      labels: { app: web }
    spec:
      affinity:
        nodeAffinity:
          # 硬约束:必须落在 ssd 或 nvme 磁盘的节点
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: disktype
                operator: In
                values: ["ssd", "nvme"]   # In 表达「或」
          # 软偏好:优先华东可用区,不满足也认
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            preference:
              matchExpressions:
              - key: zone
                operator: In
                values: ["east-1"]

那串长得吓人的字段名其实在说一件事:IgnoredDuringExecution 表示「只在调度那一刻检查,Pod 跑起来后就算节点标签变了也不驱逐」。目前所有 affinity 都是这个行为,记住这点就不会被字段名劝退。

podAffinity / podAntiAffinity:让 Pod 靠近或远离彼此

上面控制的是「Pod 和节点」的关系。有时你要控制的是「Pod 和 Pod」的关系:比如把同一服务的多个副本打散 到不同节点(避免单节点故障全挂),或者把 Web 和它的缓存放到一起(降低网络延迟)。

打散副本用 podAntiAffinity:

yaml 复制代码
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels: { app: web }
            # topologyKey 是打散的粒度:按主机名打散 = 每个节点最多一个
            topologyKey: kubernetes.io/hostname

topologyKey 是关键:它定义「什么算同一个拓扑域」。用 kubernetes.io/hostname 表示每台机器是一个域,于是同一个 app: web 的 Pod 不会有两个落在同一节点。换成 topology.kubernetes.io/zone 就是按可用区打散。

要注意用 required(硬打散)时,如果副本数超过节点数,多出来的 Pod 会一直 Pending------因为找不到没有 web Pod 的节点了。副本多、节点少的场景改用 preferred 软打散更稳妥。

taint/toleration:让节点「排斥」Pod,反向控制

前面几种是 Pod 主动挑节点。污点(taint)是反过来的:节点主动排斥 Pod,除非 Pod 明确声明能容忍这个污点。

典型场景:一台专供网关的机器,不想让普通业务 Pod 挤上来。给它打污点:

bash 复制代码
# 给节点打污点,effect=NoSchedule 表示不容忍就别调度过来
kubectl taint nodes node-gw-01 dedicated=gateway:NoSchedule

打完之后,除非 Pod 显式容忍,否则调度器不会把它放到这台机器。只有网关服务加上对应的 toleration:

yaml 复制代码
spec:
  tolerations:
  - key: dedicated
    operator: Equal
    value: gateway
    effect: NoSchedule   # 要和污点的 effect 对上
  containers:
  - name: gateway
    image: nginx:latest

effect 有三种,行为差别很大:

  • NoSchedule:不容忍的新 Pod 不调度过来,已经在跑的不动。
  • PreferNoSchedule:尽量不调度过来,但没别的节点时还是会来(软版本)。
  • NoExecute:不容忍的连已经在跑的都会被驱逐 。K8s 给节点标记 node.kubernetes.io/not-ready 时用的就是这个,所以节点 NotReady 一段时间后上面的 Pod 会被赶走重调度。

关键区分:toleration 只是「允许」,不是「指定」

这是最容易搞混的地方。给 Pod 加 toleration,只是让它有资格上带污点的节点,并不保证它一定去那儿。它照样可能被调度到其他没污点的普通节点。

如果你既要「别人上不来」又要「网关服务一定上去」,得两个机制配合:节点打污点(挡住别人)+ 网关 Pod 同时配 toleration(有资格上)+ nodeAffinity 或 nodeSelector(指定必须上这台)。三者缺一,效果就会打折。

yaml 复制代码
spec:
  # 1. 容忍污点:有资格上网关节点
  tolerations:
  - key: dedicated
    operator: Equal
    value: gateway
    effect: NoSchedule
  # 2. 亲和指定:必须上带 role=gateway 标签的节点
  nodeSelector:
    role: gateway

小结

  • nodeSelector:硬性等值匹配,最简单,只够简单场景。
  • nodeAffinity:支持「或」和软偏好(required vs preferred),控制 Pod 落到哪类节点。
  • podAffinity / podAntiAffinity :控制 Pod 之间靠近或打散,topologyKey 决定打散粒度。
  • taint/toleration :节点反向排斥 Pod,NoExecute 会驱逐已运行的 Pod;toleration 只给「资格」不给「指定」。
  • 专用节点要「污点挡别人 + toleration 给资格 + affinity 定去向」三件套配合。

一句话记忆:affinity 是 Pod 挑节点,taint 是节点挑 Pod,toleration 只是入场券不是指定席。

相关推荐
qetfw1 小时前
CentOS 7 vsftpd.conf 配置文件详解:监听、用户、权限、被动模式与 TLS
linux·运维·centos·ftp·vsftpd
念何架构之路1 小时前
moby-BuildKit(builder-next)
学习·docker·容器
风曦Kisaki1 小时前
Kubernetes(K8s)笔记Day04:控制器(ReplicaSet 与Deployment),滚动更新及回滚,滚动更新策略,Pod 的 DNS 策略
linux·运维·笔记·docker·容器·kubernetes
薛定e的猫咪1 小时前
零基础选型指南:Make / 扣子 Coze/n8n/Dify 四大自动化平台完整对比
运维·自动化
张忠琳1 小时前
【NVIDIA】k8s-device-plugin v0.19.3 辅助命令模块深度分析之七
云原生·容器·架构·kubernetes·nvidia
Huangjin007_1 小时前
【Linux 系统篇(十)】基础开发工具(五) —— 第一个系统程序 - 进度条
linux·运维·服务器
MetrixAeroCore2 小时前
出海餐厅手持POS机物联网卡:多币种计费稳定传输与跨境税务合规对接方案
运维
路由侠内网穿透.2 小时前
本地部署开源日志收集系统 Log Bull 并实现外部访问
运维·服务器·网络·数据库·开源
时空无限2 小时前
linux mellanox 网卡队列 irq rps 相关
linux·运维