Kubernetes 亲和性调度

栏目: 数据库 · 发布时间: 5年前

内容简介:前一篇文章Kubernetes 支持限制 Pod 在指定的 Node 上运行,或者指定更倾向于在某些特定 Node 上运行。有几种方式可以实现这个功能:

一、概述

前一篇文章 Kubernetes 调度器浅析 ,大致讲述了调度器的工作原理及相关调度策略。这一章会继续深入调度器,介绍下“亲和性调度”。

Kubernetes 支持限制 Pod 在指定的 Node 上运行,或者指定更倾向于在某些特定 Node 上运行。

有几种方式可以实现这个功能:

NodeName
NodeSelector
NodeAffinity
PodAffinity

二、NodeName

nodeName 是 PodSpec 的一个字段,用于直接指定调度节点,并运行该 pod。调度器在工作时,实际选择的是 nodeName 为空的 pod 并进行调度然后再回填该 nodeName,所以直接指定 nodeName 实际是直接跳过了调度器。换句话说,指定 nodeName 的方式是优于其他节点选择方法。

方法很简单,直接来个官方示例:

apiVersion: v1

kind: Pod

metadata:

  name: nginx

spec:

  containers:

  - name: nginx

    image: nginx

  nodeName: kube-01

当然如果选择的节点不存在,或者资源不足,那该 pod 必然就会运行失败。

三、NodeSelector

nodeSelector 也是 PodSpec 中的一个字段,指定键—值对的映射。

如果想要将 pod 运行到对应的 node 上,需要先给这些 node 打上 label,然后在 podSpec.NodeSelector 指定对应 node labels 即可。

步骤如下:

- 设置标签到 node 上:

kubectl label nodes kubernetes-node type=gpu

- pod 配置添加 nodeSelector 字段:

apiVersion: v1

kind: Pod

metadata:

  name: nginx

spec:

  containers:

  - name: nginx

    image: nginx

  nodeSelector:

    type: gpu

内置 Node 标签

1. Kubernetes 内置了一些节点标签:

  • kubernetes.io/hostname
  • beta.kubernetes.io/instance-type
  • beta.kubernetes.io/os
  • beta.kubernetes.io/arch
  • failure-domain.beta.kubernetes.io/zone
  • failure-domain.beta.kubernetes.io/region

有些标签是对云提供商使用。

  1. 还有些表示 node role 的 labels(可以指定 master、lb 等):

    • kubernetes.io/role
    • node-role.kubernetes.io

四、NodeAffinity

nodeSelector 通过 k-v 的方式非常简单的支持了 pod 调度限制到具有特定标签的节点上。而 nodeAffinity 根据亲和力 & 反亲和力极大地扩展了能够表达的约束信息。

nodeAffinity 特性的设计初衷就是为了替代 nodeSelector。

nodeAffinity 当前支持的匹配符号包括:In、NotIn、Exists、DoesNotExists、Gt、Lt 。

nodeAffinity 当前支持两种调度模式:

  • requiredDuringSchedulingIgnoredDuringExecution : 一定要满足的条件,如果没有找到满足条件的节点,则 Pod 创建失败。所有也称为 hard 模式
  • preferredDuringSchedulingIgnoredDuringExecution : 优先选择满足条件的节点,如果没有找到满足条件的节点,则在其他节点中择优创建 Pod。所有也称为 soft 模式

两种模式的名字特长,这是 k8s 的命名风格。其中 IgnoredDuringExecution 的意义就跟 nodeSelector 的实现一样,即使 node label 发生变更,也不会影响之前已经部署且又不满足 affinity rules 的 pods,这些 pods 还会继续在该 node 上运行。换句话说,亲和性选择节点仅在调度 Pod 时起作用。

k8s 社区正在计划提供 requiredDuringSchedulingRequiredDuringExecution 模式,便于驱逐 node 上不满足 affinity rules 的 pods。

来个官方示例,看下怎么玩:

apiVersion: v1

kind: Pod

metadata:

  name: with-node-affinity

