高可用以及高性能是分布式任务执行过程中的重要要求。在ACK Pro版集群或ACK Serverless集群Pro版中,您可以通过Kubernetes原生调度语义实现分布式任务的跨可用区打散,以达到高可用区部署的要求,或者通过Kubernetes原生调度语义实现分布式任务在指定可用区中的亲和性部署,以达到高性能部署的要求。本文介绍如何实现ECI Pod可用区打散或亲和调度。
背景信息
在某些情况下,您可能需要将Pod分散部署到多个不同的可用区,或者部署到某个指定可用区,以实现高可用或者高性能的需求。此时,您可以通过Kubernetes原生调度语义中的Pod拓扑分布约束(topologySpreadConstraints)、节点亲和性(nodeAffinity)和Pod亲和性(podAffinity)来实现。
仅当Pod中带有nodeAffinity
、podAffinity
、topologySpreadConstraints
字段或存在匹配的ResourcePolicy时才会启用可用区打散或亲和调度。
更多信息,请参见Kubernetes官方文档:
前提条件
已有ACK Pro版集群或ACK Serverless集群Pro版,并且满足以下要求:
集群版本为1.22及以上。
集群中的ACK Virtual Node组件版本为v2.10.0及以上。
集群中的kube-scheduler组件版本为5.9及以上,并且已开启虚拟节点调度功能。更多信息,请参见开启集群虚拟节点调度策略。
已在eci-profile中配置多个期望调度的目标可用区(即配置多个交换机)。具体操作,请参见多可用区创建Pod。
注意事项
目前仅支持设置
topologyKey
为topology.kubernetes.io/zone
的用法。如果ECI Pod通过
k8s.aliyun.com/eci-schedule-strategy: "VSwitchOrdered"
的Annotation声明了多可用区调度策略为按照交换机的指定顺序,当前功能将不生效。如果ECI Pod通过
k8s.aliyun.com/eci-fail-strategy: "fail-fast"
的Annotation设置了Pod故障处理策略为fail-fast
,当前功能将不生效。
配置示例
下文将在1.22版本的ACK Serverless集群Pro版本集群中演示ECI Pod可用区打散和亲和调度功能。
示例一:通过topologySpreadConstraints实现可用区打散
以下为一个配置了拓扑打散约束的示例。默认情况下,Scheduler会将所有Pod均匀调度到所有可用区上,但并不会考虑Pod的生产结果。更多信息,请参见ECI严格拓扑打散功能介绍。
在工作负载声明中增加拓扑分布约束。
Pod的
Spec
字段中或Deployment、Job等工作负载的PodTemplate的Spec
字段中,可以通过以下方式声明一个拓扑分布约束。topologySpreadConstraints: - maxSkew: <integer> minDomains: <integer> # 可选,从v1.25开始成为Beta。 topologyKey: <string> whenUnsatisfiable: <string> labelSelector: <object> matchLabelKeys: <list> # 可选,从v1.27开始成为Beta。 nodeAffinityPolicy: [Honor|Ignore] # 可选,从v1.26开始成为Beta。 nodeTaintsPolicy: [Honor|Ignore] # 可选,从v1.26开始成为Beta。
本示例将创建一个在多个可用区上均匀分布的Deployment。关于参数的详细信息,请参见topologySpreadConstraints字段。以下为该Deployment的YAML文件。
创建工作负载。
将上面的代码保存为
deployment.yaml
,并执行以下命令将Deployment提交到集群中。kubectl apply -f deployment.yaml
验证工作负载调度结果。
通过以下命令查看生产出的Pod所在的节点。
kubectl get po -lapp=with-pod-topology-spread -ocustom-columns=NAME:.metadata.name,NODE:.spec.nodeName --no-headers | grep -v "<none>"
通过以下命令查看生产出的Pod在各个可用区中的数量。
kubectl get po -lapp=with-pod-topology-spread -ocustom-columns=NODE:.spec.nodeName --no-headers | grep -v "<none>" | xargs -I {} kubectl get no {} -ojson | jq '.metadata.labels["topology.kubernetes.io/zone"]' | sort | uniq -c
示例二:通过nodeAffinity和podAffinity实现可用区亲和
在工作负载声明中增加亲和性约束。
本示例将创建在单个可用区上聚集分布的Deployment。关于参数的详细信息,请参见节点亲和性。以下为该Deployment的YAML文件。
若您希望指定可用区进行部署,可以将示例中的
podAffinity
删去,在nodeAffinity
添加如下约束。下方约束表明Pod必须在可用区cn-beijing-a上进行部署。requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - cn-beijing-a
以下为
nodeAffinity
的完整示例,表明Pod必须在可用区cn-beijing-a上进行部署。创建工作负载。
将上面的代码保存为
deployment.yaml
,并执行以下命令将Deployment提交到集群中。kubectl apply -f deployment.yaml
验证工作负载调度结果。
通过以下命令查看生产出的Pod所在的节点。
kubectl get po -lapp=with-affinity -ocustom-columns=NAME:.metadata.name,NODE:.spec.nodeName --no-headers | grep -v "<none>"
通过以下命令查看生产出的Pod在各个可用区中的数量。
kubectl get po -lapp=with-affinity -ocustom-columns=NODE:.spec.nodeName --no-headers | grep -v "<none>" | xargs -I {} kubectl get no {} -ojson | jq '.metadata.labels["topology.kubernetes.io/zone"]' | sort | uniq -c
ECI严格拓扑打散功能介绍
在保持默认状态不变的情况下,当配置了强制打散约束时,Scheduler会将所有Pod均匀放置到所有可用区上,但并不考虑ECI Pod的生产结果。如下图所示,假设将打散功能的maxSkew设置为1。关于maxSkew,请参见maxSkew。
此时若可用区B和C中生产ECI Pod失败,则可用区A上会放置2个ECI Pod,其他两个可用区没有ECI Pod,从而破坏打散功能的maxSkew约束。
当严格拓扑打散功能开启后,在ACK Serverless集群Pro版中,调度器将严格保证Pod的强制打散需求得到满足。Scheduler会在可用区A、B、C上各放置1个Pod,剩下的Pod将处于Pending状态,等待现有Pod生产,如下图所示。
当PodA1生产成功后,Pending状态的Pod将继续Pending,这是由于可用区B以及可用区C上的ECI Pod仍然可能生产失败,Pod放置于任意可用区仍然可能导致生产结束后破坏maxSkew约束。当PodB1生产成功后,Scheduler将会放置一个Pod在可用区C。如下图所示,其中绿色背景的Pod为生产完成的Pod。
若您不需要严格拓扑打散功能,请将拓扑打散约束中的调度条件whenUnsatisfiable
设置为ScheduleAnyway
。详细信息,请参见分布约束定义。