当前位置: 首页 > news >正文

第 37 篇 k8s之调度进阶:亲和性、污点与容忍

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。


在第 36 篇中,我们学会了用 Requests 和 Limits 控制 Pod 的资源使用,Scheduler 会依据资源请求自动将 Pod 调度到合适的节点。但资源充足只是调度的最低要求。在生产环境中,你往往需要更精细地决定 Pod 应该落在哪些节点上——比如,Redis 这类磁盘敏感的服务,能否强制调度到挂载了 SSD 的节点?多个 Flask 副本,能否让它们分布在不同的节点以避免单点故障?某些节点是否为 GPU 计算专用,普通业务 Pod 不得进入?

Docker Compose 完全不需要考虑这些问题,因为它只在一台机器上运行。而 Kubernetes 管理的是一个节点池,调度策略直接影响资源利用率、容灾能力和运维复杂度。今天这篇,我们就把 K8s 调度的三大利器——亲和性、污点与容忍——彻底搞懂,并将它们应用到贯穿案例的 Flask + Redis 应用中。

一、节点亲和性(Node Affinity):吸引 Pod 到指定节点

1.1 为什么需要节点亲和性?

默认情况下,Scheduler 会根据 Requests 与节点的可分配资源进行匹配,Pod 可能落在任何符合条件的节点上。但如果你需要“让 Redis 始终使用 SSD 磁盘的节点”,或者“让某些服务只在指定的 GPU 节点上运行”,就需要节点亲和性

节点亲和性像是一种吸引力规则——节点上带有特定的标签,Pod 则通过affinity声明“我喜欢带有这些标签的节点”。

1.2 节点标签

首先,你需要给节点打上标签:

kubectl labelnodeminikubedisktype=ssd

查看标签:

kubectl getnodeminikube --show-labels# NAME STATUS ROLES AGE VERSION LABELS# minikube Ready control-plane 1d v1.31.0 ...,disktype=ssd

1.3 硬亲和(required)与软亲和(preferred)

节点亲和性分为两种:

  • requiredDuringSchedulingIgnoredDuringExecution(硬亲和):必须满足。如果没有任何节点符合条件,Pod 将无法调度,一直处于 Pending。

  • preferredDuringSchedulingIgnoredDuringExecution(软亲和):倾向满足。Scheduler 会优先调度到符合条件的节点,但如果没有,也可以落在其他节点上。

两者的名字中都有IgnoredDuringExecution,意思是“一旦 Pod 已经运行,节点标签的变化不会驱逐正在运行的 Pod”。如果需要在标签变化时强制驱逐,需要更复杂的机制(如自定义控制器)。

1.4 示例:将 Redis 强制调度到 SSD 节点

apiVersion: v1 kind: Pod metadata: name: redis-ssd spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssd containers: - name: redis image: redis:alpine

解释:

  • matchExpressions:可以有多个条件,它们之间是 AND 关系。

  • operator: In:标签的值必须在values列表中。还有NotInExistsDoesNotExistGt(大于)、Lt(小于)等。

  • 如果 Minikube 只有单节点并已打上disktype=ssd,Pod 会正常调度。

部署后查看调度:

kubectl get pod redis-ssd-owide# NAME READY STATUS RESTARTS AGE IP NODE# redis-ssd 1/1 Running 0 10s 10.244.1.15 minikube

如果没有匹配节点,Pod 会 Pending:

kubectl describe pod redis-ssd|grep-A5Events# Warning FailedScheduling ... 0/1 nodes are available: 1 node(s) didn't match node selector.

1.5 软亲和示例

preferredDuringSchedulingIgnoredDuringExecution: - weight:100preference: matchExpressions: - key: disktype operator: In values: - ssd

weight是权重(1-100),Scheduler 会根据权重对节点打分。如果集群中有多个节点,权重越高的条件越优先被满足。

二、Pod 亲和性与反亲和性(Pod Affinity/Anti-affinity):Pod 之间的拓扑关系

