纵我不往,子宁不来? ——《郑风·子衿》
写在前面
分享一些 k8s 跨集群节点均匀分布Pod 的笔记
博文内容涉及:
pod 调度 && 拓扑分布约束 简单介绍
跨节点均匀分布 pod Demo && 相关配置字段说明
多个拓扑分布约束 Demo
有冲突拓扑分布约束 Demo
理解不足小伙伴帮忙指正
纵我不往,子宁不来? ——《郑风·子衿》
Pod 调度的简单介绍 在 k8s 中 通过 kube-scheduler
组件来实现 pod 的调度,所谓调度,即把需要创建的 pod 放到 合适的 node 上,大概流程为,通过对应的 调度算法
和 调度策略
,为待调度的 pod 列表中的 pod 选择一个最合适的 Node,然后目标节点上的 kubelet
通过 watch 接口监听到 kube-schedule
产生的 Pod 绑定事件
,通过 APIService 获取对应的 Pod 清单,下载 image 并且启动容器。
这里具体的 调度算法
大体上分两步,筛选出候选节点,确定最优节点,确定最优节点涉及节点打分等。
常见的 Pod 的 调度策略
有 选择器、指定节点、主机亲和性
方式,同时需要考虑节点的 coedon
与drain
标记,今天和小伙伴分享的是 调度策略
的一种, 即通过 Pod拓扑分布约束
,用来实现 跨集群节点均匀调度分布Pod
为什么需要跨集群节点 均匀调度分布 Pod ? 我们知道在 k8s 中 ,如果只是希望每个节点均匀调度分布一个 pod,那么可以利用 DaemonSet
来实现。如果多个,就需要 pod 的拓扑分布约束均匀调度 Pod ,实现在集群中均匀分布 Pod,可以尽可能的利用 节点的超售,Pod 的超用,以实现高可用性和高效的集群资源利用。
k8s 中通过 Pod 拓扑分布约束(PodTopologySpread)来实现均匀调度 pod。这一特性从 v1.19 以后达到稳定状态。在 v1.25,v1.1.26 的版本中添加的部分属性。
需要说明的是,这里的 均匀调度 pod 不是说 只有对当前需要调度的 pod 在 工作节点发生均匀调度,不考虑当前节点上之前存在的 pod , 而是基于 工作节点的 均匀调度。即所谓均匀调度分布是基于工作节点的。虽然 pod 的拓扑分布约束是定义在 pod 上的。
当前集群版本为 v1.22,所以只有部分字段
1 2 3 4 5 6 7 8 ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$kubectl get nodes NAME STATUS ROLES AGE VERSION vms155.liruilongs.github.io Ready <none> 54d v1.22.2 vms156.liruilongs.github.io Ready <none> 54d v1.22.2 vms81.liruilongs.github.io Ready control-plane,master 378d v1.22.2 vms82.liruilongs.github.io Ready <none> 378d v1.22.2 vms83.liruilongs.github.io Ready <none> 378d v1.22.2
通过帮助手册可以简单了解下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$kubectl explain pod.spec.topologySpreadConstraints KIND: Pod VERSION: v1 RESOURCE: topologySpreadConstraints <[]Object> DESCRIPTION: TopologySpreadConstraints describes how a group of pods ought to spread across topology domains. Scheduler will schedule pods in a way which abides by the constraints. All topologySpreadConstraints are ANDed. TopologySpreadConstraint specifies how to spread matching pods among the given topology. 。。。。。
如何实现跨节点均匀分布 Pod 在 定义 Pod 的 yaml 资源文件中,可以定义一个或多个 topologySpreadConstraints
条目以指导 kube-scheduler
如何将每个新来的 Pod 与跨集群的现有 Pod 相关联。从而实现 Pod 的 均匀调度,这些字段包括(1.22 版本)
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: Pod metadata: name: example-pod spec: topologySpreadConstraints: - maxSkew: <integer> topologyKey: <string> whenUnsatisfiable: <string> labelSelector: <object>
在最新的版本中提供了其他的一些字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 --- apiVersion: v1 kind: Pod metadata: name: example-pod spec: topologySpreadConstraints: - maxSkew: <integer> minDomains: <integer> topologyKey: <string> whenUnsatisfiable: <string> labelSelector: <object> matchLabelKeys: <list> nodeAffinityPolicy: [Honor|Ignore ] nodeTaintsPolicy: [Honor|Ignore ]
具体通过这些字段如何配置,先来看一个 Demo
pod 拓扑约束依赖于 节点标签
来识别每个工作节点的所在的 拓扑域
。这里为了以均匀的方式在所有集群工作节点上均匀的分布 Pod,我们使用 k8s 集群默认自带的 节点主机名节点标签
作为拓扑域,可以保证每个节点都在自己唯一的拓扑域中。
拓扑约束会基于指定的标签来做为拓扑域,这里通过 kubernetes.io/hostname
的 values 作为 拓扑域。
1 2 3 4 5 6 7 8 9 10 ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$kubectl get node --label-columns kubernetes.io/hostname NAME STATUS ROLES AGE VERSION HOSTNAME vms155.liruilongs.github.io Ready <none> 54d v1.22.2 vms155.liruilongs.github.io vms156.liruilongs.github.io Ready <none> 54d v1.22.2 vms156.liruilongs.github.io vms81.liruilongs.github.io Ready control-plane,master 378d v1.22.2 vms81.liruilongs.github.io vms82.liruilongs.github.io Ready <none> 378d v1.22.2 vms82.liruilongs.github.io vms83.liruilongs.github.io Ready <none> 378d v1.22.2 vms83.liruilongs.github.io ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$
spec.topologySpreadConstaints
定义为
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: Pod metadata: name: example-pod spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: ScheduleAnyway labelSelector: <object>
涉及多 pod 调度,所以我们需要创建一个 deploy ,同时创建一个 命名空间。具体的资源文件
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 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$cat liruilong-topo-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: liruilong-topo-namespace ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$cat deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: liruilong spec: replicas: 10 template: spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app: liruilong containers: - name: pause image: registry.aliyuncs.com/google_containers/pause:3.5
为了方便 Demo ,我们使用 kustomize
来整合 yaml 文件。并且配置一个通用的标签。
1 2 3 4 5 6 7 8 9 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$cat kustomization.yaml namespace: liruilong-topo-namespace commonLabels: app: liruilong resources: - liruilong-topo-namespace.yaml - deploy.yaml
生成的 yaml 文件为:
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 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl kustomize ./ apiVersion: v1 kind: Namespace metadata: labels: app: liruilong name: liruilong-topo-namespace --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: liruilong name: liruilong namespace: liruilong-topo-namespace spec: replicas: 10 selector: matchLabels: app: liruilong template: metadata: labels: app: liruilong spec: containers: - image: registry.aliyuncs.com/google_containers/pause:3.5 name: pause topologySpreadConstraints: - labelSelector: matchLabels: app: liruilong maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: ScheduleAnyway
应用生成的 yaml 文件,为了方便,顺便切一下命名空间
1 2 3 4 5 6 7 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl apply -k ./ namespace/liruilong-topo-namespace created deployment.apps/liruilong created ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl config set-context $(kubectl config current-context) --namespace=liruilong-topo-namespace Context "kubernetes-admin@kubernetes" modified.
查看 pod 分布,master 节点设置了污点,所以不调度,剩下的 4 个 工作节点,上面的副本数为 10
,所以均匀分布为 [ 2 2 3 3 ] ,这里实际上是利用了 whenUnsatisfiable: ScheduleAnyway
的配置,即不管如何都会发生调度,因为 master 上没有调度,所有是 0,但是其他节点为 2,3 即 不符合 maxSkew
设置的 1
,简单理解 maxSkew
即 pod 在节点分布的差值不能超过的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liruilong-547cf79f6f-2mw8f 1/1 Running 0 8m2s 10.244.171.150 vms82.liruilongs.github.io <none> <none> liruilong-547cf79f6f-4b687 1/1 Running 0 8m2s 10.244.217.21 vms155.liruilongs.github.io <none> <none> liruilong-547cf79f6f-68nmv 1/1 Running 0 8m2s 10.244.70.60 vms83.liruilongs.github.io <none> <none> liruilong-547cf79f6f-8n8zc 1/1 Running 0 8m2s 10.244.171.191 vms82.liruilongs.github.io <none> <none> liruilong-547cf79f6f-cgk9k 1/1 Running 0 8m2s 10.244.70.27 vms83.liruilongs.github.io <none> <none> liruilong-547cf79f6f-gpx4l 1/1 Running 0 8m2s 10.244.217.22 vms155.liruilongs.github.io <none> <none> liruilong-547cf79f6f-j4rk7 1/1 Running 0 8m2s 10.244.194.77 vms156.liruilongs.github.io <none> <none> liruilong-547cf79f6f-t4fhr 1/1 Running 0 8m2s 10.244.194.76 vms156.liruilongs.github.io <none> <none> liruilong-547cf79f6f-wndvb 1/1 Running 0 8m2s 10.244.194.78 vms156.liruilongs.github.io <none> <none> liruilong-547cf79f6f-zjnp9 1/1 Running 0 8m2s 10.244.217.20 vms155.liruilongs.github.io <none> <none> ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
需要注意的是,缩减 Deployment 并不能保证均匀分布
,并可能导致 Pod 分布不平衡。但是可以使用 Descheduler
,或者销毁重建的方式重新平衡 Pod 分布。看下 Demo
这是添加一个补丁文件,修改副本数为 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$cat increase_replicas.yaml apiVersion: apps/v1 kind: Deployment metadata: name: liruilong spec: replicas: 4 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$cat kustomization.yaml namespace: liruilong-topo-namespace commonLabels: app: liruilong resources: - liruilong-topo-namespace.yaml - deploy.yaml patchesStrategicMerge: - increase_replicas.yaml
重新应用,会发现 pod
的调度完全变成了非均匀,即缩减 副本数并不会发生重新的 Pod 均匀分布。
1 2 3 4 5 6 7 8 9 10 11 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl apply -k ./ namespace/liruilong-topo-namespace unchanged deployment.apps/liruilong configured ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liruilong-547cf79f6f-2mw8f 1/1 Running 0 32m 10.244.171.150 vms82.liruilongs.github.io <none> <none> liruilong-547cf79f6f-68nmv 1/1 Running 0 32m 10.244.70.60 vms83.liruilongs.github.io <none> <none> liruilong-547cf79f6f-8n8zc 1/1 Running 0 32m 10.244.171.191 vms82.liruilongs.github.io <none> <none> liruilong-547cf79f6f-cgk9k 1/1 Running 0 32m 10.244.70.27 vms83.liruilongs.github.io <none> <none>
这要如果希望均匀分布,要不使用工具,要不只能重新部署,下面为重新部署
1 2 3 4 5 6 7 8 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl delete -k ./ namespace "liruilong-topo-namespace" deleted deployment.apps "liruilong" deleted ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl apply -k ./ namespace/liruilong-topo-namespace created deployment.apps/liruilong created
重新部署可以发现 pod 均匀分布,四个工作节点各部署一个 [1 1 1 1]
。
1 2 3 4 5 6 7 8 9 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liruilong-547cf79f6f-25c4b 1/1 Running 0 4s 10.244.171.180 vms82.liruilongs.github.io <none> <none> liruilong-547cf79f6f-2qhmh 1/1 Running 0 4s 10.244.217.25 vms155.liruilongs.github.io <none> <none> liruilong-547cf79f6f-8qmbc 1/1 Running 0 4s 10.244.194.81 vms156.liruilongs.github.io <none> <none> liruilong-547cf79f6f-gbw9f 1/1 Running 0 4s 10.244.70.23 vms83.liruilongs.github.io <none> <none> ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
修改节副本数为 8 ,可以看到当前 pod 分布为 [ 2 2 2 2 ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$vim increase_replicas.yaml ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl apply -k ./ namespace/liruilong-topo-namespace unchanged deployment.apps/liruilong configured ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liruilong-547cf79f6f-25c4b 1/1 Running 0 85s 10.244.171.180 vms82.liruilongs.github.io <none> <none> liruilong-547cf79f6f-2qhmh 1/1 Running 0 85s 10.244.217.25 vms155.liruilongs.github.io <none> <none> liruilong-547cf79f6f-8qmbc 1/1 Running 0 85s 10.244.194.81 vms156.liruilongs.github.io <none> <none> liruilong-547cf79f6f-b9swn 1/1 Running 0 6s 10.244.171.187 vms82.liruilongs.github.io <none> <none> liruilong-547cf79f6f-dqxw5 1/1 Running 0 6s 10.244.70.15 vms83.liruilongs.github.io <none> <none> liruilong-547cf79f6f-gbw9f 1/1 Running 0 85s 10.244.70.23 vms83.liruilongs.github.io <none> <none> liruilong-547cf79f6f-js8ft 1/1 Running 0 6s 10.244.217.26 vms155.liruilongs.github.io <none> <none> liruilong-547cf79f6f-vnxhd 1/1 Running 0 6s 10.244.194.82 vms156.liruilongs.github.io <none> <none> ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
具体的字段解释 1 2 3 4 5 6 7 topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app: liruilong
maxSkew
:描述这些 Pod 可能被均匀分布的程度。你必须指定此字段且该数值必须大于零。 其语义将随着 whenUnsatisfiable 的值发生变化:简单来讲,就是如果为均匀分布,那么两个节点之前的 pod 差值最大可以为多大。
如果你选择 whenUnsatisfiable: DoNotSchedule
,则 maxSkew 定义目标拓扑中匹配 Pod 的数量与 全局最小值之间的最大允许差值。例如,如果你有 3 个可用区,分别有 2、2 和 1 个匹配的 Pod,则 MaxSkew 设为 1, 且全局最小值为 1。
如果你选择 whenUnsatisfiable: ScheduleAnyway
,则该调度器会更为偏向能够降低偏差值的拓扑域。
topologyKey
:是节点标签的键。如果节点使用此键标记并且具有相同的标签值
, 则将这些节点视为处于同一拓扑域
中。我们将拓扑域中(即键值对)的每个实例称为一个域
。 调度器将尝试在每个拓扑域中放置数量均衡
的 Pod。 另外,我们将符合条件的域定义为其节点满足 nodeAffinityPolicy
和 nodeTaintsPolicy
要求的域。当 topologyKey
的值为 none
的时候。
whenUnsatisfiable
: 指示如果 Pod 不满足分布约束时如何处理:
DoNotSchedule(默认)告诉调度器不要调度。
ScheduleAnyway 告诉调度器仍然继续调度,只是根据如何能将偏差最小化来对节点进行排序。
labelSelector
: 用于查找匹配的 Pod。匹配此标签的 Pod 将被统计,以确定相应拓扑域中 Pod 的数量
当 Pod 定义了不止一个 topologySpreadConstraint
,这些约束之间是逻辑与
的关系。 kube-scheduler 会为新的 Pod 寻找一个能够满足所有约束的节点。
多个拓扑分布约束 在这之前需要做一些准备工作,在每个工作节点上在打一个标签 disktype=node-group1
。作为新的拓扑域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl label node vms82.liruilongs.github.io disktype=node-group1 --overwrite node/vms82.liruilongs.github.io labeled ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl label node vms83.liruilongs.github.io disktype=node-group1 --overwrite node/vms83.liruilongs.github.io labeled ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl label node vms155.liruilongs.github.io disktype=node-group2 --overwrite node/vms155.liruilongs.github.io labeled ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl label node vms156.liruilongs.github.io disktype=node-group2 --overwrite node/vms156.liruilongs.github.io labeled ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get node --label-columns disktype NAME STATUS ROLES AGE VERSION DISKTYPE vms155.liruilongs.github.io Ready <none> 55d v1.22.2 node-group2 vms156.liruilongs.github.io Ready <none> 55d v1.22.2 node-group2 vms81.liruilongs.github.io Ready control-plane,master 379d v1.22.2 vms82.liruilongs.github.io Ready <none> 379d v1.22.2 node-group1 vms83.liruilongs.github.io Ready <none> 379d v1.22.2 node-group1 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
当前集群的 pod 在 4 个工作节点的分布, [0 1 1 1]
1 2 3 4 5 6 7 8 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liruilong-744498fcbd-4z7l4 1/1 Running 0 7h32m 10.244.70.34 vms83.liruilongs.github.io <none> <none> liruilong-744498fcbd-jpngw 1/1 Running 0 7h32m 10.244.217.27 vms155.liruilongs.github.io <none> <none> liruilong-744498fcbd-vt9gb 1/1 Running 0 7h32m 10.244.194.86 vms156.liruilongs.github.io <none> <none> ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
这里添加一个新的 Pod ,添加了两个拓扑分布约束,要求这个 pod 即在 topologyKey: kubernetes.io/hostname
的拓扑域,同时在 topologyKey: disktype
的拓扑域
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 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$cat two-constrains.yaml kind: Pod apiVersion: v1 metadata: name: mypod labels: app: liruilong spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: liruilong - maxSkew: 1 topologyKey: disktype whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: liruilong containers: - name: pause image: registry.aliyuncs.com/google_containers/pause:3.5
应用上面的 yaml 文件, pod 调度到了 82 节点,当前的 pod 分布为 [1 1 1 1]
1 2 3 4 5 6 7 8 9 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liruilong-744498fcbd-4z7l4 1/1 Running 0 8h 10.244.70.34 vms83.liruilongs.github.io <none> <none> liruilong-744498fcbd-jpngw 1/1 Running 0 8h 10.244.217.27 vms155.liruilongs.github.io <none> <none> liruilong-744498fcbd-vt9gb 1/1 Running 0 8h 10.244.194.86 vms156.liruilongs.github.io <none> <none> mypod 1/1 Running 0 39m 10.244.171.178 vms82.liruilongs.github.io <none> <none> ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
现在把 82 节点的 拓扑域标签去掉,即 80 节点不属于 disktype
约束的拓扑域。
1 2 3 4 5 6 7 8 9 10 11 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl label node vms82.liruilongs.github.io disktype- node/vms82.liruilongs.github.io unlabeled ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get node --label-columns disktype NAME STATUS ROLES AGE VERSION DISKTYPE vms155.liruilongs.github.io Ready <none> 55d v1.22.2 node-group2 vms156.liruilongs.github.io Ready <none> 55d v1.22.2 node-group2 vms81.liruilongs.github.io Ready control-plane,master 379d v1.22.2 vms82.liruilongs.github.io Ready <none> 379d v1.22.2 vms83.liruilongs.github.io Ready <none> 379d v1.22.2 node-group1
删除上面的 pod 重新应用 yaml 文件,这时候 82 节点已不满足多拓扑分布的约束。可以看到 pod 调度到了 83 节点.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl delete -f two-constrains.yaml pod "mypod" deleted ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl apply -f two-constrains.yaml pod/mypod created ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liruilong-744498fcbd-4z7l4 1/1 Running 0 8h 10.244.70.34 vms83.liruilongs.github.io <none> <none> liruilong-744498fcbd-jpngw 1/1 Running 0 8h 10.244.217.27 vms155.liruilongs.github.io <none> <none> liruilong-744498fcbd-vt9gb 1/1 Running 0 8h 10.244.194.86 vms156.liruilongs.github.io <none> <none> mypod 1/1 Running 0 8s 10.244.70.33 vms83.liruilongs.github.io <none> <none> ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
有冲突的拓扑分布约束 如果所有节点都不满足 pod 的 拓扑分布约束,当前 pod 就会调度失败。下面为创建了一个新的补丁文件,修改副本数为 5,使用 kubernetes.io/hostname
作为拓扑域
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 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl kustomize ./ apiVersion: v1 kind: Namespace metadata: labels: app: liruilong name: liruilong-topo-namespace --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: liruilong name: liruilong namespace: liruilong-topo-namespace spec: replicas: 5 selector: matchLabels: app: liruilong template: metadata: labels: app: liruilong spec: containers: - image: registry.aliyuncs.com/google_containers/pause:3.5 name: pause topologySpreadConstraints: - labelSelector: matchLabels: app: liruilong maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule
当前 whenUnsatisfiable: DoNotSchedule
,即不满足约束时,不发生调度, master 有污点,默认不发生调度,所以当 副本数为 5 的时候,工作节点各调度一个,剩下的一个 pod 调度到哪里都会违反 maxSkew: 1
,所以发生 pending 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl apply -k ./ namespace/liruilong-topo-namespace created deployment.apps/liruilong created ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liruilong-744498fcbd-22c56 1/1 Running 0 76s 10.244.194.89 vms156.liruilongs.github.io <none> <none> liruilong-744498fcbd-7vn7r 1/1 Running 0 76s 10.244.70.61 vms83.liruilongs.github.io <none> <none> liruilong-744498fcbd-8d9jq 0/1 Pending 0 76s <none> <none> <none> <none> liruilong-744498fcbd-8zh7q 1/1 Running 0 76s 10.244.171.157 vms82.liruilongs.github.io <none> <none> liruilong-744498fcbd-rhtg5 1/1 Running 0 76s 10.244.217.28 vms155.liruilongs.github.io <none> <none> ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
可以通过日志查看详细信息
1 2 3 4 5 6 7 8 9 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl describe pods liruilong-744498fcbd-8d9jq | grep -A 10 -i events Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 6m23s default-scheduler 0/5 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 4 node(s) didn' t match pod topology spread constraints. Warning FailedScheduling 4m22s (x1 over 5m22s) default-scheduler 0/5 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 4 node(s) didn' t match pod topology spread constraints. ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
事件中提示: 1 个节点有污点{node-role.kubernetes.io/master: },该 pod 不能容忍,4 个节点不符合 pod 拓扑结构的传播限制。
同样的,如果我们把 master 节点 排除出拓扑区域,那么就可以满足 maxSkew: 1
,可以看到 同样的资源。调度成功发生。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl label node vms81.liruilongs.github.io kubernetes.io/hostname- node/vms81.liruilongs.github.io unlabeled ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl delete -k ./ namespace "liruilong-topo-namespace" deleted deployment.apps "liruilong" deleted ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl apply -k ./ namespace/liruilong-topo-namespace created deployment.apps/liruilong created ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liruilong-744498fcbd-5vbmz 1/1 Running 0 5s 10.244.171.143 vms82.liruilongs.github.io <none> <none> liruilong-744498fcbd-cxlxm 1/1 Running 0 5s 10.244.70.37 vms83.liruilongs.github.io <none> <none> liruilong-744498fcbd-hzgpr 1/1 Running 0 5s 10.244.194.90 vms156.liruilongs.github.io <none> <none> liruilong-744498fcbd-nk858 1/1 Running 0 5s 10.244.194.91 vms156.liruilongs.github.io <none> <none> liruilong-744498fcbd-x2pv2 1/1 Running 0 5s 10.244.217.29 vms155.liruilongs.github.io <none> <none> ┌──[root@vms81.liruilongs.github.io]-[~/ansible/podtopolog] └─$
拓扑分布约束在实际的使用过程中还要考虑其他的调度策略,比如选择器,节点亲和性等,感兴趣小伙伴可以到官网了解下,关于 pod 通过拓扑分布约束实现的 跨节点的均匀分布 pod 就可以小伙伴们分享到这里,生活加油。 ^_^
博文参考
https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/pod-priority-preemption/
https://medium.com/geekculture/kubernetes-distributing-pods-evenly-across-cluster-c6bdc9b49699