K8S 亲和性与反亲和性 深度好文

news2025/1/21 11:43:59

今天我们来实验 pod 亲和性。官网描述如下:

假设有如下三个节点的 K8S 集群:

k8s31master 是控制节点

k8s31node1、k8s31node2 是工作节点

容器运行时是 containerd

一、镜像准备

1.1、镜像拉取

docker pull tomcat:8.5-jre8-alpine
docker pull nginx:1.14.2

1.2、镜像导出

docker save -o tomcat-8.5-jre8-alpine.tar.gz docker.io/library/tomcat:8.5-jre8-alpine
docker save -o nginx-1.14.2.tar.gz docker.io/library/nginx:1.14.2

1.3、镜像导入工作节点 containerd

# k8s31node1 执行
[root@k8s31node1 ~]# ctr -n=k8s.io images import tomcat-8.5-jre8-alpine.tar.gz
[root@k8s31node1 ~]# ctr -n=k8s.io images import nginx-1.14.2.tar.gz
[root@k8s31node1 ~]# ctr -n=k8s.io images ls|grep tomcat
[root@k8s31node1 ~]# ctr -n=k8s.io images ls|grep nginx

# k8s31node2 执行
[root@k8s31node2 ~]# ctr -n=k8s.io images import tomcat-8.5-jre8-alpine.tar.gz
[root@k8s31node2 ~]# ctr -n=k8s.io images import nginx-1.14.2.tar.gz
[root@k8s31node2 ~]# ctr -n=k8s.io images ls|grep tomcat
[root@k8s31node2 ~]# ctr -n=k8s.io images ls|grep nginx

 说明:

  • ctr 是 containerd 命令
  • ctr images import:导入镜像
  • -n=k8s.io:K8S 镜像存储命名空间

 1.4、亲和性介绍

  • 亲和性(affinity)属性,位于 pod.spec.affinity,它有三种亲和性:
kubectl explain pod.spec.affinity

 分别是 nodeAffinity(节点亲和性)、podAffinity(pod间亲和性)、podAntiAffinity(pod间反亲和性),它们可以分为两类:

  • 节点亲和性功能类似于 nodeSelector 字段,但它的表达能力更强,并且允许你指定软规则。
  • Pod 间亲和性/反亲和性允许你根据其他 Pod 的标签来约束 Pod。

简单来说:

nodeAffinity 定义了 pod 倾向于(亲和)被调度到哪些节点上。

podAffinity 定义了 pod 倾向于(亲和)跟哪些 pod 调度在一起。

podAntiAffinity 定义 pod 倾向于不(反亲和)跟哪些 pod 调度在一起。

 二、nodeAffinity(节点亲和性)

  • 查看帮助文档
kubectl explain pod.spec.affinity.nodeAffinity

 节点亲和性概念上类似于 nodeSelector, 它使你可以根据节点上的标签来约束 Pod 可以调度到哪些节点上。 节点亲和性有两种:

  • requiredDuringSchedulingIgnoredDuringExecution: 调度器只有在规则被满足的时候才能执行调度。此功能类似于 nodeSelector, 但其语法表达能力更强。
  • preferredDuringSchedulingIgnoredDuringExecution: 调度器会尝试寻找满足对应规则的节点。如果找不到匹配的节点,调度器仍然会调度该 Pod。

在上述类型中,IgnoredDuringExecution 意味着如果节点标签在 Kubernetes 调度 Pod 后发生了变更,Pod 仍将继续运行。

简单来说:

required 表示必须有节点满足这个位置定义的亲和性,这是个硬性条件,硬亲和性。

preferred 表示有节点尽量满足这个位置定义的亲和性,这不是一个必须的条件,软亲和性。

 2.1、required 硬亲和性

  • 查看 requiredDuringSchedulingIgnoredDuringExecution
kubectl explain pod.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution

 它有一个必填字段 nodeSelectorTerms。

  •  查看 nodeSelectorTerms
kubectl explain pod.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms

它是 NodeSelectorTerm 数组

NodeSelectorTerm 定义了两种匹配模式:

  • matchExpressions 数组
  • matchFields 数组

 2.1.1、matchExpressions

matchExpressions:它允许你使用表达式来匹配节点的标签。例如,你可以使用 In、NotIn、Exists、DoesNotExist、Gt、Lt 等操作符来创建复杂的标签匹配规则。