2.1 什么是 Pod 亲和性?

节点亲和性解决了“Pod 与节点的关系”,但实际中更常见的是“Pod 与 Pod 的关系”。例如:

  • Pod 亲和性:把 Web 应用调度到缓存所在节点的附近,降低延迟。

  • Pod 反亲和性:将同一服务的多个副本分散到不同节点上,避免单节点故障导致服务全部不可用。

Pod 亲和性与反亲和性通过podAffinitypodAntiAffinity实现,规则基于 Pod 的标签,并且可以根据拓扑域(topologyKey)来控制亲和性的粒度。常见的topologyKeykubernetes.io/hostname(节点级别)、topology.kubernetes.io/zone(可用区级别)。

2.2 示例:让 Flask 靠近 Redis(Pod 亲和性)

假设你有一个 Redis Pod 带着标签app=redis,你希望 Flask Pod 尽量与它在同一个节点上。

首先创建 Redis Pod 并打标签(如果还未创建):

kubectl run redis--image=redis:alpine--labels=app=redis

现在创建一个 Flask Deployment,声明 Pod 亲和性:

apiVersion: apps/v1 kind: Deployment metadata: name: flask-affinity spec: replicas:2selector: matchLabels: app: flask-counter template: metadata: labels: app: flask-counter spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - redis topologyKey: kubernetes.io/hostname containers: - name: flask image: flask-redis-counter:3.0 ports: - containerPort:5000

这里requiredDuringSchedulingIgnoredDuringExecution要求 Flask Pod 必须与拥有标签app=redis的 Pod 调度在同一个hostname上。如果 Redis Pod 不存在或没有相同拓扑的节点,Flask Pod 无法调度。

在 Minikube 单节点中,这始终成立。在多节点集群中,你会看到 Flask Pod 被拉到 Redis 所在的节点。

2.3 示例:让 Flask 副本分散部署(Pod 反亲和性)

为了高可用,我们希望多个 Flask 副本不要挤在同一个节点上。使用 Pod 反亲和性:

affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - flask-counter topologyKey: kubernetes.io/hostname

这段配置要求:如果某节点上已存在带有app=flask-counter标签的 Pod,则新 Pod 不能再调度到同一hostname上。这就强制了每个节点最多只运行一个副本

  • 优点:彻底的故障隔离,一个节点宕机只会影响一个副本。

  • 缺点:如果你的副本数超过节点数,多余的 Pod 将无法调度,处于 Pending 状态。此时应考虑使用软反亲和性(preferredDuringSchedulingIgnoredDuringExecution),允许在必要时放宽限制。

2.4 topologyKey 的选择

  • kubernetes.io/hostname:节点级分布。

  • topology.kubernetes.io/zone:可用区级分布(需要云平台支持),防止整个可用区故障。

  • 自定义标签:如rackfailure-domain

在多副本有状态应用(如数据库集群)中,反亲和性结合topologyKey: hostname可以确保每个副本都独占一个节点,避免资源竞争和单点故障。

三、污点与容忍(Taints and Tolerations):排斥与准入

3.1 污点的概念

如果说亲和性是“吸引”,那么污点就是“排斥”。节点上的污点(Taint)会阻止没有相应容忍(Toleration)的 Pod 被调度到该节点上,甚至驱逐已在运行的 Pod。

污点有三个要素:keyvalueeffect

effect有三种:

  • NoSchedule:不调度新的 Pod,但不影响已在运行的 Pod。

  • PreferNoSchedule:尽量不调度新的 Pod,但不强制。

  • NoExecute:不仅不调度新的 Pod,还会驱逐已经运行的、没有相应容忍的 Pod。

3.2 给节点添加污点

# 给节点 minikube 添加污点:专用 GPUkubectl taintnodeminikubegpu=true:NoSchedule

查看污点:

kubectl describenodeminikube|grepTaints# Taints: gpu=true:NoSchedule

现在,普通 Pod 将无法调度到这个节点上(除非它们有容忍)。这可以用来保护专用节点。

