首页 > 行业资讯 > K8s 如何实现跨集群节点均匀调度分布Pod(Pod拓扑分布约束)| 运维进阶

K8s 如何实现跨集群节点均匀调度分布Pod(Pod拓扑分布约束)| 运维进阶

时间:2023-12-04 来源: 浏览:

K8s 如何实现跨集群节点均匀调度分布Pod(Pod拓扑分布约束)| 运维进阶

山河已无恙 twt企业IT社区
twt企业IT社区

talkwithtrend

talkwithtrend.com社区(即twt社区)官方公众号,持续发布优秀社区原创内容。内容深度服务企业内各方向的架构师、运维主管、开发和运维工程师等IT专业岗位人群,让您时刻和国内企业IT同行保持信息同步。

收录于合集
【摘要】 本文进行k8s 跨集群节点均匀调度分布 Pod 的分享:包括 pod 调度&拓扑分布约束的简单介绍、跨节点均匀分布 pod Demo & 相关配置字段说明、多个拓扑分布约束 Demo、有冲突拓扑分布约束 Demo。

【作者】山河已无恙, RHCE、CKA认证,多家平台签约作者,持续分享云原生、Linux 方面的技术干货。兴趣是吃饭,喜欢吃饱了晒太阳。

Pod 调度的简单介绍

在 k8s 中 通过  kube-schedule r   组件来实现 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,所以只有部分字段

┌──[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

通过帮助手册可以简单了解下

┌──[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 版本)

apiVersion:   v1 kind:   Pod metadata:    name:   example-pod spec:    # 配置一个拓扑分布约束    topologySpreadConstraints:      -   maxSkew:   <integer>        topologyKey:   <string>        whenUnsatisfiable:   <string>        labelSelector:   <object>    ### 其他 Pod 字段置于此处

在最新的版本中提供了其他的一些字段

--- apiVersion:   v1 kind:   Pod metadata:    name:   example-pod spec:    # 配置一个拓扑分布约束    topologySpreadConstraints:      -   maxSkew:   <integer>        minDomains:   <integer>   # 可选;自从 v1.25 开始成为 Beta        topologyKey:   <string>        whenUnsatisfiable:   <string>        labelSelector:   <object>        matchLabelKeys:   <list>   # 可选;自从 v1.25 开始成为 Alpha        nodeAffinityPolicy:   [Honor|Ignore]   # 可选;自从 v1.26 开始成为 Beta        nodeTaintsPolicy:   [Honor|Ignore]   # 可选;自从 v1.26 开始成为 Beta    ### 其他 Pod 字段置于此处

具体通过这些字段如何配置,先来看一个 Demo

pod 拓扑约束依赖于  节点标签  来识别每个工作节点的所在的  拓扑域 。这里为了以均匀的方式在所有集群工作节点上均匀的分布 Pod,我们使用 k8s 集群默认自带的节点主机名节点标签作为拓扑域,可以保证每个节点都在自己唯一的拓扑域中。

拓扑约束会基于指定的标签来做为拓扑域,这里通过  kubernetes.io/hostname  的 values 作为拓扑域。

┌──[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 定义为

apiVersion:   v1 kind:   Pod metadata:    name:   example-pod spec:    # 配置一个拓扑分布约束    topologySpreadConstraints:      -   maxSkew:   1   # 以绝对均匀的方式分配 POD        topologyKey:   kubernetes.io/hostname   #使用主机名这个标签作为拓扑域        whenUnsatisfiable:   ScheduleAnyway   #始终调度 pod,即使它不能满足 pod 的均匀分布        labelSelector:   <object>   #作用于匹配这个选择器的 Pod    ### 其他 Pod 字段置于此处

涉及多 pod 调度,所以我们需要创建一个 deploy ,同时创建一个命名空间。具体的资源文件

┌──[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 文件。并且配置一个通用的标签。

┌──[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 文件为:

┌──[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 文件,为了方便,顺便切一下命名空间

┌──[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-admin126459646@kubernetes"  modified.

查看 pod 分布,master 节点设置了污点,所以不调度,剩下的 4 个工作节点,上面的副本数为 10,所以均匀分布为 [ 2 2 3 3 ] ,这里实际上是利用了 whenUnsatisfiable: ScheduleAnyway 的配置,即不管如何都会发生调度,因为 master 上没有调度,所有是 0,但是其他节点为 2,3 即不符合 maxSkew 设置的 1,简单理解 maxSkew 即 pod 在节点分布的差值不能超过的值。

┌──[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

┌──[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 均匀分布。

┌──[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>

这要如果希望均匀分布,要不使用工具,要不只能重新部署,下面为重新部署

┌──[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] 。

┌──[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 ]

┌──[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] └─$

具体的字段解释

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。作为新的拓扑域

┌──[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]

┌──[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 的拓扑域

┌──[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]

┌──[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 约束的拓扑域。

┌──[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 节点.

┌──[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 作为拓扑域

┌──[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 。

┌──[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] └─$

可以通过日志查看详细信息

┌──[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,可以看到 同样的资源。调度成功发生。

┌──[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://mediu m.com/geekculture/kubernetes-distributing-pods-evenly-across-cluster-c6bdc9b49699

欢迎点击文末 阅读原文 到社区原文下讨论交流

觉得本文有用,请 转发 或点击 ,让更多同行看到

 资料/文章推荐:

  • 容器云平台规划部署架构设计 | 周末送资料

  • K8S 需要多少台服务器?

  • 容器云平台监控架构设计及优化

  • Kubernetes 常见故障排查和处理

  • 容器常见故障排查处理和使用规范建议

  • 容器云平台如何进行日常巡检?| 运维进阶

欢迎关注社区  “容器云”技术主题  ,将会不断更新优质资料、文章。地址: https://www.talkwithtrend.com/Topic/98447

下载 twt 社区客户端 APP

长按识别二维码即可下载

或到应用商店搜索“twt”

长按二维码关注公众号

*本公众号所发布内容仅代表作者观点,不代表社区立场

版权:如无特殊注明,文章转载自网络,侵权请联系cnmhg168#163.com删除!文件均为网友上传,仅供研究和学习使用,务必24小时内删除。
相关推荐