kubectl explain pod.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchExpressions

key:标签名称。

operator:匹配操作。

values:值列表。[] 或 - 形式都可以。

  •  编写资源文件

pod-node-affinity-required-match-expressions-demo.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-node-affinity-required-match-expressions
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: zone
            operator: In
            values:
            - east
            - south
  containers:
  - name: tomcat
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080

 matchExpressions 表达式的意思是,寻找具有 label key 为 zone,值为 east 或 south 的节点,把 pod 绑定上去。

  •  运行并查看
kubectl apply -f pod-node-affinity-required-match-expressions-demo.yaml
kubectl get pod -owide

 会发现 pod 并没有被正确调度。

因为我现在工作节点上,并没有一个节点有 zone 标签,值为  east 或 south。

required 是硬亲和性,必须满足表达式,pod 才能被正确调度。

  •  查看 pod 日志
kubectl describe pod pod-node-affinity-required-match-expressions

也能发现报 node affinity 错误。

  •  给 k8s31node1 打上标签 zone=east
kubectl label node k8s31node1 zone=east
kubectl get node --show-labels

  • 观察 pod 现在可以正常调度了

  • 如果这个时候,我们变更 k8s31node1 的标签
kubectl label node k8s31node1 zone-
# zone- 表示删除标签 zone
kubectl get pod -owide

会发现 pod 并没有被驱逐。 

  2.1.2、matchFields

matchFields:它允许你根据资源的非标签字段进行匹配,例如资源的名称、状态等。

kubectl explain pod.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchFields

matchFields 跟 matchExpressions 匹配模式一样。

key:标签名称。

operator:匹配操作。

values:值列表。[] 或 - 形式都可以。

  •  编写资源文件

pod-node-affinity-required-match-fields-demo.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-node-affinity-required-match-fields
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchFields:
          - key: metadata.name
            operator: In
            values: ['k8s31node2']
  containers:
  - name: tomcat
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080

 matchFields 表达式的意思是,寻找节点具有 metadata.name 属性,且值是 k8s31node2 的节点,把 pod 绑定上去。

怎么看 node 节点具有哪些属性?

# 以 json 格式或 yaml 格式输出 节点信息
kubectl get node k8s31node2 -o json
kubectl get node k8s31node2 -o yaml

  •  运行并查看
kubectl apply -f pod-node-affinity-required-match-fields-demo.yaml
kubectl get pod -owide

可以发现,它被正确调度到 k8s31node2 上。 

 2.2、preferred 软亲和性

  • 查看 preferredDuringSchedulingIgnoredDuringExecution
kubectl explain pod.spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution

有两个必填字段:

preference:偏好。偏好 也是一个 NodeSelectorTerm,所以也会有 matchExpressions 和 matchFields。

weight:权重。1-100 的数,weight 是相对权重,权重越高,pod 调度的几率越大。

 2.2.1、matchExpressions

  • 编写资源文件

pod-node-affinity-preferred-match-expressions-demo.yaml

apiVersion: v1
kind: Pod
metadata: 
  name: pod-node-affinity-preferred-match-expressions
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - preference:
          matchExpressions:
          - key: disk
            operator: In
            values: ['SSD']
        weight: 20
      - preference:
          matchExpressions:
          - key: disk
            operator: In
            values: ['HDD']
        weight: 10
  containers:
  - name: tomcat
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080

 preferred 匹配的意思是:

将 pod 节点优先调度到有标签 disk=SSD 的节点上。因为 disk=SSD 的 weight 数值更大,优先级更高。

业务含义是,将 pod 节点优先调度到拥有固态硬盘的节点上,没有固态硬盘的话,调度到拥有机械硬盘的节点上。

  • 运行并查看
kubectl apply -f pod-node-affinity-preferred-match-expressions-demo.yaml
kubectl get pod -owide

虽然我们现在系统上并没有 disk=SSD 与 disk=HDD 的节点,但是 pod 依然可以正常调度。这是因为 preferred 是一种软亲和性,即使找不到符合条件的节点,调度器 scheduler 依然会调度该 pod。

  • 给节点打标签
