K8s 容器的定向调度与亲和性

K8s 集群节点 CPU 使用率高!内存溢出(OOM)!宕机!导致大量微服务瘫痪怎么办?可能是调度策略没做好,看完这篇文章掌握提高集群稳定性的管理诀窍。

Kubernetes(K8s)是一个开源的容器编排工具,而容器调度是其非常重要的特性,所谓的调度是指将容器(Pod)分配到集群中的节点上运行的过程。为了更好地控制容器的调度,K8s 提供了多种调度策略,其中包括定向调度和亲和性策略。在实际的 K8s 集群维护场景中,合理使用这些调度策略,对集群的稳定性至关重要。本文将通过分享实践案例,帮助你更好地理解和使用这些功能。

定向调度

定向调度通过 nodeNamenodeSelector 来声明 Pod 期望调度的目标节点,这种方式的调度是强制性的,不管节点是否存在,是否宕机,都会往声明的节点上去调度,当目标不存在或不可调度时,将会导致 Pod 无法运行。

  • nodeName

强制将 Pod 调度到指定主机名的节点上,这种方式简单粗暴,没有经过 Scheduler 的调度逻辑。

示例:我有一个机器学习的应用,需要调度到集群中唯一的 GPU 节点上,可以这样做。

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: athena
spec:
  replicas: 1
  selector:
    matchLabels:
      app: athena
  template:
    metadata:
      labels:
        app: athena
    spec:
      containers:
      - name: athena
        image: athena:2.0.0
      nodeName: k8s-node-gpu-1
  • NodeSelector

强制将 Pod 调度到指定标签的节点上,这种方式通过 Label-selector 机制实现,在 Pod 创建之前,会由 Schedule 的 MatchNodeSelector 调度策略根据 Label 匹配节点,再将 Pod 调度到目标节点上。

示例:我有一个机器学习的应用,需要调度到集群中带有 hardware-type:gpu 标签的节点上,带有该标签的节点有多台,可以这样做。

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: athena
spec:
  replicas: 1
  selector:
    matchLabels:
      app: athena
  template:
    metadata:
      labels:
        app: athena
    spec:
      containers:
      - name: athena
        image: athena:2.0.0
      nodeSelector:
        hardware-type: gpu
        # gpu-type: T4 (允许有多label匹配)

定向调度比较简单粗暴,那有没有相对温和、灵活点的调度策略呢?当然是有的,接下来让我们来看看亲和性调度策略。

亲和性调度

亲和性调度(Affinity)在定向调度的基础上,通过灵活的节点亲和性(nodeAffinity)、Pod 亲和性(podAffinity)、Pod 反亲和性(podAntiAffinity)规则,满足更多样化的调度场景。

  • nodeAffinity

nodeSelector 更加强大和灵活,可以让 Pod 满足更多样化的条件调度到指定的节点上,支持"软性调度"(PreferredDuringSchedulingIgnoreDuringExecution)和"硬性调度"(RequiredDuringSchedulingIgnoredDuringExecution)",硬性调度比较强硬,不满足条件则调度不成功,而软性调度相对温和,属于倾向性优先选择满足条件的节点,并不强求。

让我们来看两个示例,加深理解:

示例 1:我有一个机器学习的应用,必须调度到集群中带有 hardware-type: gpu,且区域 kubernetes.io/zone 的值为 cn-shenzhen-1 或 cn-shenzhen-2 标签的节点上。我们可以通过亲和性的硬性调度实现,具体如下:

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: athena
spec:
  replicas: 2
  selector:
    matchLabels:
      app: athena
  template:
    metadata:
      labels:
        app: athena
    spec:
      containers:
      - name: athena
        image: athena:2.0.0
      affinity:
        nodeAffinity:
          # 硬性调度,节点必须满足所有条件才可以调度
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: hardware-type
                # 运算
                operator: In
                values:
                - gpu
              - key: kubernetes.io/zone
                operator: In
                values:
                - cn-shenzhen-1
                - cn-shenzhen-2

Operator 支持的运算符还有:

复制代码
Exists(key必须存在,value可以是任意的)
DoesNotExist(key不能存在)
In(key的value必须在提供的值列表中)
NotIn(key的value不能在提供的值列表中)
Gt(key的value必须大于提供的值,仅支持整数)
Lt(key的value必须小于提供的值)