3.3 Pod 容忍污点

如果想让某个 Pod 能够调度到有污点的节点,需要在 Pod 中配置容忍:

tolerations: - key:"gpu"operator:"Equal"value:"true"effect:"NoSchedule"

你也可以容忍所有污点:

tolerations: - operator:"Exists"

但谨慎使用,可能让 Pod 跑到不合适的节点上。

3.4 污点的典型场景

  • GPU 专用节点:给节点打上gpu=true:NoSchedule,只有请求了 GPU 资源的 Pod 配置了对应容忍。

  • 控制平面隔离:默认 master 节点有污点node-role.kubernetes.io/control-plane:NoSchedule,防止普通业务 Pod 调度上去。

  • 节点维护:在维护前给节点添加NoExecute污点,Pod 会自动被驱逐迁移。

3.5 移除污点

kubectl taintnodeminikubegpu=true:NoSchedule-

注意末尾的-表示移除污点。

四、实战:为 Flask + Redis 配置调度策略

现在将亲和性和反亲和性应用到贯穿案例中。我们需要:

  • 确保 Redis 调度到有标签tier=backend的节点(节点亲和性)。

  • 确保 Flask 副本尽量与 Redis 在同一可用区(Pod 亲和性),但副本之间要分散在节点上(Pod 反亲和性)。

  • 为 Redis 节点添加污点,只允许 Redis 类 Pod 调度(可选)。

4.1 准备节点

Minikube 单节点做不了完整的多节点演示,但我们可以练习配置。先给节点加标签和污点(用于学习,不要影响其他 Pod,可使用PreferNoSchedule)。

kubectl labelnodeminikubetier=backend kubectl taintnodeminikubetier=backend:PreferNoSchedule

4.2 创建 Redis Deployment 带节点亲和性和容忍

apiVersion: apps/v1 kind: Deployment metadata: name: redis-backend spec: replicas:1selector: matchLabels: app: redis tier: backend template: metadata: labels: app: redis tier: backend spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: tier operator: In values: - backend tolerations: - key:"tier"operator:"Equal"value:"backend"effect:"PreferNoSchedule"containers: - name: redis image: redis:alpine

4.3 创建 Flask Deployment 带 Pod 亲和性和反亲和性

apiVersion: apps/v1 kind: Deployment metadata: name: flask-backend spec: replicas:3selector: matchLabels: app: flask-counter template: metadata: labels: app: flask-counter spec: affinity:# 亲和性:靠近 RedispodAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight:100podAffinityTerm: labelSelector: matchExpressions: - key: tier operator: In values: - backend topologyKey: kubernetes.io/hostname# 反亲和性:副本分散podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight:100podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - flask-counter topologyKey: kubernetes.io/hostname containers: - name: flask image: flask-redis-counter:3.0 ports: - containerPort:5000resources: requests: cpu:"100m"memory:"128Mi"limits: cpu:"500m"memory:"256Mi"

我们使用了preferredDuringSchedulingIgnoredDuringExecution(软亲和)来避免单节点环境中因为满足不了硬条件而无法调度。在生产多节点环境中,可以切换为required

部署后查看 Pod 分布(单节点全部在 minikube):

4.4 验证亲和性和容忍效果

检查事件,确认调度器考虑了亲和性:

kubectl describe pod<flask-pod>|grep-A5"Affinity"

由于 Minikube 单节点,我们难以看到分散效果,但配置可以无缝迁移到多节点集群。

4.5 清理污点

kubectl taintnodeminikubetier=backend:PreferNoSchedule-

五、与 Docker Compose 的对比

Compose 没有调度概念,所有容器都在同一台宿主机上,你可以通过depends_on控制启动顺序,但不能控制容器在主机内的分布(单机不存在分布问题)。K8s 的亲和性和污点机制为多节点集群提供了细粒度的调度控制,这是编排平台走向大规模生产的必然需求。

六、命令速查表