# 给 k8s31node1 节点打上 disk=HDD
kubectl label node k8s31node1 disk=HDD
# 给 k8s31node2 节点打上 disk=SSD
kubectl label node k8s31node2 disk=SSD
# 查看节点信息
kubectl get node --show-labels

  •  删除原来的 pod 并运行
kubectl delete -f pod-node-affinity-preferred-match-expressions-demo.yaml
kubectl apply -f pod-node-affinity-preferred-match-expressions-demo.yaml
kubectl get pod -owide

 可以看到 pod 被优先调度到 k8s31node2,因为它标签是 disk=SSD,权重最高。

  •  如果这个时候,我们变更 k8s31node2 的标签
kubectl label node k8s31node2 disk-
kubectl get pod -owide

 会发现 pod 并没有被驱逐。

matchFields 的情况与 required 类似,就不举例了。

2.3、节点亲和性总结

  • 节点亲和性 nodeAffinity 包括 required 和 preferred
  • required 是硬亲和性,只有条件满足,pod 才会被调度。
  • preferred 是软亲和性,条件匹配,优先按条件调度,条件不匹配,按默认算法调度。
  • matchExpressions 是按节点标签表达式来进行匹配。
  • matchFields 是按节点属性来进行匹配。
  • 无论 required 还是 preferred,在 pod 运行期,标签变更,pod 不会被驱逐。

 2.4、还原实验环境

删除 default 命名空间下所有 pod,

删除节点所有标签,为下一个实验做准备。

三、podAffinity(pod间亲和性)

podAffinity 定义了 pod 倾向于(亲和)跟哪些 pod 调度在同一个位置。

  • 查看帮助文档
kubectl explain pod.spec.affinity.podAffinity

 与节点亲和性类似,Pod 的亲和性与反亲和性也有两种类型:

  • requiredDuringSchedulingIgnoredDuringExecution
  • preferredDuringSchedulingIgnoredDuringExecution

例如,你可以使用 requiredDuringSchedulingIgnoredDuringExecution 亲和性来告诉调度器,将两个服务的 Pod 放到同一个云提供商可用区内,因为它们彼此之间通信非常频繁。

类似地,你可以使用 preferredDuringSchedulingIgnoredDuringExecution 反亲和性来将同一服务的多个 Pod 分布到多个云提供商可用区中。

3.1、required 硬亲和性

  • 查看 requiredDuringSchedulingIgnoredDuringExecution
kubectl explain pod.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution

它是 PodAffinityTerm 数组。

PodAffinityTerm 它有三个比较重要的字段:

toplogyKey:拓扑键,必填。我们在定义 pod 间亲和性时有一个前提,就是 B pod 想调度到跟 A pod 同一个位置,那么怎么定义这个位置?就是以这个字段来定义的。其取值是系统用来标示域的节点标签键。也就是说,不同节点具有相同标签 key,且 key 所对应的 value 也相同,则它们被定义为同一个位置。

 假设有如下服务器集群,在可用区A中有节点 node1、node2,它们拥有相同的节点标签(zone=A)则 node1 与 node2 被定义为同一个位置。node3 因为拥有不同的节点标签(zone=B)所以 node3 被视为不同位置。

toplogyKey 它是一个拓扑的概念,同一个机架、可用区、地域里面所有节点,都可以被 K8S 视为同一个位置而被统一调度。

labelSelector:标签选择器。通过 labelSelector 选取一组能作为亲和对象的已存在的 pod 资源。它定义了两种匹配模式:

  • matchExpressions    <[]LabelSelectorRequirement>
  • matchLabels    <map[string]string>

namespaces:名称空间。pod 在 Kubernetes 中是名称空间作用域的对象,因此 pod 的标签也隐式地具有名称空间属性。 针对 pod 标签的所有 标签选择器 都要指定名称空间,Kubernetes 会在指定的名称空间内寻找标签。

如果不指定 namespaces,那么 标签选择器 就是在当前要创建的 pod 的名称空间里查找符合条件的一组 pod。

 3.1.1、matchExpressions

matchExpressions:它允许你使用表达式来匹配 Pod 的标签。例如,你可以使用 In、NotIn、Exists、DoesNotExist 等操作符来创建复杂的标签匹配规则。

kubectl explain pod.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.labelSelector.matchExpressions

 key:标签名称。