示例 2:我有一个机器学习的应用,倾向于调度到集群中带有 hardware-type: gpu,且区域 kubernetes.io/zone 的值为 cn-shenzhen-1 或 cn-shenzhen-2 标签的节点上。我们可以通过亲和性的软性调度实现,如果不能满足条件,他也会尝试去调度其他节点,具体如下:

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: athena
spec:
  replicas: 2
  selector:
    matchLabels:
      app: athena
  template:
    metadata:
      labels:
        app: athena
    spec:
      containers:
      - name: athena
        image: athena:2.0.0
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          # 满足条件的节点会加分,值支持(1-100),分数越高,优先级越高
          # 不加的话,满足条件的节点权重也为0,不能保证其优先级。
          - weight: 1
            preference:
              matchExpressions:
              - key: hardware-type
                # 运算,支持的运算符跟硬性调度一致
                operator: In
                values:
                - gpu
              - key: kubernetes.io/zone
                operator: In
                values:
                - cn-shenzhen-1
                - cn-shenzhen-2
  • Pod 亲和性(podAffinity)和反亲和性(podAntiAffinity)

顾名思义,Pod 亲和性用来指定哪些 Pod 应该跟哪些 Pod 更加靠近,而 Pod 反亲和性通常用来打散 Pod,让某些 Pod 不在同一节点或区域,同样也有"软性调度"(PreferredDuringSchedulingIgnoreDuringExecution)"和"硬性调度" (RequiredDuringSchedulingIgnoredDuringExecution),接下来我将用一个示例,加深对 Pod 亲和性和反亲和性的理解:

示例:有两个微服务 zeusathena 相互调用比较频繁,他们都有两个副本,出于提升效率和可用性考虑,我想将 zeus 和 athena 的副本打散到两个不同的可用区(zone),并让他们的副本必须部署到同一个节点上,假设 zeus 已经部署好了,那 athena 的部署可以这样实现。

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: athena
spec:
  replicas: 2
  selector:
    matchLabels:
      app: athena
  template:
    metadata:
      labels:
        app: athena
    spec:
      containers:
      - name: athena
        image: athena:2.0.0
      affinity:
        # Pod亲和性
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                app: zeus
            # 拓扑键,表示在相同主机上调度
            topologyKey: kubernetes.io/hostname
        # Pod反亲和性
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                app: athena
            # 拓扑键,表示在不同区域上调度
            topologyKey: topology.kubernetes.io/zone

结 语

在文章开头我们提到如何借助调度策略来提升 K8s 集群的可用性,相信看完全文的小伙伴都可以悟出其中奥妙,我们可以将高计算、高内存的 Pod 调度到指定的节点,避免影响关键服务运行,另外为了保障微服务的高可用性,我们通常会打散副本到不同的节点或者可用区。

本文首发:SRE运维手记,作者:亦零一。

本文由博客一文多发平台 OpenWrite 发布!

相关推荐
小仓桑9 小时前
【Agent智能体项目实战一】阿里云通义千问兼容 OpenAI 接口实现 AI 对话
人工智能·阿里云·云计算·agent
AI周红伟10 小时前
周红伟:豆包大模型的尽头是直播间,豆包开启AI购物内测 电商平台加码“一句话购物”
人工智能·阿里云·云计算·腾讯云·openclaw
威联通安全存储10 小时前
某大型食品饮料企业:基于威联通 TS-h1290FX 的中央数据管控与合规实践
大数据·人工智能·云计算
大树8811 小时前
国产液冷产业链的突破:应对龙虾大模型等终端算力需求激增的倒逼效应
科技·ai·云计算
未来之窗软件服务13 小时前
阿里云 page-agent 核心逻辑梳理[AI人工智能(六十一)]—东方仙盟
人工智能·阿里云·云计算·仙盟创梦ide·东方仙盟
武汉唯众智创13 小时前
云计算大数据实训平台:从私有云到容器化的教学实现|原理+实操+踩坑+性能全解析
大数据·人工智能·云计算·云计算实训室·大数据实训室·职校云计算大数据实训室建设·职校实训室建设
不吃香菜kkk、15 小时前
夜莺n9e+监控K8s集群+自定义监控页面
运维·云原生·云计算
张彦峰ZYF16 小时前
阿里云云计算ACA - ACP认证考试模拟试卷二
阿里云·云计算·aca - acp
柯儿的天空16 小时前
【OpenClaw 全面解析:从零到精通】第 014 篇:OpenClaw 云端部署实战——阿里云、腾讯云与 Docker 部署全指南
人工智能·阿里云·docker·云计算·aigc·腾讯云·ai写作
魔极客16 小时前
阿里云免费额度用完即停设置指南
数据库·阿里云·云计算