【问题标题】:K8s Pod Topology Spread is not respected after rollout?推出后不尊重 K8s Pod 拓扑扩展?
【发布时间】:2021-03-06 21:40:08
【问题描述】:

我正在尝试传播我的 ingress-nginx-controller 豆荚:

  • 每个可用区都有相同的 pod 数 (+- 1)。
  • Pod 更喜欢当前运行最少 Pod 的节点。

根据此处的其他问题,我在我的 pod 部署中设置了 Pod 拓扑传播约束:

      replicas: 4
      topologySpreadConstraints:
      - labelSelector:
          matchLabels:
            app.kubernetes.io/name: ingress-nginx
        maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
      - labelSelector:
          matchLabels:
            app.kubernetes.io/name: ingress-nginx
        maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: DoNotSchedule

我目前有 2 个节点,每个节点位于不同的可用区:

$ kubectl get nodes --label-columns=topology.kubernetes.io/zone,kubernetes.io/hostname
NAME                            STATUS   ROLES                  AGE    VERSION   ZONE         HOSTNAME
ip-{{node1}}.compute.internal   Ready    node                   136m   v1.20.2   us-west-2a   ip-{{node1}}.compute.internal
ip-{{node2}}.compute.internal   Ready    node                   20h    v1.20.2   us-west-2b   ip-{{node2}}.compute.internal

在为该部署运行 kubectl rollout restart 后,我在一个节点中获得 3 个 pod,在另一个节点中获得 1 个 pod,其偏差为 2 > 1

$ kubectl describe pod ingress-nginx-controller -n ingress-nginx | grep 'Node:'
Node:         ip-{{node1}}.compute.internal/{{node1}}
Node:         ip-{{node2}}.compute.internal/{{node2}}
Node:         ip-{{node1}}.compute.internal/{{node1}}
Node:         ip-{{node1}}.compute.internal/{{node1}}

为什么我的约束没有得到遵守?如何调试 pod 调度程序?

我的 kubectl 版本:

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"21+", GitVersion:"v1.21.0-beta.0.607+269d62d895c297", GitCommit:"269d62d895c29743931bfaaec6e8d37ced43c35f", GitTreeState:"clean", BuildDate:"2021-03-05T22:28:02Z", GoVersion:"go1.16", Compiler:"gc", Platform:"darwin/arm64"}
Server Version: version.Info{Major:"1", Minor:"20", GitVersion:"v1.20.2", GitCommit:"faecb196815e248d3ecfb03c680a4507229c2a56", GitTreeState:"clean", BuildDate:"2021-01-13T13:20:00Z", GoVersion:"go1.15.5", Compiler:"gc", Platform:"linux/amd64"}

【问题讨论】:

  • 我目前的理论是 Pod 传播拓扑也考虑了之前推出的 pod。在所有新的 Pod 运行后,k8s 会终止一些之前的 rollout Pod,这可能会导致不平衡。
  • 你能提供你的 pod yaml 吗?如果部署 yaml 甚至更好
  • @SahadatHossain 在这里,这是一个亚马逊 nginx-ingress 清单,编辑很少:gist.github.com/roim/64de522ec887409ad5c6cf4ac0343de0 我确实发现其他人描述了同样的问题:github.com/kubernetes/kubernetes/issues/98215 我能够通过扩展我的部署来获得正确的拓扑到 1 个副本,然后再到 4 个。如果推出后的不良拓扑确实是根本原因,我可能会考虑 Kubernetes 解调度器作为一种缓解措施。
  • @roim 你能告诉你你的集群是如何创建的吗?它是自我管理的解决方案还是提供商管理的解决方案(amazon nginx-ingress 是否有机会告诉这是EKS)?另外,作为一种解决方法,您是否考虑过使用Daemonset?不同之处在于,不是区域中的Pod,而是每个Node 上的Pod
  • @DawidKruk 集群是自托管的,使用 kOps 创建,我安装了 nginx-ingress 及其 AWS 官方清单 (kubernetes.github.io/ingress-nginx/deploy)。我会看看一个 Daemonset,这听起来很有希望

标签: kubernetes


【解决方案1】:

提高评论的可见度:

Daemonset 工作并且很简单。它不适用于我们每个节点有多个 pod 的部署,但是那里有缓解措施(调度程序),它应该随着集群的增长自行解决。

请将此答案视为一种解决方法

DaemonSet 确保所有(或部分)节点运行 Pod 的副本。 随着节点被添加到集群中,Pod 也被添加到其中。当从集群中删除节点时,这些 Pod 会被垃圾回收。删除 DaemonSet 将清理它创建的 Pod。

-- Kubernetes.io: Docs: Concepts: Workloads: Controllers: Daemonset

一个例子如下:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      name: nginx
  template:
    metadata:
      labels:
        name: nginx 
    spec:
      #nodeSelector: 
          #schedule: here 
      tolerations:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: nginx
        image: nginx

此定义将在集群中的每个 Node 上生成一个 Pod。您可以通过指定nodeSelector 来进一步限制Pod 调度。

假设您有一些控制器/逻辑负责使用特定标签标记节点,您可以在特定节点上安排Pods。负责它的部分在上面的清单中被注释掉了:

      nodeSelector: 
          schedule: here 

节点(raven-sgdmraven-xvvw 已标记)::

NAME         STATUS   ROLES    AGE    VERSION
raven-6k6m   Ready    <none>   159m   v1.20
raven-sgdm   Ready    <none>   159m   v1.20
raven-xvvw   Ready    <none>   159m   v1.20

Daemonset:

NAME    DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
nginx   2         2         2       2            2           schedule=here   99m

其他资源:

【讨论】:

  • 这是一个很好的解决方法,因为当前的 K8s 问题在您的 pod 数量较低时更为常见(类似于您选择的拓扑的基数),因此每个节点运行 1 个 pod 是有意义的。如果您因为每个节点需要多个 pod 而无法使用守护程序集,那么此处描述的问题可能无论如何都不适用。
【解决方案2】:

kubectl rollout restart 启动新的 pod,然后所有新的 pod 都启动并运行之后终止旧的 pod。

从 pod 拓扑传播约束 known limitations 部分来看,当 pod 被移除时,约束不会保持满足,现在推荐的缓解措施是使用 Descheduler ,您似乎已经从您的评论中使用了它。

【讨论】:

  • 将此作为公认的答案,因为它直接回答了我的问题。其他答案提供了解决方法,但仍然有用。
【解决方案3】:

在某个时刻,倾斜是正确的。

但是当要移除的 pod 将被移除时,倾斜可能会发生倾斜 :)

基本上你正面临here描述的限制:

Scaling down a Deployment may result in imbalanced Pods distribution.

我应用的一个简单解决方法是缩小规模 + 重新启动/部署 + 扩大规模

那么倾斜就完美了!

【讨论】:

  • 我认为,使用 OrderedReady StatefulSet 可以在缩减期间克服这个限制。对吗?
猜你喜欢
  • 2020-09-28
  • 1970-01-01
  • 2015-08-23
  • 1970-01-01
  • 2018-08-08
  • 1970-01-01
  • 2015-12-13
  • 2017-10-11
相关资源
最近更新 更多