七、本篇总结

  • 节点亲和性:通过nodeAffinity将 Pod 调度到带有特定标签的节点上,支持硬性和软性两种策略。

  • Pod 亲和性与反亲和性:通过podAffinitypodAntiAffinity控制 Pod 之间的拓扑关系,实现拉近或分散部署,提高性能或可用性。

  • 污点与容忍:通过TaintToleration实现节点的专属访问控制,防止无关 Pod 调度,支持NoSchedulePreferNoScheduleNoExecute效果。

  • 调度策略的实际价值:合理的亲和性和反亲和性配置是实现高可用部署、资源隔离和性能优化的关键手段,也是 K8s 集群运维中常被忽略的细节。

通过本篇,你获得了控制 Pod 落点的完整工具集。下一篇文章——第 38 篇:安全:RBAC 与 ServiceAccount 实战——我们将进入 K8s 安全领域,学习如何通过基于角色的访问控制来保护集群资源。

想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !

http://www.jsqmd.com/news/945839/

相关文章:

  • 鸿蒙生态日益完善:头部应用全适配,日常使用无忧
  • 小程序毕业设计-基于springboot+微信小程序的企业网络主机IP地址管理系统(源码+LW+部署文档+全bao+远程调试+代码讲解等)
  • 智标宝深度评测:AI大模型在招投标场景的技术落地实践
  • 新手零压力:用快马生成交互式jupyter notebook轻松学python
  • 2026北京配眼镜推荐,到底怎么选,五家门店从验光到取镜全看 - 配眼镜新资讯
  • 零代码实战:用Coze打造“绝不瞎编”的课程客服智能体
  • 说明书公开不充分?你的专利可能白申请了
  • 2026年四向穿梭式货架生产厂排名,哪家性价比高? - 工业品牌热点
  • OA审批流开发避坑指南:从‘待我审批’查询到事务提交的五个实战细节
  • VoLTE通话失败别抓瞎:手把手教你用拆线原因代码定位问题(附常见场景排查)
  • 3分钟快速上手:通达信缠论可视化插件的终极指南
  • 从游戏AI到工业控制:深入浅出对比DQN、DDQN与Dueling DQN的实战选择
  • ai辅助开发:让kimi等模型在快马平台为你自动编写和解释matlab代码
  • GitHub加速插件:5分钟解决国内访问缓慢的完整方案
  • 从芯片手册到手上模块:手把手拆解SX1308升压电路,看懂每个元件的作用
  • 第 38 篇 k8s之RBAC 与 ServiceAccount 实战
  • 小程序毕业设计-基于微信小程序的旅游景点服务小程序基于springboot+微信小程序的旅游景点导览APP的设计与实现小程序(源码+LW+部署文档+全bao+远程调试+代码讲解等)
  • 树莓派新手避坑指南:wpa_supplicant.conf文件配置详解与SSH连接全流程
  • 业内口碑不错的4J36低膨胀合金厂商有哪些?这份清单请收好 - 品牌2026
  • 别再死记硬背了!用Python+SciPy快速求解热传导与优化问题(以国赛A题为例)
  • 2026优选:浙江区域独立站定制服务商实力排行 - 奔跑123
  • 三步获取阿里云盘Refresh Token:轻松实现自动化管理的完整指南
  • 告别龟速下载!保姆级教程:为Windows上的MSYS2配置清华/阿里云镜像源
  • 靠谱的运动木地板安装施工队,你选对了吗? - 工业品牌热点
  • 【AI模型监控黄金标准】:20年SRE专家亲授5大必控指标与实时告警闭环实践
  • 一件硬通货,拍出不俗身价
  • 腾讯云快直播浏览器推流深度解析:从 WebRTC 原理到 480p 落地方案
  • 如何快速实现文本差异比对:JavaScript开发者的完整指南
  • 2026北京配眼镜推荐,高性价比去哪些店,五家精选各有侧重 - 配眼镜新资讯
  • 从“各自为战”到“万物互联”:GB28181国标视频监控行业正在经历的三场革命