kubernetes亲和性和反亲和性——<13>

本文介绍Kubernetes中Pod调度的核心概念,包括nodeSelector、节点亲和性与反亲和性及Pod间的亲和性与反亲和性。通过具体配置示例解释如何利用这些策略优化部署。

一、nodeSelector

nodeSelector 提供了一个非常简单的方式,将 Pod 限定到包含特定标签的节点上。
亲和性与反亲和性(affinity / anti-affinity)特性则极大地扩展了限定的表达方式。主要的增强点在于:

a、表达方式更加有效(不仅仅是多个精确匹配表达式的“和”关系)
b、可以标识该规则为“soft” / “preference” (软性的、偏好的)而不是 hard requirement(必须的),此时,
如果调度器发现该规则不能被满足,Pod 仍然可以被调度
c、可以对比节点上(或其他拓扑域 topological domain)已运行的其他 Pod 的标签,而不仅仅是节点自己的标签,
此时,可以定义类似这样的规则:某两类 Pod 不能在同一个节点(或拓扑域)上共存

nodeSelector使用范例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
  labels:
    app: test-app
  namespace: default
spec:
  selector:
    matchLabels:
      app: test-app
  replicas: 1
  template:
    metadata:
      labels:
        app: test-app
    spec:
      nodeSelector:
        type: k8s-node02
      containers:
      - name: test-app
        image: xx.xx.xxx.xxx/test-app/test-app:v1.23
        env:
        - name: TZ
          value: Asia/Shanghai
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: test-app
  namespace: default
spec:
  type: ClusterIP
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: test-app

主要配置部分和说明

spec:
  nodeSelector:
    type: k8s-node01

其对应的标签命令如下
# 节点打上标签
kubectl label node k8s-node01 type=k8s-node01 
# 查询所有集群内节点标签
kubectl get nodes --show-labels

更换打标签内容则需要改对应nodeSelector,如下:
kubectl label node k8s-node01 com=k8s-node01 
则配置需要更改为
spec:
  nodeSelector:
    com: k8s-node01

二、节点亲和性(node affinity)

2.1 基础理解

节点亲和性(node affinity)的概念与 nodeSelector 相似,可以基于节点的标签来限定 Pod 可以被调度到哪些节点上。

当前支持两种类型的节点亲和性:
requiredDuringSchedulingIgnoredDuringExecution (hard,目标节点必须满足此条件) 以及 
preferredDuringSchedulingIgnoredDuringExecution (soft,目标节点最好能满足此条件)。

名字中 IgnoredDuringExecution 意味着:
如果 Pod 已经调度到节点上以后,节点的标签发生改变,使得节点已经不再匹配该亲和性规则了,
Pod 仍将继续在节点上执行(这一点与 nodeSelector 相似)

将来,Kubernetes 将会提供 requiredDuringSchedulingRequiredDuringExecution 这个选项,
该选项与 requiredDuringSchedulingIgnoredDuringExecution 相似,不同的是,当节点的标签不在匹配亲和性规则之后,Pod 将被从节点上驱逐。

requiredDuringSchedulingIgnoredDuringExecution(硬策略) 的一个例子是,只在 Intel CPU 上运行该 Pod,
preferredDuringSchedulingIgnoredDuringExecution(软策略)的一个例子是,尽量在高可用区 XYZ 中运行这个 Pod,但是如果做不到,也可以在其他地方运行该 Pod。

2.2 例一和分析

PodSpec 中通过 affinity.nodeAffinity 字段来定义节点亲和性,示例文件如下

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/e2e-az-name
            operator: In
            values:
            - e2e-az1
            - e2e-az2
      preferredDuringSchedulingIgnoredDuringExecution:
      - 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

分析释意:

<一>、此处的亲和性规则表明
该 Pod 只能被调度到包含 key 为 kubernetes.io/e2e-az-name 且 value 为 e2e-az1 或 e2e-az2 的标签的节点上。
此外,如果节点已经满足了前述条件,将优先选择包含 key 为 another-node-label-key 且 value 为 another-node-label-value 的标签的节点。
<二>、其它补充说明
2.1 例子中使用了操作符 In。节点亲和性支持如下操作符:In、NotIn、Exists、DoesNotExist、Gt、Lt。使用 NotIn 和 DoesNotExist 可以
实现节点反亲和性(node anti-affinity)的效果,或者也可以使用 污点 为节点排斥某类 Pod。
2.2 如果某个 Pod 同时指定了 nodeSelector 和 nodeAffinity,则目标节点必须同时满足两个条件,才能将 Pod 调度到该节点上.
2.3 如果为 nodeAffinity 指定多个 nodeSelectorTerms,则目标节点只需要满足任意一个 nodeSelectorTerms 的要求,
    就可以将 Pod 调度到该节点上。
2.4 如果为 nodeSelectorTerms 指定多个 matchExpressions,则目标节点必须满足所有的 matchExpressions 的要求,才能将 Pod 调度到该节点上。
2.5 当 Pod 被调度到某节点上之后,如果移除或者修改节点的标签,Pod 将仍然继续在节点上运行。
    换句话说,节点亲和性规则只在调度该 Pod 时发生作用。