operator:匹配操作。

values:值列表。[] 或 - 形式都可以。

  • 实验准备

使用 kubeadm join 往集群中加入一个新的工作节点 k8s31node3:

  • 镜像准备
# 将 tomcat、nginx 镜像也导入到 k8s31node3
# k8s31node3 执行
[root@k8s31node3 ~]# ctr -n=k8s.io images import tomcat-8.5-jre8-alpine.tar.gz
[root@k8s31node3 ~]# ctr -n=k8s.io images import nginx-1.14.2.tar.gz
[root@k8s31node3 ~]# ctr -n=k8s.io images ls|grep tomcat
[root@k8s31node3 ~]# ctr -n=k8s.io images ls|grep nginx

  • 资源文件编写

假设我们现在有两个 pod,nginx 跟 tomcat,nginx 反向代理 tomcat,它们之间要频繁通信,所以我们希望 pod-nginx 跟 pod-tomcat 能调度到同一个可用区内。

pod-pod-affinity-required-match-expressions-tomcat.yaml

apiVersion: v1
kind: Pod
metadata:
  name: tomcat
  labels:
    app: tomcat
spec:
  containers:
  - name: tomcat
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080
  • 运行并查看
kubectl apply -f pod-pod-affinity-required-match-expressions-tomcat.yaml
kubectl get pod -owide

tomcat 被调度到 k8s31node3 节点上。

  •  资源文件编写

pod-pod-affinity-required-match-expressions-nginx.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - topologyKey: zone
        labelSelector:
          matchExpressions:
          - {key: app, operator: In, values: ["tomcat"]}
  containers:
  - name: nginx
    image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
  • 运行并查看
kubectl apply -f pod-pod-affinity-required-match-expressions-nginx.yaml
kubectl get pod -owide

发现 nginx 无法被调度。

查看 pod 日志

kubectl describe pod nginx

报 pod 亲和性不符合。

原因是我们现在所有节点上,并没有定义 topologyKey=zone 这个键,而 required 是属于硬亲和性,在节点调度期,找不到符合调度规则的节点,系统不会对 pod 进行调度。

  • 给节点打标签
kubectl label node k8s31node1 zone=A
kubectl label node k8s31node2 zone=B
kubectl label node k8s31node3 zone=B
kubectl get pod -owide

 可以看到 nginx 被调度到 tomcat 所在的节点 k8s31node3 上了。

 倘若这个时候,我们起一个 nginx:

pod-pod-affinity-required-match-expressions-nginx2.yaml

就只是把上一个 nginx.yaml 改了一下 metadata.name 为 nginx2 而已。

apiVersion: v1
kind: Pod
metadata:
  name: nginx2
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - topologyKey: zone
        labelSelector:
          matchExpressions:
          - {key: app, operator: In, values: ["tomcat"]}
  containers:
  - name: nginx
    image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
kubectl apply -f pod-pod-affinity-required-match-expressions-nginx2.yaml
kubectl get pod -owide

会发现 nginx2 被调度到 k8s31node2 上了。

  •  分析

整个的部署图如下:

  • tomcat 首先被调度到 node3,这个过程是随机的,scheduler 调度器根据自己内部的调度算法来决定的。
  • nginx 被调度时,因为 nginx 跟 tomcat podAffinity,所以它要被调度到跟 tomcat 具有相同 topologyKey 的节点上,这个时候 node3 跟 node2 都满足要求(node1 因为 topologyKey 的值是 A,所以不满足要求),scheduler 调度器觉得 node3 这个时候的负载不高,所以也把 nginx 调度到 node3 上。
  • nginx2 被调度时,走 nginx 一样的逻辑,所以 node3 跟 node2 都满足要求,但此时 node3 负载已经很高了(跑着两个 pod),所以 scheduler 调度器决定将 nginx2 调度到 node2。
  •  还原实验环境

删除 nginx 跟 nginx2 以便进行下面的实验。

kubectl delete pod nginx
kubectl delete pod nginx2

3.1.2、matchLabels

matchLabels 的匹配方式,相对于 matchExpressions 更简单,它是以 键值对 的方式进行匹配的。

kubectl explain pod.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.labelSelector.matchLabels

  • 编写资源文件

