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

文摘   2024-10-18 09:26   中国香港  
k8s集群节点CPU使用率高!内存OOM!宕机!导致大量微服务瘫痪怎么办?可能是调度策略没做好,看完这篇文章掌握提高集群稳定性的管理诀窍。

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


01

定向调度


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


  • nodeName

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

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

apiVersion: apps/v1kind: Deploymentmetadata:  name: athenaspec:  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/v1kind: Deploymentmetadata:  name: athenaspec:  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匹配)

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

02

亲和性调度


    亲和性调度(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/v1kind: Deploymentmetadata:  name: athenaspec:  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/v1kind: Deploymentmetadata:  name: athenaspec:  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亲和性和反亲和性的理解:

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

apiVersion: apps/v1kind: Deploymentmetadata:  name: athenaspec:  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

03

结 语

     

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

欢迎订阅我的公众号「SRE运维手记」,加交流群进公众号菜单栏


文章转载自SRE运维手记点击这里阅读原文了解更多


CNCF概况(幻灯片)

扫描二维码联系我们!




CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。 

CNCF云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。请关注CNCF微信公众号。

CNCF
云原生计算基金会(CNCF)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。
 最新文章