本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes v1.26:Kubernetes 流量工程的進展

Kubernetes v1.26 在網路流量工程方面取得了重大進展,其中兩個特性(Service 內部流量策略支援和 EndpointSlice 終止條件)升級為正式釋出(GA),第三個特性(代理終止端點)升級為 Beta 版。這些增強功能的結合旨在解決人們當前面臨的流量工程短板,併為未來解鎖新的能力。

滾動更新期間來自負載均衡器的流量丟失

在 Kubernetes v1.26 之前,當 externalTrafficPolicy 欄位設定為 Local 時,叢集在滾動更新期間可能會遇到來自 Service 負載均衡器的流量丟失問題。這裡涉及很多活動部件,因此快速瞭解一下 Kubernetes 如何管理負載均衡器可能會有所幫助!

在 Kubernetes 中,你可以建立一個 type: LoadBalancer 的 Service,透過負載均衡器將應用程式對外暴露。負載均衡器的實現因叢集和平臺而異,但 Service 提供了一個通用的抽象,代表了在所有 Kubernetes 安裝中都一致的負載均衡器。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  type: LoadBalancer

在底層,Kubernetes 為該 Service 分配一個 NodePort,然後 kube-proxy 使用該 NodePort 提供從 NodePort 到 Pod 的網路資料路徑。控制器隨後會將叢集中所有可用的節點新增到負載均衡器的後端池中,使用為該 Service 指定的 NodePort 作為後端目標埠。

Figure 1: Overview of Service load balancers

圖 1:Service 負載均衡器概覽

通常,為 Service 設定 externalTrafficPolicy: Local 是有益的,以避免在沒有執行健康 Pod 來支援該 Service 的節點之間產生額外的網路跳數。當使用 externalTrafficPolicy: Local 時,會額外分配一個 NodePort 用於健康檢查,這樣不包含健康 Pod 的節點就會從負載均衡器的後端池中排除。

Figure 2: Load balancer traffic to a healthy Node, when externalTrafficPolicy is Local

圖 2:當 externalTrafficPolicy 為 Local 時,負載均衡器流量流向健康節點

一種可能導致流量丟失的場景是,當一個節點失去了某個 Service 的所有 Pod,但外部負載均衡器尚未探測到健康檢查 NodePort 的狀態。這種情況發生的可能性很大程度上取決於負載均衡器上配置的健康檢查間隔。間隔越大,這種情況就越有可能發生,因為即使在 kube-proxy 移除了該 Service 的轉發規則之後,負載均衡器仍會繼續向該節點發送流量。這在滾動更新期間 Pod 開始終止時也會發生。由於 Kubernetes 不認為正在終止的 Pod 是“就緒”的,因此在滾動更新期間,當任何給定節點上只有正在終止的 Pod 時,可能會發生流量丟失。

Figure 3: Load balancer traffic to terminating endpoints, when externalTrafficPolicy is Local

圖 3:當 externalTrafficPolicy 為 Local 時,負載均衡器流量流向正在終止的端點

從 Kubernetes v1.26 開始,kube-proxy 預設啟用了 ProxyTerminatingEndpoints 特性,該特性在流量否則會被丟棄的場景下,為正在終止的端點添加了自動故障轉移和路由功能。更具體地說,當進行滾動更新且某個節點只包含正在終止的 Pod 時,kube-proxy 將根據它們的就緒狀態將流量路由到這些正在終止的 Pod。此外,如果只有正在終止的 Pod 可用,kube-proxy 將主動使健康檢查 NodePort 失敗。透過這樣做,kube-proxy 會通知外部負載均衡器不應將新連線傳送到該節點,但會優雅地處理現有連線的請求。

Figure 4: Load Balancer traffic to terminating endpoints with ProxyTerminatingEndpoints enabled, when externalTrafficPolicy is Local

圖 4:當 externalTrafficPolicy 為 Local 且啟用 ProxyTerminatingEndpoints 時,負載均衡器流量流向正在終止的端點

EndpointSlice 條件

為了支援 kube-proxy 中的這一新功能,EndpointSlice API 引入了針對端點的新條件:servingterminating

Figure 5: Overview of EndpointSlice conditions

圖 5:EndpointSlice 條件概覽

serving 條件在語義上與 ready 相同,但它在 Pod 終止期間可以是 truefalse,而 ready 出於相容性原因,對於正在終止的 Pod 總是 falseterminating 條件對於正在終止的 Pod(deletionTimestamp 非空)為 true,否則為 false。

這兩個條件的增加使該 API 的使用者能夠了解以前無法獲知的 Pod 狀態。例如,我們現在可以跟蹤那些同時也在終止的“就緒”和“非就緒”的 Pod。

Figure 6: EndpointSlice conditions with a terminating Pod

圖 6:帶有正在終止的 Pod 的 EndpointSlice 條件

EndpointSlice API 的使用者,如 Kube-proxy 和 Ingress 控制器,現在可以利用這些條件來協調連線排空事件,透過繼續為現有連線轉發流量,但將新連線重新路由到其他非終止的端點。

最佳化內部節點本地流量

類似於 Service 可以設定 externalTrafficPolicy: Local 來避免外部來源流量的額外跳數,Kubernetes 現在支援 internalTrafficPolicy: Local,以為叢集內部產生的流量(特別是以 Service Cluster IP 為目標地址的流量)實現相同的最佳化。該特性在 Kubernetes v1.24 中升級為 Beta 版,並在 v1.26 中升級為 GA。

Service 的 internalTrafficPolicy 欄位預設為 Cluster,此時流量會隨機分配到所有端點。

Figure 7: Service routing when internalTrafficPolicy is Cluster

圖 7:當 internalTrafficPolicy 為 Cluster 時的 Service 路由

internalTrafficPolicy 設定為 Local 時,kube-proxy 僅在有位於同一節點上的可用端點時,才會轉發 Service 的內部流量。

Figure 8: Service routing when internalTrafficPolicy is Local

圖 8:當 internalTrafficPolicy 為 Local 時的 Service 路由

參與其中

如果你對未來 Kubernetes 流量工程的討論感興趣,可以透過以下方式參與 SIG Network