pod-pod-affinity-required-match-labels-nginx.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - topologyKey: zone
        labelSelector:
          matchLabels:
            app: tomcat
  containers:
  - name: nginx
    image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

 pod-pod-affinity-required-match-labels-nginx2.yaml

俩个文件之间的差异,只在 metadata.name

apiVersion: v1
kind: Pod
metadata:
  name: nginx2
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - topologyKey: zone
        labelSelector:
          matchLabels:
            app: tomcat
  containers:
  - name: nginx
    image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
  •  运行并查看
kubectl apply -f pod-pod-affinity-required-match-labels-nginx.yaml
kubectl apply -f pod-pod-affinity-required-match-labels-nginx2.yaml
kubectl get pod -owide

可以看到跟 matchExpressions 是一样的效果。

  • 节点标签变更

倘如我们这个时候,将所有节点的 zone 标签删除,看看会有什么效果。

kubectl label node k8s31node1 zone-
kubectl label node k8s31node2 zone-
kubectl label node k8s31node3 zone-
kubectl get pod -owide

可以看到 pod 并不会被驱逐。

  •  还原实验环境

 删除 tomcat、nginx 跟 nginx2 以便进行下面的实验。

kubectl delete pod tomcat
kubectl delete pod nginx
kubectl delete pod nginx2

3.2、preferred 软亲和性

  • 查看 preferredDuringSchedulingIgnoredDuringExecution
kubectl explain pod.spec.affinity.podAffinity.preferredDuringSchedulingIgnoredDuringExecution

它是 WeightedPodAffinityTerm 数组。

WeightedPodAffinityTerm 它有两个必填字段:

podAffinityTerm:PodAffinityTerm 对象。它跟上面 required 是一模一样的。所以也必然有 toplogyKey、labelSelector、namespaces。

weight:权重。1-100 的数,weight 是相对权重,权重越高,pod 调度的几率越大。

假设现在有如下部署图:

node1、node2、node3 分别有标签 zone=A、zone=B、zone=C,表示它们分别位于可用区 A B C。

node1、node2、node3 上分别运行着 pod tomcat1、tomcat2、tomcat3。

tomcat1、tomcat2、tomcat3 分别有标签 app=tomcat1、app=tomcat2、app=tomcat3,它们的权重,分别是 10、30、20。

现在有一个新的 pod-nginx,加入进来,我们看看 K8S 是如何调度的-->

  • 编写 tomcat 配置文件

pod-pod-affinity-preferred-match-expressions-tomcat1.yaml

apiVersion: v1
kind: Pod
metadata:
  name: tomcat1
  labels:
    app: tomcat1
spec:
  nodeName: k8s31node1
  containers:
  - name: tomcat
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080

 nodeName 指定它运行在 node1 节点上。

 pod-pod-affinity-preferred-match-expressions-tomcat2.yaml

apiVersion: v1
kind: Pod
metadata:
  name: tomcat2
  labels:
    app: tomcat2
spec:
  nodeName: k8s31node2
  containers:
  - name: tomcat
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080

  nodeName 指定它运行在 node2 节点上。

  pod-pod-affinity-preferred-match-expressions-tomcat3.yaml

apiVersion: v1
kind: Pod
metadata:
  name: tomcat3
  labels:
    app: tomcat3
spec:
  nodeName: k8s31node3
  containers:
  - name: tomcat
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080

   nodeName 指定它运行在 node3 节点上。

  • 启动 tomcat
kubectl apply -f pod-pod-affinity-preferred-match-expressions-tomcat1.yaml
kubectl apply -f pod-pod-affinity-preferred-match-expressions-tomcat2.yaml
kubectl apply -f pod-pod-affinity-preferred-match-expressions-tomcat3.yaml
kubectl get pod -owide --show-labels

  • 给节点打标签
kubectl label node k8s31node1 zone=A
kubectl label node k8s31node2 zone=B
kubectl label node k8s31node3 zone=C
kubectl get node --show-labels

  • 编写 nginx 配置文件

pod-pod-affinity-preferred-match-expressions-nginx.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    podAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 10
        podAffinityTerm: 
          topologyKey: zone
          labelSelector:
            matchExpressions:
            - {key: app, operator: In, values: ["tomcat1"]}
      - weight: 30
        podAffinityTerm:
          topologyKey: zone
          labelSelector:
            matchExpressions:
            - {key: app, operator: In, values: ["tomcat2"]}
      - weight: 20
        podAffinityTerm:
          topologyKey: zone
          labelSelector:
            matchExpressions:
            - {key: app, operator: In, values: ["tomcat3"]}
  containers:
  - name: nginx
    image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

