

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

# 透過網路連線的 Kubernetes Pod 容錯移轉
<a name="hybrid-nodes-kubernetes-pod-failover"></a>

首先，我們會回顧影響 Kubernetes 在節點和 Kubernetes 控制平面之間的網路連線中斷期間的行為的重要概念、元件和設定。EKS 符合上游 Kubernetes 規範，因此此處所述的所有 Kubernetes 概念、元件和設定都適用於 EKS 和 EKS 混合節點部署。

EKS 已針對改善網路連線中斷期間的 Pod 容錯移轉行為進行改善，如需詳細資訊，請參閱上游 Kubernetes 儲存庫中的 GitHub 問題 [\$1131294](https://github.com/kubernetes/kubernetes/pull/131294) 和 [\$1131481](https://github.com/kubernetes/kubernetes/issues/131481)。

## 概念
<a name="_concepts"></a>

 標記和容錯：在 Kubernetes 中使用標記和容錯來控制 Pod 在節點上的排程。污點是由 node-lifecycle-controller 設定，以表示節點不符合排程資格，或應移出這些節點上的 Pod。當節點因網路連線中斷而無法連線時，node-lifecycle-controller會使用 NoSchedule 效果套用 node.kubernetes.io/unreachable 污點，並在符合特定條件時套用 NoExecute 效果。node.kubernetes.io/unreachable 污點對應至 NodeCondition Ready be Unknown。使用者可以在 PodSpec 中的應用程式層級為污點指定容錯。
+ NoSchedule：除非有相符的容錯，否則不會在污點節點上排程新的 Pod。不會移出已在節點上執行的 Pod。
+ NoExecute：不會容忍污點的 Pod 會立即被移出。容忍污點的 Pod （不指定tolerationSeconds) 會永遠保持繫結。使用指定的tolerationSeconds容忍污點的 Pod 在指定的時間內保持繫結。經過這段時間後，節點生命週期控制器會從節點移出 Pod。

 節點租用：Kubernetes 使用租用 API 將 kubelet 節點活動訊號與 Kubernetes API 伺服器通訊。對於每個節點，都有一個具有相符名稱的租用物件。在內部，每個 kubelet 活動訊號都會更新租用物件的 spec.renewTime 欄位。Kubernetes 控制平面會使用此欄位的時間戳記來判斷節點可用性。如果節點與 Kubernetes 控制平面中斷連線，則無法更新其租用的 spec.renewTime，且控制平面會將該節點解譯為 NodeCondition Ready 為未知。

## 元件
<a name="_components"></a>

