

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 將工作負載分散到節點和可用區域
<a name="spread-workloads"></a>

將工作負載分散到可用區域和節點等[故障網域](https://cluster-api-aws.sigs.k8s.io/topics/failure-domains/)，可改善元件可用性，並減少水平擴展應用程式的故障機率。下列各節介紹將工作負載分散到節點和可用區域的方法。

## 使用 Pod 拓撲分散限制
<a name="spread-constraints"></a>

[Kubernetes Pod 拓撲分散限制](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)，指示 Kubernetes 排程器將由不同故障網域 （可用區域、節點和硬體類型） 管理`ReplicaSet`的 Pod 分發`StatefulSet`。當您使用 Pod 拓撲分散限制時，您可以執行下列動作：
+ 根據應用程式需求，將 Pod 分散或集中於不同的故障網域。例如，您可以分佈 Pod 以實現彈性，也可以集中 Pod 以實現網路效能。
+ 結合不同的條件，例如跨可用區域分佈和跨節點分佈。
+ 如果無法滿足條件，請指定偏好的動作：
  + 使用 `whenUnsatisfiable: DoNotSchedule`搭配 `maxSkew`和 的組合`minDomains`來建立排程器的硬性需求。
  + 使用 `whenUnsatisfiable: ScheduleAnyway` 減少 `maxSkew`。

如果故障區域無法使用，該區域中的 Pod 會變得運作狀態不佳。Kubernetes 會重新排程 Pod，同時盡可能遵守分散限制條件。

下列程式碼顯示使用 Pod 拓撲跨可用區域或跨節點分散限制的範例：

```
...
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)，用於跨節點和可用區域分佈 Pod：

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

**注意**  
需要不同類型的拓撲限制的應用程式可以覆寫叢集層級政策。

預設限制條件會設定較高的 `maxSkew`，這不適用於具有少量 Pod 的部署。截至目前為止， `KubeSchedulerConfiguration` [無法在 Amazon EKS 中變更](https://github.com/aws/containers-roadmap/issues/1468)。如果您需要強制執行其他一組拓撲分散限制，請考慮使用變動許可控制器，如以下章節所示。如果您執行替代排程器，也可以控制預設拓撲分散限制條件。不過，管理自訂排程器會增加複雜性，並可能影響叢集彈性和 HA。基於這些原因，我們不建議僅針對拓撲分散限制使用替代排程器。

### 拓撲分散限制的 Gatekeeper 政策
<a name="gatekeeper-policy"></a>

強制執行拓撲分散限制的另一個選項是使用 [Gatekeeper](https://open-policy-agent.github.io/gatekeeper/website/docs/) 專案的政策。Gatekeeper 政策是在應用程式層級定義。

下列程式碼範例顯示使用`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)

        }
```

下列程式碼顯示 `constraints` YAML 資訊清單 `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>

考慮在下列案例中使用拓撲分散限制條件：
+ 任何水平擴展的應用程式 （例如，無狀態 Web 服務）
+ 具有主動-主動或主動-被動複本的應用程式 （例如 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/)

## Pod 親和性與反親和性
<a name="anti-affinity"></a>

在某些情況下，確保節點上執行的特定類型不超過一個 Pod 是有益的。例如，若要避免在同一個節點上排程多個網路密集型 Pod，您可以使用反親和性規則搭配 標籤`Ingress`或 `Network-heavy`。使用 時`anti-affinity`，您也可以使用下列的組合：
+ 網路最佳化節點上的污點
+ 網路密集型 Pod 上的對應公差
+ 節點親和性或節點選擇器，以確保網路密集型 Pod 使用網路最佳化執行個體

網路密集型 Pod 做為範例使用。您可能有不同的需求，例如 GPU、記憶體或本機儲存。如需其他使用範例和組態選項，請參閱 [Kubernetes 文件](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity)。

### 重新平衡 Pod
<a name="rebalance-pods"></a>

本節討論在 Kubernetes 叢集中重新平衡 Pod 的兩種方法。第一個 使用適用於 Kubernetes 的 Descheduler。Descheduler 透過強制執行策略來移除違反拓撲分散限制或反親和性規則的 Pod，協助維護 Pod 分佈。第二個方法使用 Karpenter 整合和 bin-packing 功能。合併透過將工作負載合併到較少、更有效率的封裝節點上，持續評估和最佳化資源用量。

如果您不使用 Karpenter，建議使用 Descheduler。如果您同時使用 Karpenter 和 Cluster Autoscaler，則可以將 Descheduler 與 Cluster Autoscaler 用於節點群組。

#### 無群組節點的排程器
<a name="descheduler"></a>

無法保證移除 Pod 時，拓撲限制仍能滿足。例如，縮減部署規模可能會導致 Pod 分佈不平衡。不過，由於 Kubernetes 僅在排程階段使用 Pod 拓撲分散限制，因此 Pod 在故障網域中會保持不平衡。

若要在這類情況下維持平衡的 Pod 分佈，您可以使用 [Descheduler for Kubernetes](https://github.com/kubernetes-sigs/descheduler)。Descheduler 是適用於多種用途的實用工具，例如強制執行最大 Pod 存留期或存留時間 (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 整合和 bin-packing 功能
<a name="karpenter"></a>

對於使用 Karpenter 的工作負載，您可以使用整合和 bin-packing 功能來最佳化資源使用率，並降低 Kubernetes 叢集中的成本。Karpenter 會持續評估 Pod 置放和節點使用率，並盡可能嘗試將工作負載合併到較少、更有效率的封裝節點。此程序涉及分析資源需求、考慮 Pod 親和性規則等限制，以及可能在節點之間移動 Pod 以提高整體叢集效率。下列程式碼提供範例：

```
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 會考慮僅整合不包含工作負載 Pod 的節點。

Karpenter 整合決策並非僅根據您在監控工具中可能看到的 CPU 或記憶體使用率百分比。反之，Karpenter 會根據 Pod 資源請求和潛在的成本最佳化，使用更複雜的演算法。如需詳細資訊，請參閱 [Karpenter](https://karpenter.sh/docs/concepts/disruption/#consolidation) 文件。