介绍PodTopologySpread

作者: 黄炜(IBM),奥尔多·卡尔奎孔多(Google)

在整个集群中管理Pod分发非常困难。著名的Kubernetes Pod亲和力和反亲和力功能,可对Pod放置进行一些控制 在不同的拓扑中。但是,这些功能只能解决部分Pod 分发用例:将无限Pod放置到单个拓扑中,或 不允许两个Pod共同位于同一拓扑中。在这两者之间 在极端情况下,通常需要将Pod在整个 拓扑,以实现更好的群集利用率和高可用性 applications.

PodTopologySpread调度插件(最初建议为EvenPodsSpread) 旨在填补这一空白。我们在1.18中将其提升为Beta。

API 变更

A new field topologySpreadConstraints is introduced in the Pod's spec API :

spec:
  topologySpreadConstraints:
  - maxSkew: <integer>
    topologyKey: <string>
    当不满意: <string>
    labelSelector: <object>

由于此API已嵌入Pod的规范中,因此您可以在所有 高级工作负载API,例如Deployment,DaemonSet,StatefulSet等。

让我们看一个集群示例,以了解此API。

API

  • labelSelector 用于查找匹配的Pod。对于每种拓扑,我们计算 与此标签选择器匹配的Pod数。在上面的例子中,给出 labelSelector为“ app:foo”,“ zone1”中的匹配数为2;而 “ zone2”中的数字为0。
  • topologyKey 是在“节点”标签中定义拓扑的键。在 在上面的示例中,如果某些节点具有标签,则将它们分组为“ zone1” “ zone = zone1”标签;而其他的则分组为“ zone2”。
  • maxSkew 描述Pod可以最大程度地达到不均匀的程度 分散式。在上面的示例中:
    • 如果我们将传入的Pod放入“ zone1”,则“ zone1”上的时滞将变为3(3 与“ zone1”匹配的广告连播;在“ zone2”上匹配的0个Pod的全局最小值), 违反了“ maxSkew:1”约束。
    • 如果将传入Pod放置到“ zone2”,则“ zone2”上的时滞为0(1 Pod 在“ zone2”中匹配; 1个Pod的全局最小值与“ zone2”本身匹配), 满足“ maxSkew:1”约束。请注意,偏斜为 计算每个合格节点,而不是全局偏斜。
  • 当不满意 指定当不能满足“ maxSkew”时,什么 应该采取的行动:
    • DoNotSchedule (默认值)告诉调度程序不要调度它。它是 hard constraint.
    • ScheduleAnyway 告诉调度程序在优先级排序时仍然调度它 减少偏斜的节点。这是一个软约束。

高级用法

正如功能名称“ PodTopologySpread”所暗示的,此功能的基本用法 是以绝对平均的方式(maxSkew = 1)或相对 even manner (maxSkew>=2). See the 官方 document更多细节。

除了这种基本用法之外,还有一些高级用法示例 使您的工作负载受益于高可用性和群集利用率。

与NodeSelector / NodeAffinity一起使用

您可能发现我们没有“ topologyValues”字段来限制 Pod将要安排的拓扑。默认情况下, 搜索所有节点并按“ topologyKey”将其分组。有时这可能不是 理想情况。例如,假设有一个集群,其节点标记为 “ env = prod”,“ env = staging”和“ env = qa”,现在您想将Pod均匀地放置到 跨区域的“ qa”环境,是否可能?

答案是肯定的。您可以利用NodeSelector或NodeAffinity API 规范。 在后台,PodTopologySpread功能将 荣誉 并计算 满足选择器的节点之间的传播约束。

Advanced-Usage-1

As illustrated above, you can specify spec.affinity.nodeAffinity to limit the 将“搜索范围”设置为“ qa”环境,在该范围内, 调度到一个满足topologySpreadConstraints的区域。在这个 case, it's "zone2".

多个拓扑扩展约束

了解一个拓扑拓朴约束的工作原理很直观。 多个TopologySpreadConstraints是什么情况?在内部,每个 TopologySpreadConstraint是独立计算的,结果集将 合并以生成最终结果集-即合适的节点。

在下面的示例中,我们想将Pod调度到具有2的集群 同时要求:

  • 将Pod与Pod跨区域均匀放置
  • 跨节点将Pod和Pod均匀放置

Advanced-Usage-2

对于第一个约束,zone1中有3个Pod,zone2中有2个Pod,因此 只能将传入的Pod放入zone2以满足“ maxSkew = 1”的约束。在 换句话说,结果集是nodeX和nodeY。

对于第二个约束,nodeB和nodeX中的Pod太多,因此 传入的Pod只能放入nodeA和nodeY。

现在我们可以得出结论,唯一合格的节点是nodeY-从 {nodeX,nodeY}(来自第一个约束)和{nodeA,nodeY}(来自 second constraint).

多个TopologySpreadConstraints功能强大,但请务必了解 与前面的“ NodeSelector / NodeAffinity”示例的区别:一个是 独立计算结果集,然后相互关联;而另一个是 根据节点的过滤结果计算topologySpreadConstraints constraints.

您可以在所有topologySpreadConstraints中使用“硬”约束,而不必 还结合使用“硬”约束和“软”约束来遵守更多 不同的集群情况。

注意: 如果将两个TopologySpreadConstraints应用于同一{topologyKey, 当不满意}元组时,Pod的创建将被阻止,返回一个 validation error.

PodTopologySpread默认值

PodTopologySpread是Pod级别的API。因此,要使用功能,工作量 作者需要了解集群的基础拓扑,然后 specify proper topologySpreadConstraints in the Pod spec for every workload. 虽然Pod级API提供了最大的灵活性,但也有可能 指定集群级别的默认值。

默认的PodTopologySpread约束允许您为所有对象指定传播 为集群量身定制的拓扑结构。约束可以是 由操作员/管理员在PodTopologySpread插件参数中指定 计划配置文件配置 API 启动时 kube-scheduler.

配置示例如下所示:

apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
profiles:
  pluginConfig:
  - name: PodTopologySpread
    args:
      defaultConstraints:
      - maxSkew: 1
        topologyKey: example.com/rack
        当不满意: ScheduleAnyway

配置默认约束时,标签选择器必须保留为空。 kube-scheduler将从Pod的成员推断标签选择器 服务,ReplicationControllers,副本集或StatefulSet。豆荚可以 始终通过提供自己的默认约束来覆盖默认约束 PodSpec.

注意: 使用默认的PodTopologySpread约束时,建议禁用 旧的DefaultTopologySpread插件。

包起来

PodTopologySpread允许您为工作负载定义扩展约束 具有灵活且富有表现力的Pod级API。过去,工作量作者使用 Pod AntiAffinity规则强制或提示调度程序每个运行一个Pod 拓扑域。相反,新的PodTopologySpread约束允许Pod 指定可能需要(硬)或需要(软)的偏斜级别。的 功能可以与节点选择器和节点相似性配对以限制 传播到特定领域。可以为 不同的拓扑,例如主机名,区域,区域,机架等。

最后,集群运营商可以定义默认约束以应用于所有 豆荚。这样,Pods无需知道其基础拓扑 cluster.