提升服务高可用性—Pod亲和力 十八岁 2025-09-13 2025-09-13
提升服务高可用性-Pod亲和力 1.亲和力Affinity Kubernetes的亲和力(Affinity)是一种调度规则,作用于Pod资源,用于控制Pod的调度行为,比如Pod应该或者尽量调度到哪些节点上、Pod不能和哪些Pod部署在一起等,Pod尽量和哪些Pod部署到一起,从而实现更灵活的资源管理和故障隔离。
Kubernetes的亲和力支持三种类型:节点亲和力(NodeAffinity)、Pod亲和力(PodAffinity)、Pod反亲和力(PodAntiAffinity)。
分别用于如下用途:
节点亲和力:用于控制Pod和节点之间的关系
Pod亲和力:用于控制Pod和Pod之间的关系,允许和某些Pod部署在同一个位置
Pod反亲和力:同样用于控制Pod和Pod之间的关系,不允许和某些Pod部署在同一个位置
同时每种亲和力也分为了强制和非强制 调度策略,用于实现调度规则是属于尽量满足还是必须满足 。
亲和力详细分类:
在配置Pod的节点亲和性时,硬亲和性(requiredDuringSchedulingIgnoredDuringExecution)和软亲和性(preferredDuringSchedulingIgnoredDuringExecution)的调度行为是有明确优先级和处理顺序的。Kubernetes调度器会首先考虑硬亲和性,然后在此基础上尽力满足软亲和性。
调度流程
硬亲和性(Hard Affinity) :
首先,Kubernetes调度器会检查所有符合硬亲和性条件的节点。如果没有任何节点满足硬亲和性的条件,Pod将不会被调度。
硬亲和性是强制性的要求,如果没有符合条件的节点,Pod就会处于待调度状态,直到有匹配的节点可用。
软亲和性(Soft Affinity) :
在找到满足硬亲和性条件的节点集合后,调度器会根据软亲和性的权重(weight)对这些节点进行评分和排序。
调度器会优先选择得分最高的节点来调度Pod,但如果没有任何节点满足软亲和性的条件,Pod仍然会调度到满足硬亲和性但不满足软亲和性的节点上。
2.认识拓扑域和拓扑键 拓扑键(topologyKey) 和 拓扑域(topology domain) 是 Kubernetes 中用来描述节点物理/逻辑分组的核心概念,主要用于调度(尤其是 Pod Topology Spread Constraints)、亲和性/反亲和性,以及服务流量路由等场景。
拓扑键(topologyKey) 它是节点标签(Node Label)的 key 。 常见标准值:
kubernetes.io/hostname:每个节点自己是一个独立拓扑
topology.kubernetes.io/zone:可用区(Availability Zone)
topology.kubernetes.io/region:区域(Region)
你也可以用自定义标签,比如 rack、failure-domain.beta.kubernetes.io/zone 等。
拓扑域(topology domain) 当多个节点拥有相同的 topologyKey 且 value 相同 时,这些节点就被认为属于同一个拓扑域 。
举例:
关键点是:标签本身不会自动成为拓扑域,只有当某个规则把这个 Label 的 key 作为 topologyKey 使用时,才会按这个标签值划分拓扑域。
3.Pod硬亲和力配置详解 假设已经有一组 Redis Pod,它的pod标签如下:
现在希望业务 Pod myapp 必须调度到和 Redis Pod 相同的节点上 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 [root@k8s-master01 affinity ] apiVersion: apps/v1 kind: Deployment metadata: name: myapp namespace: default spec: replicas: 2 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: redis namespaces: - default topologyKey: kubernetes.io/hostname containers: - name: myapp image: nginx:1.27 ports: - name: http containerPort: 80
标签匹配还可以使用正则方式匹配,例如:
当前 Pod 必须调度到:与 default 命名空间中、标签 security=S1 的 Pod 所在节点属于同一个 zone 拓扑域的节点上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: topology.kubernetes.io/zone namespaces: - default
其中最关键的是:
1 2 3 4 5 6 7 8 matchExpressions: - key: security operator: In values: - S1 它等价于: matchLabels: security: S1
但 matchExpressions 能表达更复杂的条件。 比如:
1 2 3 4 5 6 7 8 matchExpressions: - key: security operator: In values: - S1 - S2
常见 operator 有这几个:
operator
含义
values 是否需要
In
标签值必须在指定列表中
需要
NotIn
标签值不能在指定列表中
需要
Exists
只要求这个标签存在
不需要
DoesNotExist
要求这个标签不存在
不需要
例如:表示只要 Pod 上存在 gpu 这个标签就匹配,不关心它的值是什么。
1 2 3 matchExpressions: - key: gpu operator: Exists
4.Pod软亲和力配置详解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 affinity: podAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: security operator: In values: - S2 topologyKey: topology.kubernetes.io/zone namespaces: - default
5.Pod硬反亲和力配置详解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: default spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: nginx namespaces: - default topologyKey: kubernetes.io/hostname
6.Pod软反亲和力配置详解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: nginx namespaces: - default topologyKey: kubernetes.io/hostname
7.节点硬亲和力和软亲和力配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 apiVersion: apps/v1 kind: Deployment metadata: name: myapp namespace: default spec: replicas: 2 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disk operator: In values: - ssd preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 preference: matchExpressions: - key: gpu operator: In values: - A100 containers: - name: myapp image: nginx:1.27
假设节点标签如下:
1 2 3 node01 disk=ssd gpu=A100 node02 disk=ssd gpu=H100 node03 disk=hdd gpu=A100
在调度时会先执行硬亲和筛选 :
1 2 3 node01 disk=ssd ✅ 可以 node02 disk=ssd ✅ 可以 node03 disk=hdd ❌ 直接排除
然后再执行软亲和,因此在 node01 和 node02 ,更倾向调度到 node01:
1 2 node01 gpu=A100 ← 优先 node02 gpu=H100
上述案例配置的意思是:Pod 必须 调度到有 disk=ssd 标签的节点上;在满足这个条件的节点中,优先 选择 具有gpu=A100 标签的节点。
8.拓扑域划分 集群中有以下6个节点:
1 2 3 4 5 6 7 8 [root@k8s-master01 ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master01 Ready <none> 635d v1.31.4 k8s-master02 Ready <none> 635d v1.31.4 k8s-master03 Ready <none> 635d v1.31.4 k8s-node01 Ready <none> 635d v1.31.4 k8s-node02 Ready <none> 635d v1.31.4 k8s-node03 Ready <none> 635d v1.31.4
在一个超大规模的集群中,可以使用不同的区域和可用区划分拓扑,同时可以精确到数据中 心或机房,甚至某个机柜。
比如按照区域划分拓扑域:
1 2 3 4 5 6 7 8 9 10 11 12 # 把k8s-master01,k8s-master02,k8s-node01,k8s-node02四个节点划分到北京的区域 [root@k8s-master01 ~]# kubectl label nodes k8s-master01 k8s-master02 k8s-node01 k8s-node02 region=beijing node/k8s-master01 labeled node/k8s-master02 labeled node/k8s-node01 labeled node/k8s-node02 labeled # 把k8s-master03,k8s-node03两个节点划分到南京的区域 [root@k8s-master01 ~]# kubectl label nodes k8s-master03 k8s-node03 region=nanjing node/k8s-master03 labeled node/k8s-node03 labeled
同时如果一个区域具备多个数据中心,也可以按照可用区进行再次划分,比如北京区域有两个数据中心位于海淀和朝阳:
1 2 3 4 5 6 7 8 9 10 # 把北京的四台机器进一步划分,k8s-master01,k8s-node01在海淀,k8s-master02和k8s-node02在朝阳 # 划分haidian [root@k8s-master01 ~]# kubectl label nodes k8s-master01 k8s-node01 k8s-node02 zone=beijing-haidian node/k8s-master01 labeled node/k8s-node02 labeled node/k8s-node01 labeled # 划分chaoyang [root@k8s-master01 ~]# kubectl label nodes k8s-master02 zone=beijing-chaoyang node/k8s-master02 labeled
如果需要进一步划分,可以按照不同的标签进行划分即可,就是为不同的节点打上标签,来做逻辑上的划分,只有节点标签的key和value相同时它们才属于同一个拓扑域。
9.k8s亲和力实战 9.1pod必须部署在不同的节点
亲和性(Affinity) :让 Pod 尽量靠近 (放在相同节点 / 相同 zone 等)。
反亲和性(Anti-Affinity) :让 Pod 尽量远离 (放在不同节点 / 不同 zone 等)。
想让多个 Pod 必须部署到不同的宿主机上,就是典型的“排斥”需求,所以用 podAntiAffinity 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 3 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: my-app topologyKey: kubernetes.io/hostname namespaces: - default containers: - name: app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
创建资源:
1 2 [root@k8s-master01 20-affinity]# kubectl create -f my-app.yaml deployment.apps/my-app created
查看pod的分布情况,三个副本的pod分布在不同主机上:
1 2 3 4 5 [root@k8s-master01 20-affinity]# kubectl get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-app-544c97bd6d-bfjb6 1/1 Running 0 2m49s 172.16.32.133 k8s-master01 <none> <none> my-app-544c97bd6d-m2rvf 1/1 Running 0 2m49s 172.16.85.255 k8s-node01 <none> <none> my-app-544c97bd6d-p7vdh 1/1 Running 0 2m49s 172.16.58.214 k8s-node02 <none> <none>
在上述案例中当副本数少于节点数量时 ,pod会分散在不同的节点上部署,但是当副本数大于节点数时 ,就会有pod一直处于Pending状态 ,无法部署成功:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # 增加副本数为7,修改replicas参数为7 [root@k8s-master01 20-affinity]# kubectl edit deployments.apps my-app apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "1" creationTimestamp: "2026-09-10T16:01:59Z" generation: 1 name: my-app namespace: default resourceVersion: "94941999" uid: e6287757-34d4-4fca-88a9-0015c31302d8 spec: progressDeadlineSeconds: 600 replicas: 7 #将副本修改为7
查看pod部署情况:
1 2 3 4 5 6 7 8 9 [root@k8s-master01 20-affinity]# kubectl get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-app-544c97bd6d-5k79n 1/1 Running 0 55s 172.16.122.178 k8s-master02 <none> <none> my-app-544c97bd6d-8vxdl 0/1 Pending 0 55s <none> <none> <none> <none> my-app-544c97bd6d-bfjb6 1/1 Running 0 12m 172.16.32.133 k8s-master01 <none> <none> my-app-544c97bd6d-dtg8f 1/1 Running 0 55s 172.16.135.178 k8s-node03 <none> <none> my-app-544c97bd6d-j8qcr 1/1 Running 0 55s 172.16.195.39 k8s-master03 <none> <none> my-app-544c97bd6d-m2rvf 1/1 Running 0 12m 172.16.85.255 k8s-node01 <none> <none> my-app-544c97bd6d-p7vdh 1/1 Running 0 12m 172.16.58.214 k8s-node02 <none> <none>
可以看到名字是my-app-544c97bd6d-8vxdl的pod一直处于pending,可以查看具体信息:
1 2 3 4 5 6 7 8 9 # describe指令查看详细信息 [root@k8s-master01 20-affinity]# kubectl describe po my-app-544c97bd6d-8vxdl Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 2m3s default-scheduler 0/6 nodes are available: 6 node(s) didn't match pod anti-affinity rules. preemption: 0/6 nodes are available: 6 No preemption victims found for incoming pod. 翻译:警告:调度失败,耗时 2 分钟 3 秒,默认调度器 0/6 个节点可用:6 个节点不符合 Pod 反亲和性规则。抢占:0/6 个节点可用:6 个节点未找到传入 Pod 的抢占目标。 也就是说6个节点都不符合定义的pod反亲和性规则,所以一直pending
所以当pod副本数大于 节点数量时就要用preferredDuringSchedulingIgnoredDuringExecution软亲和性来实现,参考9.2
9.2pod尽量部署在不同的节点 当pod副本数大于 节点数量时,pod应该尽量分散部署,不是强制必须,用podAntiAffinity和preferredDuringSchedulingIgnoredDuringExecution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 [root@k8s-master01 20 -affinity ] apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 3 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - my-app topologyKey: kubernetes.io/hostname namespaces: - default containers: - name: app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
创建上述资源:
1 2 [root@k8s-master01 20-affinity]# kubectl replace -f my-app.yaml deployment.apps/my-app replaced
检查pod分散情况:
1 2 3 4 5 [root@k8s-master01 20-affinity]# kubectl get pod -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-app-74fdd4ccdf-qs9nn 1/1 Running 0 36s 172.16.122.157 k8s-master02 <none> <none> my-app-74fdd4ccdf-xgx9c 1/1 Running 0 31s 172.16.32.147 k8s-master01 <none> <none> my-app-74fdd4ccdf-zvt7k 1/1 Running 0 33s 172.16.135.131 k8s-node03 <none> <none>
此时在将pod副本数扩容至8个,在观察pod分散情况:
1 2 3 4 5 6 7 8 [root@k8s-master01 20-affinity]# kubectl edit deployments.apps my-app spec: progressDeadlineSeconds: 600 replicas: 8 #将replicas参数修改为8 revisionHistoryLimit: 10 selector: matchLabels: app: my-app
1 2 # 可以看到在k8s-node02和k8s-master01上分别部署了两个pod,此时pod都是Running状态,就没有penging的了 [root@k8s-master01 20-affinity]# kubectl get po -owide
9.3同一应用分布在不同可用域 假设集群中6个节点按照zone划分haidian和chaoyang两个可用域
1 2 3 4 5 6 7 8 9 10 11 # 划分haidian, [root@k8s-master01 ~]# kubectl label nodes k8s-master01 k8s-node01 k8s-node02 zone=beijing-haidian node/k8s-master01 labeled #这三个节点属于同一个可用域haidian node/k8s-node02 labeled node/k8s-node01 labeled # 划分chaoyang [root@k8s-master01 ~]# kubectl label nodes k8s-master02 zone=beijing-chaoyang node/k8s-master02 labeled #这三个节点属于同一个可用域chaoyang node/k8s-master03 labeled node/k8s-node03 labeled
按照上述规划,集群划分为两个不同的可用域,分别是haidian和chaoyang两个可用域,可以把应用分布在不同的可用域,以提高服务的高可用性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 [root@k8s-master01 20 -affinity ] apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 2 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - my-app topologyKey: zone namespaces: - default containers: - name: app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
创建资源:
1 2 [root@k8s-master01 20-affinity]# kubectl create -f diff-zone.yaml deployment.apps/my-app created
查看pod分散情况:
1 2 3 4 [root@k8s-master01 20-affinity]# kubectl get po -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-app-c458695bc-ssrxq 1/1 Running 0 10s 172.16.122.185 k8s-master02 <none> <none> my-app-c458695bc-xd9ht 1/1 Running 0 10s 172.16.58.226 k8s-node02 <none> <none>
可以看到两个副本的pod分别落在k8s-node02(属于haidian域)和k8s-master02(属于chaoyang域) ,因为副本是2,不同的可用域也是2个,所以刚好分散,当副本数大于不同可用域的个数时,使用硬反亲和性时会出现pod是Pending状态
扩容pod副本为4:
1 2 [root@k8s-master01 20-affinity]# kubectl edit deployments.apps my-app replicas: 2 #将replicas的值修改为4
再次查看pod分散情况,可以看到新增的两个pod一直处于pending状态,没有满足的节点,因为上述的规则是按照可用域来分散pod:
1 2 3 4 5 6 [root@k8s-master01 20-affinity]# kubectl get po -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-app-c458695bc-99drz 0/1 Pending 0 2s <none> <none> <none> <none> my-app-c458695bc-ssrxq 1/1 Running 0 95s 172.16.122.185 k8s-master02 <none> <none> my-app-c458695bc-w42f9 0/1 Pending 0 2s <none> <none> <none> <none> my-app-c458695bc-xd9ht 1/1 Running 0 95s 172.16.58.226 k8s-node02 <none> <none>
9.4应用尽量和缓存服务部署在同一个可用域 如果集群分布在不同的可用域,为了提升基础组件的使用性能,可以把应用程序尽量和缓存 服务部署在同一个可用域。首先部署一个redis缓存服务:
1 2 [root@k8s-master01 20-affinity]# kubectl create deployment redis-cache --image=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/redis:5.0.14 deployment.apps/redis-cache created
Pod标签如下(app=redis-cache):
1 2 3 [root@k8s-master01 20-affinity]# kubectl get po --show-labels NAME READY STATUS RESTARTS AGE LABELS redis-cache-79987bf7f4-hfwz4 1/1 Running 0 9m31s app=redis-cache,pod-template-hash=79987bf7f4
Pod部署在node02节点上:
如果按照zone来划分拓扑域的话,在9.3中规划的 k8s-node02 ,k8s-node01,k8s-master01属于同一个可用域beijing-haidian,所以按照预期规划应用应该部署在k8s-node02 ,k8s-node01,k8s-master01三台节点上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 [root@k8s-master01 20 -affinity ] apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 2 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - redis-cache topologyKey: zone namespaces: - default containers: - name: app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
创建应用资源:
1 2 [root@k8s-master01 20-affinity]# kubectl create -f my-app.yaml deployment.apps/my-app created
查看pod部署位置,可以看到my-app的pod按照预期部署在对应的节点上:
上述流程需要注意的问题是:redis缓存服务没有配置任何调度的限制,在缓存更新重启时pod可能调度到其他可用域中,此时应用的pod如果不更新的话,那么它们有可能不在同一个可用域,在生产中这种情况也要在redis服务中配置亲和性,让它靠近我们的应用服务才算完整。
9.5节点亲和性-必须调度到高性能节点 假设集群中有一批机器是高性能机器,而有一些需要密集计算的服务,需要部署至这些机器,以提高计算性能,此时可以使用节点亲和力来控制 Pod 尽量或者必须部署至这些高性能节点上。
设置k8s-master02的标签为disktype=nvem,k8s-master03,k8s-node01,k8s-node02,k8s-node03的标签为disktype=ssd
1 2 3 4 5 6 7 # 给节点打上标签 kubectl label nodes k8s-master02 disktype=nvem node/k8s-master02 labeled # 给节点打上标签 kubectl label nodes k8s-master03,k8s-node01,k8s-node02,k8s-node03 disktype=ssd
应用资源亲和性配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 [root@k8s-master01 20 -affinity ] apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 2 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktpye operator: In values: - ssd - nvme containers: - name: app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
创建资源:
1 2 [root@k8s-master01 20-affinity]# kubectl create -f disktype.yaml deployment.apps/my-app created
按照规划pod会部署在 k8s-master02 ,k8s-master03,k8s-node01,k8s-node02,k8s-node03 当中:
9.6节点亲和性-尽量调度到高性能节点 依然使用9.5中的标签配置:
1 2 k8s-master02的标签为disktype=nvem k8s-master03,k8s-node01,k8s-node02,k8s-node03的标签为disktype=ssd
如果不是强制要求,可以用preferredDuringSchedulingIgnoredDuringExecution参数让服务尽量部署至高性能节点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 2 selector: matchLabels: app: my-app template: metadata: labels: app: my-app #定义的pod标签时app=myapp spec: affinity: nodeAffinity: # 尽量满足 preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 preference: - matchExpressions: - key: disktype operator: In values: - ssd - nvme containers: - name: app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
同时还可以配置优先调度到 nvem 的节点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 1 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 50 preference: matchExpressions: - key: disktype operator: In values: - ssd - weight: 90 preference: matchExpressions: - key: disktype operator: In values: - nvem containers: - name: app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
创建资源:
1 2 [root@k8s-master01 20-affinity]# kubectl create -f disktype.yaml deployment.apps/my-app created
查看pod部署情况,副本是1,优先部署在k8s-master02节点上:
把pod副本数扩容3时,pod才会部署在disktype=ssd的节点上:
9.7应用尽量不部署至低性能节点 假如集群中有一些机器可能性能不佳或者其他因素的影响,需要控制某个服务尽量不部署至这些机器,因为节点亲和性中没有反亲和性,所以此时只需要把 operator 改为 NotIn 即可:
假设集群中k8s-master01,k8s-master02,k8s-master03三个节点性能比较低,尽可能的不要将应用部署到这三台节点上,为三个节点打上 performance=low标签
1 2 3 4 [root@k8s-master01 20-affinity]# kubectl label nodes k8s-master01 k8s-master02 k8s-master03 performance=low node/k8s-master01 labeled node/k8s-master02 labeled node/k8s-master03 labeled
定义资源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 vim performance.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 3 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 preference: matchExpressions: - key: performance operator: NotIn values: - low containers: - name: app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
创建资源:
1 2 [root@k8s-master01 20-affinity]# kubectl create -f performance.yaml deployment.apps/my-app created
查看pod部署的节点情况,可以看到pod部署在node节点上,没有在master节点:
9.8控制Pod在集群拓扑域中均分的分布 如果你的目标是 “让 Pod 尽量均匀地分散到不同拓扑域” ,更推荐用 Pod Topology Spread Constraints(Pod 拓扑分布约束) ,而不是主要依赖 Pod 亲和/反亲和。
两者的核心区别:
机制
更适合解决什么问题
是否能“均匀分散”
podAntiAffinity
不希望两个 Pod 出现在同一个拓扑域
可以间接实现,但控制不够精细
topologySpreadConstraints
控制不同拓扑域之间 Pod 数量差异
最适合
比如你的拓扑域是:
1 2 zone=beijing-haidian zone=beijing-chaoyang
你希望 4 个 Pod 最终变成:
这种需求应该优先用:
1 topologySpreadConstraints
而软反亲和可以做到“尽量分散”,但不如 topologySpreadConstraints精确,例如:
1 2 3 4 5 6 7 8 podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: my-app topologyKey: zone
这代表:调度器尽量避免把 Pod 放到已经有 my-app 的 zone。
所以 4 个 Pod 可能 接近:
但它只是一个调度偏好。
不能明确约束:
而 topologySpreadConstraints 可以,配置示例:
1 2 3 4 5 6 7 8 spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: my-app
topologySpreadConstraints:拓扑域约束配置,多个副本均匀分布在不同的域中
maxSkew:指定允许的最大偏差。例如,如果 maxSkew 设置为 1,那么在任何拓扑域 中,副本的数量最多只能相差 1
whenUnsatisfiable:指定当无法满足拓扑约束时的行为
DoNotSchedule:不允许调度新的 Pod,直到满足约束
ScheduleAnyway:即使不满足约束,也允许调度新的 Pod
topologyKey:指定拓扑域的键
labelSelector:指定要应用拓扑约束的 Pod 的标签选择器,通常配置为当前 Pod 的标 签
9.8应用均匀部署在不同的机房 Kubernetes 的 topologySpreadConstraints(拓扑域约束) 是一种高级的调度策略,用于确 保工作负载的副本在集群中的不同拓扑域(如节点、可用区、区域等)之间均匀分布。
节点规划如下:
1 2 3 region=beijing的有:k8s-master01,k8s-master02,k8s-node01,k8s-node02 zone=beijing-haidian的有:k8s-master01,k8s-node01,k8s-node02 zone=beijing-chaoyang的有:k8s-master02
需求时pod必须部署在beijing,并且在beijing-haidian和beijing-chaoyang之间均匀的分布
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 [root@k8s-master01 20 -affinity ] apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 8 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: region operator: In values: - beijing topologySpreadConstraints: - maxSkew: 1 topologyKey: zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: my-app containers: - name: app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
创建资源:
1 2 [root@k8s-master01 20-affinity]# kubectl create -f spread.yaml deployment.apps/my-app created
查看pod分布情况,可以看到8个副本的pod在zone=beijing-chaoyang的k8s-master02节点上部署了4个,而另外4个副本分散在zone=beijing-haidian节点上,只是zone=beijing-chaoyang的节点就一个,但是按照zone来均匀分散的目的已经完成。