app=tomcat2 的权重最高,所以 nginx 需要被调度到跟 tomcat2 相同 zone 下的服务器上,因为该 zone 只有一个 node2,所以 nginx 被调度到 node2 上。

  • 删掉 nginx,并修改所有 pod label
kubectl delete pod nginx
kubectl label pod tomcat1 app=tomcat --overwrite=true
kubectl label pod tomcat2 app=tomcat --overwrite=true
kubectl label pod tomcat3 app=tomcat --overwrite=true
# --overwrite=true 表示覆盖原来 label 的值
kubectl get pod -owide --show-labels

  •  重新运行 nginx,我们看看会发生什么
kubectl apply -f pod-pod-affinity-preferred-match-expressions-nginx.yaml
kubectl get pod -owide --show-labels

 现在没有一个 pod 的标签符合 标签选择器 的规则,但是 nginx 还是能被正常的调度,因为 preferred 是一种软亲和性。标签选择器的规则不匹配,scheduler 调度器会根据内部的算法选择合适的节点来绑定pod。

 3.3、pod 间亲和性总结

  • pod 间亲和性 podAffinity 包括 required 和 preferred
  • required 是硬亲和性,只有条件满足,pod 才会被调度。
  • preferred 是软亲和性,条件匹配,优先按条件调度,条件不匹配,按默认算法调度。
  • matchExpressions 是按 pod 标签表达式来进行匹配。
  • matchLabels 也是按 pod 标签来进行匹配,不过它是以键值对的方式来表示匹配规则。
  • 无论 required 还是 preferred,在 pod 运行期,不管是 节点 标签变更,还是被亲和的 pod 标签变更,pod 都不会被驱逐。
  • podAffinity 中有一个很重要的概念是 toplogyKey,理解它对于理解 pod 调度非常重要。

 3.4、还原实验环境

删除 nginx tomcat1 tomcat2 tomcat3

kubectl delete pod nginx tomcat1 tomcat2 tomcat3 --force --grace-period=0

 保留 node1、node2、node3 的 zone label

四、podAntiAffinity(pod间反亲和性)

podAntiAffinity 定义了 pod 倾向于不跟哪些 pod 调度在同一个位置。

  • 查看帮助文档
kubectl explain pod.spec.affinity.podAntiAffinity

可以看到,它跟 podAffinity 的定义,几乎是一摸一样的。

可以猜到,K8S 内部在进行调度的时候,应该是采用一种取反的操作。

筛选出不想亲和的 pod 所具有的 toplogyKey,然后在剩下的 toplogyKey 里选择节点进行绑定。

下面是 podAffinity 的定义。

 4.1、required 硬亲和性

 这一节,我们只演示 required,其他大同小异。

 假设现在有如下部署图:

node1、node2、node3 分别有标签 zone=A、zone=B、zone=C,表示它们分别位于可用区 A B C。

node3 运行着 tomcat1,它有标签 app=tomcat。

现在再来一个 tomcat2,我们不希望它跟 tomcat1 在同一个可用区下。

在实际业务中,相同的可用区往往意味着同一个机房,而部署同一个应用,往往不希望它们在同一个节点、或者同一个可用区下,因为这样容易导致 单点故障。从而让整个服务不可用。

我们看看这在 K8S 中要怎么实现-->

  •  编写 tomcat1 资源文件

pod-pod-antiaffinity-required-match-expressions-tomcat1.yaml

apiVersion: v1
kind: Pod
metadata:
  name: tomcat1
  labels:
    app: tomcat
spec:
  nodeName: k8s31node3
  containers:
  - name: tomcat
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080

 nodeName 指定它运行在 node3 节点上。

  •   编写 tomcat2 资源文件

pod-pod-antiaffinity-required-match-expressions-tomcat2.yaml

apiVersion: v1
kind: Pod
metadata:
  name: tomcat2
  labels:
    app: tomcat
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - topologyKey: zone
        labelSelector:
          matchExpressions:
          - {key: app, operator: In, values: ["tomcat"]}
  containers:
  - name: tomcat
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080
  •  运行并查看