spec:

  affinity:

    nodeAffinity:

      # 必须选择 node label key 为 kubernetes.io/e2e-az-name,

      # value 为 e2e-az1 或 e2e-az2.

      requiredDuringSchedulingIgnoredDuringExecution:

        nodeSelectorTerms:

        - matchExpressions:

          - key: kubernetes.io/e2e-az-name

            operator: In

            values:

            - e2e-az1

            - e2e-az2

      # 过滤掉上面的必选项后,再优先选择 node label key 为 another-node-label-key

      # value 为 another-node-label-value.

      preferredDuringSchedulingIgnoredDuringExecution:

      # 如果满足节点亲和,积分加权重(优选算法,会对 nodes 打分)

      # weight: 0 - 100

      - weight: 1

        preference:

          matchExpressions:

          - key: another-node-label-key

            operator: In

            values:

            - another-node-label-value

  containers:

  - name: with-node-affinity

    image: k8s.gcr.io/pause:2.0

简单看下 NodeAffinity 的结构体,下面介绍注意事项时会涉及:

type NodeAffinity struct {

RequiredDuringSchedulingIgnoredDuringExecution *NodeSelector

PreferredDuringSchedulingIgnoredDuringExecution []PreferredSchedulingTerm

}



type NodeSelector struct {

NodeSelectorTerms []NodeSelectorTerm

}



type NodeSelectorTerm struct {

MatchExpressions []NodeSelectorRequirement

MatchFields []NodeSelectorRequirement

}

配置相关的注意点:

  • 如果 nodeSelectornodeAffinity 两者都指定,那 node 需要两个条件都满足,pod 才能调度。
  • 如果指定了多个 NodeSelectorTerms ,那 node 只要满足其中一个条件,pod 就可以进行调度。
  • 如果指定了多个 MatchExpressions ,那必须要满足所有条件,才能将 pod 调度到该 node。

五、PodAffinity

nodeSelector & nodeAffinity 都是基于 node label 进行调度。而有时候我们希望调度的时候能考虑 pod 之间的关系,而不只是 pod 和 node 的关系。

举个例子,会有需求希望服务 A 和 B 部署在同一个机房、机架或机器上,因为这些服务可能会对网路延迟比较敏感,需要低延时;再比如,希望服务 C 和 D 又希望尽量分开部署,即使一台主机甚至一个机房出了问题,也不会导致两个服务一起挂而影响服务可用性,提升故障容灾的能力。

podAffinity 会基于节点上已经运行的 pod label 来约束新 pod 的调度。

其规则就是“如果 X 已经运行了一个或者多个符合规则 Y 的 Pod,那么这个 Pod 应该(如果是反亲和性,则是不应该)调度到 X 上”。

这里的 Y 是关联 namespace 的 labelSelector,当然 namespace 也可以是 all。和 node 不同,pod 是隶属于 namespace 下的资源,所以基于 pod labelSelector 必须指定具体的 namespace;而 X 则可以理解为一个拓扑域,类似于 node、rack、zone、cloud region 等等,就是前面提到的 内置 Node 标签 ,当然也可以自定义。

看下 pod affinity 涉及的结构体,便于进行功能介绍:

type Affinity struct {

// NodeAffinity 前面介绍了

NodeAffinity *NodeAffinity

// pod 亲和性

PodAffinity *PodAffinity

// pod 反亲和性

PodAntiAffinity *PodAntiAffinity

}



type PodAffinity struct {

// hard 模式, 必选项

RequiredDuringSchedulingIgnoredDuringExecution []PodAffinityTerm

// soft 模式, 进行 node 优先

PreferredDuringSchedulingIgnoredDuringExecution []WeightedPodAffinityTerm

}



type PodAffinityTerm struct {

LabelSelector *metav1.LabelSelector

Namespaces []string

TopologyKey string

}



type WeightedPodAffinityTerm struct {

Weight int32

PodAffinityTerm PodAffinityTerm

}

podAffinity 和 nodeAffinity 有相似的地方,使用了 labelSelector 进行匹配,支持的匹配符号包括:In、NotIn、Exists、DoesNotExists;

也支持两种调度模式 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution , 功能和 nodeAffinity 一样,这里就不在累述。

podAffinity 和 nodeAffinity 也有较大的差异,前面讲了 pod 是 namespace 资源,所以必然会需要配置 namespaces,支持配置多个 namespace。如果省略的话,默认为待调度 pod 所属的 namespace;如果定义了但是值为空,则表示使用 “all” namespaces。

还有一个较大的差别 TopologyKey , 便于理解进行单独介绍。

TopologyKey

