高可用性と高パフォーマンスは、分散ジョブにとって不可欠です。Container Service for Kubernetes (ACK) Pro クラスタまたは ACK Serverless Pro クラスタでは、Kubernetes ネイティブのスケジューリングセマンティクスに基づいて、分散タスクをゾーン全体に分散できます。また、Kubernetes ネイティブのスケジューリングセマンティクスに基づいてアフィニティを設定し、特定のゾーンに分散タスクをデプロイすることもできます。これにより、タスクデプロイの効率が向上します。このトピックでは、Elastic Container Instance ベースの Pod をゾーン全体に分散する方法と、Pod のアフィニティを設定する方法について説明します。
背景情報
特定のシナリオでは、高可用性または高パフォーマンスを実現するために、複数のゾーンまたは特定のゾーンに Pod をデプロイする必要があります。このような場合は、Pod トポロジスプレッド制約 (topologySpreadConstraints
)、ノードアフィニティ (nodeAffinity
)、Pod アフィニティ (podAffinity
) などの Kubernetes ネイティブのスケジューリング機能を使用できます。
Elastic Container Instance ベースの Pod をゾーン全体に分散したり、Pod のアフィニティを設定したりできるのは、nodeAffinity
、podAffinity
、topologySpreadConstraints
パラメータが Pod に設定されている場合、または Pod が既存のリソースポリシーと一致する場合のみです。
詳細については、次の Kubernetes 公式ドキュメントを参照してください。
前提条件
ACK Pro クラスタまたは ACK Serverless Pro クラスタ が作成されており、クラスタが次の要件を満たしていること。
クラスタの Kubernetes バージョンが 1.22 以降であること。
クラスタ内の ACK 仮想ノード コンポーネントのバージョンが 2.10.0 以降であること。
クラスタ内の kube-scheduler コンポーネントのバージョンが 5.9 以降であり、クラスタで仮想ノードベースの Pod スケジューリング機能が有効になっていること。詳細については、ACK クラスタの仮想ノードベースの Pod スケジューリングポリシーを有効にする を参照してください。
eci-profile で複数のゾーン (vSwitch) が指定されていること。Pod は複数のゾーンにスケジュールできます。詳細については、複数のゾーンを設定して Pod を作成する を参照してください。
使用上の注意
topologyKey
パラメータをtopology.kubernetes.io/zone
に設定する必要があります。このトピックで説明されている機能は、次のシナリオでは有効になりません。
k8s.aliyun.com/eci-schedule-strategy: "VSwitchOrdered"
アノテーションを使用して、指定された vSwitch 順序に従う複数ゾーンのスケジューリング戦略を Pod に宣言している場合。k8s.aliyun.com/eci-fail-strategy: "fail-fast"
アノテーションを使用して、Pod の障害処理ポリシーをfail-fast
に設定している場合。
設定例
以下のセクションでは、Kubernetes バージョンが 1.22 の ACK Serverless Pro クラスタを使用して、Pod をゾーン全体に分散する方法とアフィニティを設定する方法について説明します。
例 1: topologySpreadConstraints を使用して Pod をゾーン全体に分散する
次の例は、トポロジスプレッド制約を設定する方法を示しています。デフォルトでは、Scheduler はすべての Pod をすべてのゾーンに均等にスケジュールしますが、Pod の生成結果は考慮しません。詳細については、厳密な Elastic Container Instance ベースの Pod トポロジスプレッド を参照してください。
ワークロードの設定にトポロジスプレッド制約を追加します。
Pod の設定の
Spec
パラメータ、または Deployment や Job などのワークロードの設定のSpec
パラメータにトポロジスプレッド制約を指定するには、次の手順を実行します。topologySpreadConstraints: - maxSkew: <integer> minDomains: <integer> # このパラメータはオプションであり、Kubernetes 1.25 以降ではベータ段階です。 topologyKey: <string> whenUnsatisfiable: <string> labelSelector: <object> matchLabelKeys: <list> # このパラメータはオプションであり、Kubernetes 1.27 以降ではベータ段階です。 nodeAffinityPolicy: [Honor|Ignore] # このパラメータはオプションであり、Kubernetes 1.26 以降ではベータ段階です。 nodeTaintsPolicy: [Honor|Ignore] # このパラメータはオプションであり、Kubernetes 1.26 以降ではベータ段階です。
この例では、Pod が複数のゾーンに均等に分散される Deployment を作成します。パラメータの詳細については、topologySpreadConstraints field を参照してください。次のコードブロックは、Deployment の YAML テンプレートを示しています。
ワークロードを作成します。
deployment.yaml
という名前のファイルを作成し、上記の YAML テンプレートをファイルにコピーします。次に、次のコマンドを実行して、クラスタに Deployment を作成します。kubectl apply -f deployment.yaml
ワークロードのスケジューリング結果を確認します。
次のコマンドを実行して、Deployment が Pod をデプロイするノードをクエリします。
kubectl get po -lapp=with-pod-topology-spread -ocustom-columns=NAME:.metadata.name,NODE:.spec.nodeName --no-headers | grep -v "<none>"
次のコマンドを実行して、各ゾーンで Deployment によって作成された 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
例 2: nodeAffinity と podAffinity を使用して特定のゾーンに Pod をデプロイする
ワークロードの設定にアフィニティを追加します。
この例では、Pod が単一ゾーンにデプロイされる Deployment を作成します。パラメータの詳細については、Node affinity を参照してください。次のコードブロックは、Deployment の YAML テンプレートを示しています。
特定のゾーンに Pod をデプロイする場合は、
podAffinity
パラメータを削除し、nodeAffinity
パラメータに次の制約を追加します。次の設定では、Pod を北京ゾーン A にデプロイする必要があることを指定しています。requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - cn-beijing-a
次のコードブロックは、
nodeAffinity
パラメータを含むサンプルコードを示しています。Pod は北京ゾーン A にのみデプロイされます。ワークロードを作成します。
deployment.yaml
という名前のファイルを作成し、上記の YAML テンプレートをファイルにコピーします。次に、次のコマンドを実行して、クラスタに Deployment を作成します。kubectl apply -f deployment.yaml
ワークロードのスケジューリング結果を確認します。
次のコマンドを実行して、Deployment が Pod をデプロイするノードをクエリします。
kubectl get po -lapp=with-affinity -ocustom-columns=NAME:.metadata.name,NODE:.spec.nodeName --no-headers | grep -v "<none>"
次のコマンドを実行して、各ゾーンで Deployment によって作成された 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
厳密な Elastic Container Instance ベースの Pod トポロジスプレッド
デフォルトでは、Elastic Container Instance ベースの Pod をゾーン全体に強制的に分散する場合、kube-scheduler はワークロードの Pod をすべてのゾーンに均等にデプロイします。ただし、Elastic Container Instance ベースの Pod は一部のゾーンで作成に失敗する可能性があります。次の図は、maxSkew パラメータが 1 に設定されている場合のスケジューリング結果を示しています。maxSkew の詳細については、maxSkew を参照してください。
ゾーン B とゾーン C で Elastic Container Instance ベースの Pod の作成に失敗した場合、2 つの Elastic Container Instance ベースの Pod がゾーン A で実行され、ゾーン B またはゾーン C では Elastic Container Instance ベースの Pod は実行されません。これは、maxSkew パラメータで指定された制約に違反しています。
ACK Serverless Pro クラスタ では、厳密な Elastic Container Instance ベースの Pod トポロジスプレッドを有効にして、Pod がゾーン全体に厳密に分散されるようにすることができます。厳密な Elastic Container Instance ベースの Pod トポロジスプレッドを有効にすると、kube-scheduler はまず、ゾーン A、ゾーン B、ゾーン C のそれぞれに Pod をスケジュールします。kube-scheduler は、スケジュールされた Pod が作成されるまで、保留中の Pod をスケジュールしません。次の図を参照してください。
Pod A1 が作成された場合でも、保留中の Pod はスケジュールされません。これは、ゾーン B またはゾーン C で Pod の作成に失敗した場合、maxSkew パラメータで指定された制約に違反するためです。Pod B1 が作成されると、kube-scheduler はゾーン C に Pod をスケジュールします。緑色の網掛けが付いた Pod は作成されています。
厳密な Elastic Container Instance ベースの Pod トポロジスプレッドを無効にする場合は、whenUnsatisfiable
パラメータを ScheduleAnyway
に設定します。詳細については、Spread constraint definition を参照してください。