すべてのプロダクト
Search
ドキュメントセンター

Container Service for Kubernetes:ECI Pod をゾーン間で分散配置し、アフィニティスケジューリングを設定する

最終更新日:Mar 26, 2026

あるゾーン内で ECI ベースの Pod の作成に失敗した場合、そのゾーンに集中しているすべてのレプリカが利用不可になります。この障害には、主に以下の 2 つのパターンがあります:スケジューリング時にすべてのレプリカが同一ゾーンに割り当てられること、および一部のゾーンで ECI の作成に失敗した際に、分散保証が静かに違反されることです。本トピックでは、ACK 管理型 Pro クラスターにおいて、Kubernetes のトポロジ分散制約(topology spread constraints)およびアフィニティルールを活用して、これらの問題を防止する方法について説明します。

前提条件

開始する前に、以下の条件を満たしていることを確認してください。

  • 以下の要件を満たす ACK 管理型 Pro クラスター:

  • eci-profile に複数のゾーン(vSwitch)が設定されており、Pod が複数ゾーンにわたってスケジュール可能であること

  • Pod の仕様(spec)に nodeAffinitypodAffinity、または topologySpreadConstraints フィールドが設定されていること、または Pod に対して ResourcePolicy が設定されていること

説明

ARM ベースの仮想ノードに Pod をスケジュールする場合は、当該ノードのテイントと一致する Toleration を追加してください。

注意事項

  • topologyKeytopology.kubernetes.io/zone に設定してください。

  • 以下の条件が満たされている場合、本トピックで説明するスケジューリング動作は適用されません。

    • Pod に k8s.aliyun.com/eci-schedule-strategy: "VSwitchOrdered" アノテーションが設定されている場合(マルチゾーンスケジューリングは固定の vSwitch 順序に従います)。

    • Pod に k8s.aliyun.com/eci-fail-strategy: "fail-fast" アノテーションが設定されている場合。

アプローチの選択

Kubernetes には、異なる目的に対応する 2 つのメカニズムがあります。

目的メカニズム使用タイミング
利用可能なすべてのゾーンに Pod を均等に分散配置するtopologySpreadConstraints高可用性 — ゾーン単位の障害発生時でも、影響を受けるレプリカ数を最小限に抑えるため
Pod を特定のゾーンに固定する、または Pod を同一ゾーン内に集約するpodAffinitynodeAffinityパフォーマンス — Pod 間のレイテンシ低減が重要である場合、またはワークロードを特定のゾーンに配置する必要がある場合

以下の例では、両方とも ECI に必須となる共通のフィールドを使用しています:テイント virtual-kubelet.io/provider に対する Toleration、および仮想ノードよりも Elastic Compute Service (ECS) ノードを優先する preferredDuringSchedulingIgnoredDuringExecution 型のノードアフィニティです。変更されるのは、分散またはアフィニティルールのみです。

例 1:ゾーン間で Pod を均等に分散配置する

この例では、利用可能なすべてのゾーンに均等に分散される 10 個のレプリカを持つ Deployment を作成します。

[ステップ 1] Deployment の作成

以下の YAML を deployment.yaml として保存し、kubectl apply -f deployment.yaml を実行します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: with-pod-topology-spread
  labels:
    app: with-pod-topology-spread
spec:
  replicas: 10
  selector:
    matchLabels:
      app: with-pod-topology-spread
  template:
    metadata:
      labels:
        app: with-pod-topology-spread
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: type
                operator: NotIn
                values:
                - virtual-kubelet
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: with-pod-topology-spread
      tolerations:
        - key: "virtual-kubelet.io/provider"
          operator: "Exists"
          effect: "NoSchedule"
      containers:
      - name: with-pod-topology-spread
        image: registry.k8s.io/pause:2.0
        resources:
          requests:
            cpu: "1"
            memory: "256Mi"

スケジューリングに関連する 3 つのセクションは以下のとおりです。

セクション機能
nodeAffinitypreferredDuringSchedulingIgnoredDuringExecutiontype NotIn virtual-kubeletECS ノードを優先します。ECS ノードが利用できない場合は仮想ノードへフォールバックします。詳細については、「ノードアフィニティ」をご参照ください。
topologySpreadConstraintsmaxSkew: 1topologyKey: topology.kubernetes.io/zonewhenUnsatisfiable: DoNotSchedule任意の 2 つのゾーン間における Pod 数の差を最大 1 に制限します。この制約を満たせない場合、kube-scheduler は配置をブロックします。詳細については、「topologySpreadConstraints フィールド」をご参照ください。
tolerationsvirtual-kubelet.io/provider: Exists, NoScheduleデフォルトでこのテイントを持つ仮想ノードへの Pod 配置を kube-scheduler に許可します。詳細については、「Taints and tolerations」をご参照ください。
説明

ARM ベースの仮想ノードに Pod をスケジュールする場合は、ARM 固有のテイントに対する Toleration を追加してください。

topologySpreadConstraints フィールドには複数のパラメーターが指定可能です。下表では、本例で使用するパラメーターおよび、最新の Kubernetes バージョンで利用可能なオプションパラメーターについて説明します。

パラメーター必須説明
maxSkewはい任意の 2 つのゾーン間における Pod 数の最大許容差
topologyKeyはいECI ベースの Pod の場合、必ず topology.kubernetes.io/zone を指定する必要があります
whenUnsatisfiableはいDoNotSchedule は制約を満たせない場合に配置をブロックします。ScheduleAnyway分散制約の定義 はベストエフォートでの配置を許可します
labelSelectorはい歪み(skew)評価時にカウント対象とする Pod を選択します
minDomainsいいえ考慮対象とするゾーンの最小数。Kubernetes 1.25 からベータ版
matchLabelKeysいいえ同一グループに属する Pod を識別するために使用される追加のラベルキー。Kubernetes 1.27 からベータ版
nodeAffinityPolicyいいえゾーンごとの Pod 数カウント時にノードアフィニティルールを尊重するかどうか。Kubernetes 1.26 からベータ版
nodeTaintsPolicyいいえゾーンごとの Pod 数カウント時にノードのテイントを尊重するかどうか。Kubernetes 1.26 からベータ版