kubectl apply -f pod-pod-antiaffinity-required-match-expressions-tomcat1.yaml
kubectl apply -f pod-pod-antiaffinity-required-match-expressions-tomcat2.yaml
kubectl get pod -owide --show-labels

可以看到 tomcat2 被调度到跟 tomcat1 不同的 zone 的服务器上(node1、node2 都可以)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2279798.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用户中心项目教程(五)---MyBatis-Plus完成后端初始化+测试方法

文章目录 1.数据库的链接和创建2.建库建表语句3.引入依赖4.yml配置文件5.添加相对路径6.实体类的书写7.Mapper接口的定义8.启动类的指定9.单元测试10运行时的bug 1.数据库的链接和创建 下面的这个就是使用的我们的IDEA链接这个里面的数据库&#xff1a; 接下来就是输入这个用户…

TL3562/3568移植无锡沐创N500L-AM4驱动进内核源码,报错及其解决方案

前言 创龙官方提供的资料无锡沐创N500L-AM4驱动是rnpgbe-0.1.0.rc60-dd9f3cf.tar.gz&#xff1b;无锡沐创官方&#xff0c;截止目前&#xff0c;最新驱动是rnpgbe-0.2.3-f26b9a4.tar.gz。考虑到开发的稳妥性&#xff0c;先选用创龙尝试过的rnpgbe-0.1.0.rc60-dd9f3cf.tar.gz来移…

CycleGAN - CycleGAN网络:无监督图像到图像转换的生成对抗网络

1. 背景与问题 在图像到图像转换任务中&#xff0c;传统的生成对抗网络&#xff08;GANs&#xff09;依赖于成对的训练数据来进行监督学习。然而&#xff0c;获得大量成对标注数据通常是昂贵且耗时的。在许多应用中&#xff0c;真实世界的标注数据往往是稀缺的&#xff0c;因此…

空间解析几何8:空间线段与圆锥侧面的最短距离【附MATLAB代码】