TopologyKey 用于定义 in the same place ,前面也介绍了是 拓扑域 的概念。

看下面的图,这两个 pod 到底该如何算在一个拓扑域?

Kubernetes 亲和性调度

如果我们使用 k8s.io/hostnamein the same place 则意味着在同一个 node,那下图的 pods 就不在一个 place:

Kubernetes 亲和性调度

如果我们使用 failure-domain.k8s.io/zone 来表示一个 place,那下图的 pods 就表示在一个 zone:

Kubernetes 亲和性调度

当然我们也可以自定义 node labels 作为 TopologyKey。比如我们可以给一组 node 打上 rack 标签,那下图的 pods 表示在同一个 place:

Kubernetes 亲和性调度

原则上,topologyKey 可以是任何合法的 label key。但是出于性能和安全考虑,topologyKey 存在一些限制:

  • 对于亲和性和反亲和性的 requiredDuringSchedulingIgnoredDuringExecution 模式,topologyKey 不能为空
  • pod 反亲和性 requiredDuringSchedulingIgnoredDuringExecution 模式下, LimitPodHardAntiAffinityTopology 权限控制器会限制 topologyKey 只能设置为 kubernetes.io/hostname 。当然如果你想要使用自定义 topology,那可以简单禁用即可。
  • pod 反亲和性 preferredDuringSchedulingIgnoredDuringExecution 模式下,topologyKey 为空则表示所有的拓扑域。截止 v1.12 版本,所有的拓扑域还只能是 kubernetes.io/hostname , failure-domain.beta.kubernetes.io/zonefailure-domain.beta.kubernetes.io/region 的组合。
  • 除此之外,topologyKey 可以是任何合法的 label key。

示例

来个官方示例,有三节点集群,需要分别部署 3 份 web 和 redis 服务。希望 web 与 redis 服务共存,但需要保证各个服务的副本分散部署。

先创建 redis 集群:

apiVersion: apps/v1

kind: Deployment

metadata:

name: redis-cache

spec:

selector:

matchLabels:

  app: store

replicas: 3

template:

metadata:

  labels:

    app: store

spec:

  affinity:

    // pod 反亲和性, 打散 redis 各个副本

    podAntiAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchExpressions:

          - key: app

            operator: In

            values:

            - store

        topologyKey: "kubernetes.io/hostname"

  containers:

  - name: redis-server

    image: redis:3.2-alpine

再部署 web 服务,需要打散并且与 redis 服务共存,配置如下:

apiVersion: apps/v1

kind: Deployment

metadata:

name: web-server

spec:

selector:

matchLabels:

  app: web-store

replicas: 3

template:

metadata:

  labels:

    app: web-store

spec:

  affinity:

    podAntiAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchExpressions:

          - key: app

            operator: In

            values:

            - web-store

        topologyKey: "kubernetes.io/hostname"

    podAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchExpressions:

          - key: app

            operator: In

            values:

            - store

        topologyKey: "kubernetes.io/hostname"

  containers:

  - name: web-app

    image: nginx:1.12-alpine

注意1: pod affinity 需要进行大量处理,所以会明显减慢大型集群的调度时间,不建议在大于几百个节点的集群中使用该功能。

注意2: pod antiAffinity 要求对节点进行一致标志,即集群中的所有节点都必须具有适当的标签用于配置给 topologyKey,如果节点缺少指定的 topologyKey 指定的标签,则可能会导致意外行为。

六、参考资料

官方

- Assigning Pods to Nodes - Kubernetes

- node affinity

- pod affinity

- 性能优化: Improve performance of affinity/anti-affinity predicate by 20x in large clusters by bsalamat

blog

- Scheduling in Kubernetes, Part 2: Pod Affinity – Koki – Medium


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

云攻略

云攻略

马克·贝尼奥夫、卡莱尔·阿德勒 / 徐杰 / 海天出版社 / 2010年8月 / 36.00元

Apple、Google、甲骨文、腾讯 都已投入了云的怀抱, 你还在等什么? 快来加入我们! 最初,Salesforce.com 只是一间小小的租赁公寓 在短短10年内 它已成长为 世界上发展最快、最具创新力的 产业变革领导者 曾经,这是个软件为王的时代。 现在,这是个云计算的新时代。 NO SOFTWARE 抛弃软件的......一起来看看 《云攻略》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具