

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# ノードとアベイラビリティーゾーンにワークロードを分散する
<a name="spread-workloads"></a>

アベイラビリティーゾーンやノードなどの[障害ドメイン](https://cluster-api-aws.sigs.k8s.io/topics/failure-domains/)間でワークロードを分散することで、コンポーネントの可用性が向上し、水平方向にスケーラブルなアプリケーションの障害が発生する可能性が低くなります。以下のセクションでは、ノードとアベイラビリティーゾーンにワークロードを分散する方法について説明します。

## ポッドトポロジの分散制約を使用する
<a name="spread-constraints"></a>

[Kubernetes ポッドトポロジの分散制約](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)により、Kubernetes スケジューラは`StatefulSet`、異なる障害ドメイン (アベイラビリティーゾーン、ノード、およびハードウェアのタイプ) によって管理されるポッド`ReplicaSet`を分散するように指示されます。ポッドトポロジの分散制約を使用すると、次のことができます。
+ アプリケーションの要件に応じて、さまざまな障害ドメインにポッドを分散または集中させます。たとえば、レジリエンスのためにポッドを配布し、ネットワークパフォーマンスのためにポッドを集中させることができます。
+ アベイラビリティーゾーン間での分散やノード間での分散など、さまざまな条件を組み合わせます。
+ 条件が満たされない場合は、優先アクションを指定します。
  + `maxSkew` と の組み合わせ`whenUnsatisfiable: DoNotSchedule`で を使用して`minDomains`、スケジューラのハード要件を作成します。
  + `whenUnsatisfiable: ScheduleAnyway` を使用して を減らします`maxSkew`。

障害ゾーンが使用できなくなった場合、そのゾーンのポッドは異常になります。Kubernetes は、可能であればスプレッド制約に従ってポッドを再スケジュールします。

次のコードは、アベイラビリティーゾーン間またはノード間でポッドトポロジースプレッド制約を使用する例を示しています。

```
...
spec:
  selector:
    matchLabels:
      app: <your-app-label>
    replicas: 3
    template:
      metadata:
        labels: <your-app-label>
      spec:
        serviceAccountName: <ServiceAccountName>
...
        topologySpreadConstraints:
        - labelSelector:
            matchLabels:
              app: <your-app-label>
          maxSkew: 1
          topologyKey: topology.kubernetes.io/zone # <---spread those pods evenly over all availability zones
          whenUnsatisfiable: ScheduleAnyway
        - labelSelector:
            matchLabels:
              app: <your-app-label>
          maxSkew: 1
          topologyKey: kubernetes.io/hostname # <---spread those pods evenly over all nodes
          whenUnsatisfiable: ScheduleAnyway
```

### クラスター全体のトポロジのデフォルトの分散制約
<a name="default-constraints"></a>

デフォルトでは、Kubernetes はノードとアベイラビリティーゾーン間でポッドを分散するための[トポロジースプレッド制約のセット](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/#internal-default-constraints)を提供します。

```
defaultConstraints:
  - maxSkew: 3
    topologyKey: "kubernetes.io/hostname"
    whenUnsatisfiable: ScheduleAnyway
  - maxSkew: 5
    topologyKey: "topology.kubernetes.io/zone"
    whenUnsatisfiable: ScheduleAnyway
```

**注記**  
さまざまなタイプのトポロジ制約を必要とするアプリケーションは、クラスターレベルのポリシーを上書きできます。

デフォルトの制約は高い を設定します。これは`maxSkew`、少数のポッドを持つデプロイには役に立ちません。現時点では、Amazon EKS `KubeSchedulerConfiguration` では [を変更できません](https://github.com/aws/containers-roadmap/issues/1468)。他のトポロジスプレッド制約のセットを適用する必要がある場合は、以下のセクションのように変更アドミッションコントローラーを使用することを検討してください。代替スケジューラを実行する場合は、デフォルトのトポロジスプレッド制約を制御することもできます。ただし、カスタムスケジューラを管理すると複雑さが増し、クラスターの耐障害性と HA に影響する可能性があります。このような理由から、トポロジの分散制約にのみ代替スケジューラを使用することはお勧めしません。

### トポロジの分散制約のゲートキーパーポリシー
<a name="gatekeeper-policy"></a>

トポロジの分散制約を適用するもう 1 つのオプションは、[Gatekeeper](https://open-policy-agent.github.io/gatekeeper/website/docs/) プロジェクトのポリシーを使用することです。ゲートキーパーポリシーはアプリケーションレベルで定義されます。

次のコード例は、デプロイ用の`Gatekeeper OPA`ポリシーの使用を示しています。必要に応じてポリシーを変更できます。たとえば、 というラベルを持つデプロイにのみポリシーを適用するか`HA=true`、別のポリシーコントローラーを使用して同様のポリシーを記述します。

この最初の例は、 で`ConstraintTemplate`使用されている を示しています`k8stopologyspreadrequired_template.yml`。

```
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8stopologyspreadrequired
spec:
  crd:
    spec:
      names:
        kind: K8sTopologySpreadRequired
      validation:
        openAPIV3Schema:
          type: object
          properties:
            message:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8stopologyspreadrequired

        get_message(parameters, _default) =3D msg {
          not parameters.message
          msg :=_default
        }


        get_message(parameters, _default) =3D msg {
          msg := parameters.message
        }

        violation[{"msg": msg}] {
          input.review.kind.kind ="Deployment"
          not input.review.object.spec.template.spec.topologySpreadConstraint
          def_msg :"Pod Topology Spread Constraints are required for Deployments"
          msg :get_message(input.parameters, def_msg)

        }
```

次のコードは、YAML `constraints` マニフェスト を示しています`k8stopologyspreadrequired_constraint.yml`。

```
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sTopologySpreadRequired
metadata:
  name: require-topologyspread-for-deployments
spec:
  match:
    kinds:
      - apiGroups: ["apps"]
        kinds: ["Deployment"]
    namespaces:  ## Without theses two lines will apply to the whole cluster
      - "example"
```

### トポロジスプレッド制約を使用するタイミング
<a name="when-to-use"></a>

以下のシナリオでは、トポロジースプレッド制約の使用を検討してください。
+ 水平方向にスケーラブルなアプリケーション (ステートレスウェブサービスなど)
+ アクティブ/アクティブまたはアクティブ/パッシブレプリカを持つアプリケーション (NoSQL データベースやキャッシュなど)
+ スタンバイレプリカを持つアプリケーション (コントローラーなど)

水平方向にスケーラブルなシナリオに使用できるシステムコンポーネントには、次のようなものがあります。
+ [Cluster Autoscaler](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler) と [Karpenter](https://karpenter.sh/) ( `replicaCount > 1`と を使用`leader-elect = true`)
+ [AWS Load Balancerコントローラー](https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/)
+ [CoreDNS](https://coredns.io/)

## ポッドアフィニティとアンチアフィニティ
<a name="anti-affinity"></a>

場合によっては、特定のタイプのポッドがノードで実行されないようにすることが有益です。たとえば、同じノードで複数のネットワーク負荷の高いポッドをスケジュールしないようにするには、ラベル `Ingress`または でアンチアフィニティルールを使用できます`Network-heavy`。を使用する場合は`anti-affinity`、次の組み合わせを使用することもできます。
+ ネットワーク最適化ノードのテイント
+ ネットワーク負荷の高いポッドでの対応する許容範囲
+ ネットワーク負荷の高いポッドがネットワーク最適化インスタンスを使用するようにするためのノードアフィニティまたはノードセレクタ

ネットワーク負荷の高いポッドが例として使用されます。GPU、メモリ、ローカルストレージなど、要件が異なる場合があります。その他の使用例と設定オプションについては、[Kubernetes ドキュメント](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity)を参照してください。

### ポッドの再調整
<a name="rebalance-pods"></a>

このセクションでは、Kubernetes クラスター内のポッドを再調整するための 2 つのアプローチについて説明します。1 つ目は Descheduler for Kubernetes を使用します。Descheduler は、トポロジの分散制約やアンチアフィニティルールに違反するポッドを削除する戦略を強制することで、ポッドの分散を維持するのに役立ちます。2 番目のアプローチでは、Karpenter 統合とビンパッキング機能を使用します。統合は、ワークロードをより少ない、より効率的にパックされたノードに統合することで、リソースの使用状況を継続的に評価および最適化します。

Karpenter を使用していない場合は、Descheduler を使用することをお勧めします。Karpenter と Cluster Autoscaler を一緒に使用している場合は、ノードグループに Descheduler と Cluster Autoscaler を使用できます。

#### グループレスノードのデスケジューラ
<a name="descheduler"></a>

ポッドが削除されてもトポロジの制約が満たされ続ける保証はありません。たとえば、デプロイをスケールダウンすると、ポッド分散が不均衡になる可能性があります。ただし、Kubernetes はスケジューリング段階でのみポッドトポロジの分散制約を使用するため、ポッドは障害ドメイン間で不均衡なままになります。

このようなシナリオでバランスの取れたポッドディストリビューションを維持するには、[Descheduler for Kubernetes ](https://github.com/kubernetes-sigs/descheduler)を使用できます。デスケジューラは、ポッドの最大有効期間や有効期限 (TTL) の適用、インフラストラクチャの使用の改善など、複数の目的に便利なツールです。レジリエンスと高可用性 (HA) の観点から、次のデスケジューラ戦略を検討してください。
+ [RemovePodsViolatingTopologySpreadConstraint](https://github.com/kubernetes-sigs/descheduler?tab=readme-ov-file#removepodsviolatingtopologyspreadconstraint)
+ [RemovePodsViolatingInterPodAntiAffinity](https://github.com/kubernetes-sigs/descheduler?tab=readme-ov-file#removepodsviolatinginterpodantiaffinity)
+ [RemoveDuplicates](https://github.com/kubernetes-sigs/descheduler?tab=readme-ov-file#removeduplicates)

#### Karpenter 統合とビンパッキング機能
<a name="karpenter"></a>

Karpenter を使用するワークロードでは、統合機能とビンパッキング機能を使用してリソース使用率を最適化し、Kubernetes クラスターのコストを削減できます。Karpenter はポッドの配置とノード使用率を継続的に評価し、可能な場合はワークロードをより少ない、より効率的にパックされたノードに統合しようとします。このプロセスでは、リソース要件を分析し、ポッドアフィニティルールなどの制約を考慮し、ノード間でポッドを移動して全体的なクラスター効率を向上させる可能性があります。次のコードは例を示しています。

```
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: default
spec:
  disruption:
    consolidationPolicy: WhenUnderutilized
    expireAfter: 720h
```

では`consolidationPolicy`、 `WhenUnderutilized`または を使用できます`WhenEmpty`。
+ `consolidationPolicy` が に設定されている場合`WhenUnderutilized`、Karpenter はすべてのノードを統合と見なします。Karpenter が空または十分に使用されていないノードを検出すると、Karpenter はコストを削減するためにノードの削除または交換を試みます。
+ `consolidationPolicy` が に設定されている場合`WhenEmpty`、Karpenter はワークロードポッドを含まないノードのみを統合対象と見なします。

Karpenter の統合の決定は、モニタリングツールに表示される CPU またはメモリ使用率のみに基づくものではありません。代わりに、Karpenter はポッドリソースリクエストと潜在的なコスト最適化に基づいて、より複雑なアルゴリズムを使用します。詳細については、[Karpenter](https://karpenter.sh/docs/concepts/disruption/#consolidation) のドキュメントを参照してください。