2.6 preferredDuringSchedulingIgnoredDuringExecution 中的 weight 字段取值范围为 1-100。
    对于每一个满足调度要求的节点(资源请求、亲和性/反亲和性规则,等),
    调度器将遍历该节点匹配的 preferredDuringSchedulingIgnoredDuringExecution 中所有的weight 并求和。
    此求和结果将与节点的其他优先级计算的得分合并。得分最高的节点被优先选择。

2.3 例二和分析

DeploymentSpec 中通过 affinity.nodeAffinity 字段来定义节点亲和性,示例文件如下

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: affinity
  labels:
    app: affinity
spec:
  replicas: 3
  revisionHistoryLimit: 15
  template:
    metadata:
      labels:
        app: affinity
        role: test
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
          name: nginxweb
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:  # 硬策略
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/hostname
                operator: NotIn
                values:
                - node03
          preferredDuringSchedulingIgnoredDuringExecution:  # 软策略
          - weight: 1
            preference:
              matchExpressions:
              - key: com
                operator: In
                values:
                - yijiadashuju

分析释意:

这个pod调度的时候,首先要求不能运行在标签为kubernetes.io/hostname=node03节点上,
但是如果有节点满足labels为com=yijiadashuju 的话,就会优先调度到这个节点上。

三、topologyKey理解

顾名思义,topology 就是 拓扑 的意思,这里指的是一个 拓扑域,是指一个范围的概念,
比如一个 Node、一个机柜、一个机房或者是一个地区(如杭州、上海)等,实际上对应的还是 Node 上的标签。
这里的 topologyKey 对应的是 Node 上的标签的 Key(没有Value),可以看出,其实 topologyKey 就是用于筛选 Node 的。
通过这种方式,我们就可以将各个 Pod 进行跨集群、跨机房、跨地区的调度了。

四、pod亲和性和反亲和性

4.1 基础理解

pod的亲和性主要用来解决pod可以和哪些pod部署在同一个集群里面,即拓扑域(由node组成的集群)里面;
而pod的反亲和性是为了解决pod不能和哪些pod部署在一起的问题,二者都是为了解决pod之间部署问题。

Pod之间的亲和性与反亲和性(inter-pod affinity and anti-affinity)可以基于已经运行在节点上的 Pod 的标签
(而不是节点的标签)来限定 Pod 可以被调度到哪个节点上。此类规则的表现形式是:

当 X 已经运行了一个或者多个满足规则 Y 的 Pod 时,待调度的 Pod 应该(或者不应该 - 反亲和性)在 X 上运行
规则 Y 以 LabelSelector 的形式表述,附带一个可选的名称空间列表

与节点不一样,Pod 是在名称空间中的(因此,Pod的标签是在名称空间中的),针对 Pod 的 LabelSelector 必须同时指定对应的名称空间

X 是一个拓扑域的概念,例如节点、机柜、云供应商可用区、云供应商地域,等。
X 以 topologyKey 的形式表达,该 Key代表了节点上代表拓扑域(topology domain)的一个标签。

4.2 pod affinity 的一个例子

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: failure-domain.beta.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: failure-domain.beta.kubernetes.io/zone
  containers:
  - name: with-pod-affinity
    image: k8s.gcr.io/pause:2.0

分析释意:

<一> Pod 的 affinity 定义了一个 Pod 亲和性规则和一个 Pod 反亲和性规则: 
	podAffinity 是 requiredDuringSchedulingIgnoredDuringExecution,
	podAntiAffinity 则是 preferredDuringSchedulingIgnoredDuringExecution。

五、常用经典例子

5.1 在一个三节点的集群中,部署一个使用 redis 的 web 应用程序,并期望 web-server 尽可能与 redis 在同一个节点上。

下面是 redis deployment 的 yaml 片段,包含三个副本以及 app=store 标签选择器。Deployment 中配置了 PodAntiAffinity(反请和性),确保调度器不会将三个副本调度到一个节点上:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-cache
spec:
  selector:
    matchLabels:
      app: store
  replicas: 3
  template:
    metadata:
      labels:
        app: store
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: redis-server
        image: redis:3.2-alpine

下面是 webserver deployment 的 yaml 片段,配置了 podAntiAffinity 以及 podAffinity。要求将其副本与 包含 app=store 标签的 Pod 放在同一个节点上;同时也要求 web-server 的副本不被调度到同一个节点上。

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

上面案例简单分析

在这里插入图片描述
其中 topologyKey: “kubernetes.io/hostname” 表示满足条件的节点必须存在一个key为kubernetes.io/hostname

上一篇:kubernetes集群网络模型记录——<12>

参考文章:http://bazingafeng.com/2019/03/31/k8s-affinity-topologykey/
参考文章:https://kuboard.cn/learning/k8s-intermediate/config/affinity.html#pod-affinity-%E7%9A%84%E4%B8%80%E4%B8%AA%E4%BE%8B%E5%AD%90

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值