[ステップ 2] スケジューリング結果の確認

以下のコマンドを実行して、各 Pod がどのノードに配置されたかを確認します。

kubectl get po -lapp=with-pod-topology-spread \
  -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName \
  --no-headers | grep -v "<none>"

ゾーンごとに Pod の数をカウントするには:

kubectl get po -lapp=with-pod-topology-spread \
  -o custom-columns=NODE:.spec.nodeName \
  --no-headers | grep -v "<none>" \
  | xargs -I {} kubectl get no {} -o json \
  | jq '.metadata.labels["topology.kubernetes.io/zone"]' \
  | sort | uniq -c

例 2:特定のゾーンに Pod をデプロイする

この例では、すべてのレプリカが同一ゾーンに配置される 3 個のレプリカを持つ Deployment を作成します。ゾーン間分散よりも Pod 間のレイテンシ低減が重要な場合に、このパターンを使用します。

[ステップ 1] Deployment の作成

以下の YAML を deployment.yaml として保存し、kubectl apply -f deployment.yaml を実行します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: with-affinity
  labels:
    app: with-affinity
spec:
  replicas: 3
  selector:
    matchLabels:
      app: with-affinity
  template:
    metadata:
      labels:
        app: with-affinity
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - with-affinity
            topologyKey: topology.kubernetes.io/zone
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: type
                operator: NotIn
                values:
                - virtual-kubelet
      tolerations:
        - key: "virtual-kubelet.io/provider"
          operator: "Exists"
          effect: "NoSchedule"
      containers:
      - name: with-affinity
        image: registry.k8s.io/pause:2.0

スケジューリングに関連する 3 つのセクションは以下のとおりです。

セクション機能
podAffinityrequiredDuringSchedulingIgnoredDuringExecutiontopologyKey: topology.kubernetes.io/zoneapp: with-affinity ラベルを持つすべての Pod を同一ゾーンに配置することを要求します。kube-scheduler は、この条件を満たせない限り Pod を配置しません。詳細については、「ノードアフィニティ」をご参照ください。
nodeAffinitypreferredDuringSchedulingIgnoredDuringExecutiontype NotIn virtual-kubeletECS ノードを優先します。ECS ノードが利用できない場合は仮想ノードへフォールバックします。詳細については、「ノードアフィニティ」をご参照ください。
tolerationsvirtual-kubelet.io/provider: Exists, NoSchedulekube-scheduler による仮想ノードへの Pod 配置を許可します。詳細については、「Taints and tolerations」をご参照ください。

Pod を最初の Pod が配置された場所ではなく、特定のゾーンに固定するには、podAffinity ブロックを requiredDuringSchedulingIgnoredDuringExecution 型のノードアフィニティに置き換えます。以下の構成では、Pod を北京ゾーン A にのみスケジュールします。

requiredDuringSchedulingIgnoredDuringExecution:
  nodeSelectorTerms:
  - matchExpressions:
    - key: topology.kubernetes.io/zone
      operator: In
      values:
      - cn-beijing-a

[ステップ 2] スケジューリング結果の確認

以下のコマンドを実行して、各 Pod がどのノードに配置されたかを確認します。

kubectl get po -lapp=with-affinity \
  -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName \
  --no-headers | grep -v "<none>"

ゾーンごとの Pod の数をカウントするには:

kubectl get po -lapp=with-affinity \
  -o custom-columns=NODE:.spec.nodeName \
  --no-headers | grep -v "<none>" \
  | xargs -I {} kubectl get no {} -o json \
  | jq '.metadata.labels["topology.kubernetes.io/zone"]' \
  | sort | uniq -c

Strict な ECI Pod トポロジ分散

デフォルトでは、kube-scheduler は均等なゾーン分散を目標としますが、一部のゾーンで ECI の作成に失敗した場合でも、Pod の配置をブロックしません。これにより、maxSkew 制約が静かに違反される可能性があります。

たとえば、maxSkew: 1 かつ 3 つのゾーン(A、B、C)が存在する場合、kube-scheduler はワークロードの Pod をすべてのゾーンに均等にデプロイしようとします。しかし、ゾーン B およびゾーン C で ECI の作成に失敗した場合、Pod はゾーン A のみで実行され、maxSkew で指定された制約が違反されます。

image

Strict な ECI Pod トポロジ分散を有効化することで、制約が確実に遵守されることを保証できます。Strict モードが有効の場合、kube-scheduler はまず各ゾーンに 1 つずつ Pod を配信し、スケジュール済みの Pod が実際に作成されるまで保留中の Pod を待機させます。以下の図は初期状態を示しており、各ゾーンに 1 つの Pod が配信され、それ以外のすべての Pod が保留中です。

image

Pod A1 が作成された後も、kube-scheduler は次の Pod をスケジュールしません。これは、ゾーン B またはゾーン C が失敗した場合に制約が違反されるためです。Pod B1 も作成された後に初めて、kube-scheduler はゾーン C に Pod をスケジュールします。緑色で強調表示された Pod は、作成済みの Pod を示します。

image

制約の遵守を無視して kube-scheduler が Pod を自由にスケジュールできるようにするには、whenUnsatisfiable: ScheduleAnyway を設定します。パラメーターの詳細については、「分散制約の定義」をご参照ください。