理论推导 matlab代码 function [dmin] distanceConeToLine (A1,B1,A2,B2,R) dmin 100000000; h norm(A2-B2); A B1(1)-A1(1); if(abs(A)<1e-2)A 1e-2; end B B1(2)-A1(2); if(abs(B)<1e-2)B 1e-2; end C B1(3)-A1(3); F A1(1)*CA*h-A1(3)*A; G A1(2)*CB*h-A1(…

K8S 集群搭建和访问 Kubernetes 仪表板(Dashboard)

一、环境准备 服务器要求&#xff1a; 最小硬件配置&#xff1a;2核CPU、4G内存、30G硬盘。 服务器可以访问外网。 软件环境&#xff1a; 操作系统&#xff1a;Anolis OS 7.9 Docker&#xff1a;19.03.9版本 Kubernetes&#xff1a;v1.18.0版本 内核版本&#xff1a;5.4.203-…

2024:成长、创作与平衡的年度全景回顾

文章目录 1.前言2.突破自我&#xff1a;2024年个人成长与关键突破3.创作历程&#xff1a;从构想到落笔&#xff0c;2024年的文字旅程4.生活与学业的双重奏&#xff1a;如何平衡博客事业与个人生活5.每一步都是前行&#xff1a;2024年度的挑战与收获6.总结 1.前言 回首2024年&a…

HTML<form>标签

例子 具有两个输入字段和一个提交按钮的HTML表单&#xff1a; <form action"/action_page.php" method"get"> <label for"fname">First name:</label> <input type"text" id"fname" name"f…

C++:输入3个整数,利用指针和函数,按由小到大的顺序输出。

输出样例如图所示&#xff1a; 代码如图&#xff1a; #include<iostream> using namespace std;void exchange(int* x, int* y){int temp;temp *x;*x *y;*y temp; }int main(){int a 0, b 0, c 0;int* p1 &a, * p2 &b, * p3 &c;cout << &quo…

【QT】 控件 -- 按钮类(Button)

&#x1f525; 目录 1. 前言 2. Push Button 按钮 1、带有图标的按钮 -- 纯代码实现2、带有快捷键的按钮 -- 图形化&代码实现 3、按钮的重复触发 3. Radio Button 按钮 **1. click、press、release、toggled 的区别** **2. 单选框分组** 4. Check Box 复选 5. Tool Butto…

【Linux】Linux入门(三)权限

目录 前提权限概念whoami指令 Linux权限管理文件访问者的分类&#xff08;人&#xff09;file指令权限信息权限的表示方法 chmod指令 更改权限chown指令 修改文件&#xff0c;文件夹所属用户和用户组 权限掩码umask&#xff08;权限掩码&#xff09; 粘滞位 前提 请先看下面这…

Unity编辑器缩放设置

Unity默认界面UI字体太小了&#xff0c;可以设置一下缩放 打开首选项&#xff0c; UI Scaling 设置成125%或者更大 &#xff0c;然后重启

【Maui】下拉框的实现,绑定键值对

文章目录 前言一、问题描述二、解决方案三、软件开发&#xff08;源码&#xff09;3.1 创建模型3.2 视图界面3.3 控制器逻辑层 四、项目展示![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/05795ee1c24c49129b822b530ef58302.png) 前言 .NET 多平台应用 UI (.NET MA…

ARCGIS国土超级工具集1.3更新说明

ARCGIS国土超级工具集V1.3版本&#xff0c;功能已增加至49 个。在V1.2的基础上修复了若干使用时发现的BUG&#xff0c;完善了部分已有的功能&#xff0c;新增了“面要素狭长面检测分割”等功能&#xff0c;新工具使用说明如下&#xff1a; 一、勘测定界工具栏更新土地分类面积表…

HunyuanDiT代码笔记

HunyuanDiT 是由腾讯发布的文生图模型&#xff0c;适配中英双语。 在模型方面的改进&#xff0c;主要包括&#xff1a; transformer结构text encoderpositional encoding Improving Training Stability To stabilize training, we present three techniques: We add layer nor…

DDD - 如何设计支持快速交付的DDD技术中台

文章目录 Pre概述打造快速交付团队烟囱式的开发团队(BAD)大前端技术中台(GOOD) 技术中台的特征简单易用的技术中台建设总结 Pre DDD - 软件退化原因及案例分析 DDD - 如何运用 DDD 进行软件设计 DDD - 如何运用 DDD 进行数据库设计 DDD - 服务、实体与值对象的两种设计思路…

服务器硬盘RAID速度分析

​ 在现代数据中心和企业环境中&#xff0c;服务器的存储性能至关重要&#xff0c;RAID&#xff08;独立磁盘冗余阵列&#xff09;技术通过将多块硬盘组合成一个逻辑单元&#xff0c;提供了数据冗余和性能优化&#xff0c;本文将详细探讨不同RAID级别对服务器硬盘速度的影响&am…

【Docker】搭建一个功能强大的自托管虚拟浏览器 - n.eko

前言 本教程基于群晖的NAS设备DS423的docker功能进行搭建&#xff0c;DSM版本为 DSM 7.2.2-72806 Update 2。 n.eko 支持多种类型浏览器在其虚拟环境中运行&#xff0c;本次教程使用 Chromium​ 浏览器镜像进行演示&#xff0c;支持访问内网设备和公网地址。 简介 n.eko 是…

五、华为 RSTP

RSTP&#xff08;Rapid Spanning Tree Protocol&#xff0c;快速生成树协议&#xff09;是 STP 的优化版本&#xff0c;能实现网络拓扑的快速收敛。 一、RSTP 原理 快速收敛机制&#xff1a;RSTP 通过引入边缘端口、P/A&#xff08;Proposal/Agreement&#xff09;机制等&…

“深入浅出”系列之C++:(9)线程分离

线程分离的基本概念 线程分离是通过调用 std::thread::detach() 方法实现的。当线程被分离时&#xff0c;它会成为一个独立的线程&#xff0c;并且会自动管理自己的资源。当该线程完成执行时&#xff0c;它会自动清理资源&#xff0c;父线程不再需要等待或回收这个线程。 线程…

Day 13 卡玛笔记

这是基于代码随想录的每日打卡 144. 二叉树的前序遍历 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a; root [1,null,2,3] 输出&#xff1a;[1,2,3] 解释&#xff1a; 示例 2&#xff1a; 输入&#xff1a; ro…