![\[涉及 Pod 容錯移轉行為的 Kubernetes 元件\]](http://docs.aws.amazon.com/zh_tw/eks/latest/best-practices/images/hybrid/k8s-components-pod-failover.png)



| 元件 | 子元件 | Description | 
| --- | --- | --- | 
|  Kubernetes 控制平面  |  kube-api-server  |  API 伺服器是 Kubernetes 控制平面的核心元件，可公開 Kubernetes API。  | 
|  Kubernetes 控制平面  |  node-lifecycle-controller  |  kube-controller-manager 執行的其中一個控制器。它負責偵測和回應節點問題。  | 
|  Kubernetes 控制平面  |  kube-scheduler  |  控制平面元件，可監看沒有指派節點的新建立 Pod，並選取要在其上執行的節點。  | 
|  Kubernetes 節點  |  kubelet  |  在叢集中每個節點上執行的代理程式。kubelet 會監看 PodSpecs，並確保這些 PodSpecs 中所述的容器執行正常。  | 

## 組態設定
<a name="_configuration_settings"></a>


| 元件 | 設定 | Description | K8s 預設 | EKS 預設 | 可在 EKS 中設定 | 
| --- | --- | --- | --- | --- | --- | 
|  kube-api-server  |  default-unreachable-toleration-seconds  |  指出 的 公差的 `tolerationSeconds` `unreachable:NoExecute`，預設會新增至尚未具有此類公差的每個 Pod。  |  300  |  300  |  否  | 
|  node-lifecycle-controller  |  node-monitor-grace-period  |  節點在標示為運作狀態不佳之前可能沒有回應的時間量。必須是 kubelet 的 N 倍`nodeStatusUpdateFrequency`，其中 N 是允許 kubelet 張貼節點狀態的重試次數。  |  40  |  40  |  否  | 
|  node-lifecycle-controller  |  large-cluster-size-threshold  |  對於移出邏輯，node-lifecycle-controller將叢集視為大型的節點數目。對於此大小或更小的叢集`--secondary-node-eviction-rate`， 會覆寫為 0。  |  50  |  100,000  |  否  | 
|  node-lifecycle-controller  |  unhealthy-zone-threshold  |  區域中必須尚未就緒，才能將該區域視為運作狀態不佳的節點百分比。  |  55%  |  55%  |  否  | 
|  kubelet  |  node-status-update-frequency  |  kubelet 將節點狀態發佈到控制平面的頻率。必須與 node-lifecycle-controller `nodeMonitorGracePeriod`中的 相容。  |  10  |  10  |  是  | 
|  kubelet  |  節點標籤  |  在叢集中註冊節點時要新增的標籤。`topology.kubernetes.io/zone` 可以使用混合節點指定標籤，將節點分組到區域中。  |  無  |  無  |  是  | 

## 透過網路連線的 Kubernetes Pod 容錯移轉
<a name="_kubernetes_pod_failover_through_network_disconnections"></a>

此處描述的行為假設 Pod 正在執行為具有預設設定的 Kubernetes 部署，且 EKS 用作 Kubernetes 供應商。實際行為可能會因您的環境、網路連線類型、應用程式、相依性和叢集組態而有所不同。本指南中的內容已使用特定應用程式、叢集組態和外掛程式子集進行驗證。強烈建議在進入生產環境之前，先使用您自己的應用程式來測試行為。

當節點與 Kubernetes 控制平面之間發生網路連線中斷時，每個中斷連線節點上的 kubelet 無法與 Kubernetes 控制平面通訊。因此，在連線還原之前，kubelet 無法移出這些節點上的 Pod。這表示在網路連線中斷之前在這些節點上執行的 Pod 會在中斷連線期間繼續執行，假設沒有其他失敗導致它們關閉。總而言之，您可以在節點與 Kubernetes 控制平面之間的網路連線中斷期間達到靜態穩定性，但在連線還原之前，您無法對節點或工作負載執行變動操作。

有五種主要案例會根據網路連線的性質產生不同的 Pod 容錯移轉行為。在所有情況下，當節點重新連線至 Kubernetes 控制平面時，叢集會再次正常運作，無需操作員介入。以下案例根據我們的觀察概述預期結果，但這些結果可能不適用於所有可能的應用程式和叢集組態。

### 案例 1：完全叢集中斷
<a name="_scenario_1_full_cluster_disruption"></a>

 **預期結果**：無法連線節點上的 Pod 不會移出，並繼續在這些節點上執行。

完整的叢集中斷表示叢集中的所有節點都與 Kubernetes 控制平面中斷連線。在此案例中，控制平面上的node-lifecycle-controller會偵測到叢集中的所有節點都無法連線，並取消任何 Pod 移出。

叢集管理員將在中斷連線`Not Ready`期間看到狀態為 的所有節點。Pod 狀態不會變更，而且在中斷連線和後續重新連線期間，不會在任何節點上排程新的 Pod。

### 案例 2：全區域中斷
<a name="_scenario_2_full_zone_disruption"></a>

 **預期結果**：無法連線節點上的 Pod 不會移出，並繼續在這些節點上執行。

完全區域中斷表示該區域中的所有節點都與 Kubernetes 控制平面中斷連線。在此案例中，控制平面上的node-lifecycle-controller偵測到區域中的所有節點都無法連線，並取消任何 Pod 移出。

叢集管理員將在中斷連線`Not Ready`期間看到狀態為 的所有節點。Pod 狀態不會變更，而且在中斷連線和後續重新連線期間，不會在任何節點上排程新的 Pod。

### 案例 3：主要區域中斷
<a name="_scenario_3_majority_zone_disruption"></a>

 **預期結果**：無法連線節點上的 Pod 不會移出，並繼續在這些節點上執行。

大多數區域中斷表示指定區域中的大多數節點都與 Kubernetes 控制平面中斷連線。Kubernetes 中的區域由具有相同`topology.kubernetes.io/zone`標籤的節點定義。如果叢集中未定義任何區域，則大多數中斷表示整個叢集中的大多數節點都會中斷連線。根據預設，大多數是由 node-lifecycle-controller 的 定義`unhealthy-zone-threshold`，在 Kubernetes 和 EKS 中均設為 55%。由於 `large-cluster-size-threshold` EKS 中的 設為 100，000，如果區域中 55% 以上的節點無法連線，則會取消 Pod 移出 （因為大多數叢集遠小於 100，000 個節點）。

叢集管理員會在中斷連線`Not Ready`期間看到區域中狀態為 的大多數節點，但 Pod 的狀態不會變更，也不會在其他節點上重新排程這些節點。

請注意，上述行為僅適用於大於三個節點的叢集。在不超過三個節點的叢集中，無法連線節點上的 Pod 會排程為移出，而新的 Pod 會排程在運作狀態良好的節點上。

在測試期間，我們偶爾會觀察到 Pod 在網路連線中斷期間從剛好一個無法連線的節點移出，即使大部分的區域節點都無法連線。作為此行為的原因，我們仍在 Kubernetes node-lifecycle-controller中調查可能的競爭條件。

### 案例 4：少數區域中斷
<a name="_scenario_4_minority_zone_disruption"></a>

 **預期結果**：從無法連線的節點移出 Pod，並在可用的合格節點上排程新的 Pod。

少數中斷表示區域中較少百分比的節點與 Kubernetes 控制平面中斷連線。如果叢集中未定義任何區域，則少數中斷表示整個叢集中節點的少數節點會中斷連線。如上所述，少數是節點node-lifecycle-controller`unhealthy-zone-threshold`的設定，預設為 55%。在此案例中，如果網路連線的持續時間超過 `default-unreachable-toleration-seconds`(5 分鐘） 和 `node-monitor-grace-period`(40 秒），且區域中少於 55% 的節點無法連線，則會在運作狀態良好的節點上排程新的 Pod，而無法連線節點上的 Pod 會標記為移出。

叢集管理員將看到在運作狀態良好的節點上建立的新 Pod，中斷連線節點上的 Pod 將顯示為 `Terminating`。請記住，即使已中斷連線節點上的 Pod 具有 `Terminating` 狀態，在節點重新連線至 Kubernetes 控制平面之前，它們不會完全移出。

## 案例 5：網路中斷期間節點重新啟動
<a name="_scenario_5_node_restart_during_network_disruption"></a>

 **預期結果**：在節點重新連線至 Kubernetes 控制平面之前，無法連線節點上的 Pod 不會啟動。Pod 容錯移轉遵循案例 1–3 中所述的邏輯，取決於無法連線的節點數量。

網路中斷期間節點重新啟動表示節點上發生另一個故障 （例如電源循環、out-of-memory事件或其他問題） 與網路中斷連線同時發生。如果 kubelet 也已重新啟動，則網路中斷連線開始時在該節點上執行的 Pod 不會在中斷連線期間自動重新啟動。kubelet 會在啟動期間查詢 Kubernetes API 伺服器，以了解應執行哪些 Pod。如果 kubelet 由於網路連線中斷而無法連接 API 伺服器，則無法擷取啟動 Pod 所需的資訊。

在這種情況下，無法使用本機故障診斷工具，例如 `crictl` CLI，將 Pod 手動啟動為「中斷玻璃」量值。Kubernetes 通常會移除故障的 Pod 並建立新的 Pod，而不是重新啟動現有的 Pod （如需詳細資訊，請參閱容器化 GitHub 儲存庫中的 [\$110213](https://github.com/containerd/containerd/pull/10213))。靜態 Pod 是唯一由 kubelet 控制的 Kubernetes 工作負載物件，並且可以在這些情況下重新啟動。不過，通常不建議使用靜態 Pod 進行應用程式部署。相反地，在不同的主機之間部署多個複本，以確保在發生多個同時故障時應用程式可用性，例如節點故障，以及節點和 Kubernetes 控制平面之間的網路連線中斷。