EndpointSlices

EndpointSlice API 是 Kubernetes 用來讓您的服務擴展以處理大量後端,並允許叢集有效率地更新其健康後端列表的機制。
功能狀態: Kubernetes v1.21 [穩定]

Kubernetes 的 EndpointSlice API 提供了一種追蹤 Kubernetes 叢集中網路端點的方式。EndpointSlice 提供了比 端點 (Endpoints) 更具擴展性和延伸性的替代方案。

EndpointSlice API

在 Kubernetes 中,一個 EndpointSlice 包含一組網路端點的參考。控制平面會自動為任何指定了 選擇器 (selector) 的 Kubernetes 服務建立 EndpointSlice。這些 EndpointSlice 包含對所有符合服務選擇器的 Pod 的參考。EndpointSlice 依協定、埠號和服務名稱的獨特組合將網路端點分組在一起。EndpointSlice 物件的名稱必須是有效的 DNS 子網域名稱

舉例來說,以下是一個範例 EndpointSlice 物件,它由 example Kubernetes 服務所擁有。

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: example-abc
  labels:
    kubernetes.io/service-name: example
addressType: IPv4
ports:
  - name: http
    protocol: TCP
    port: 80
endpoints:
  - addresses:
      - "10.1.2.3"
    conditions:
      ready: true
    hostname: pod-1
    nodeName: node-1
    zone: us-west2-a

預設情況下,控制平面建立和管理 EndpointSlice,使其每個最多有 100 個端點。您可以使用 --max-endpoints-per-slice kube-controller-manager 標誌來設定此值,最多可設定為 1000。

EndpointSlice 可以作為 kube-proxy 在如何路由內部流量方面的真實來源。

位址類型

EndpointSlice 支援三種位址類型

  • IPv4
  • IPv6
  • FQDN (完整合格網域名稱)

每個 EndpointSlice 物件代表特定的 IP 位址類型。如果您有一個透過 IPv4 和 IPv6 可用的服務,則至少會有兩個 EndpointSlice 物件 (一個用於 IPv4,另一個用於 IPv6)。

條件

EndpointSlice API 儲存關於端點的條件,這些條件可能對消費者有用。三個條件為 readyservingterminating

Ready

ready 是一個對應到 Pod 的 Ready 條件的條件。Ready 條件設定為 True 的執行中 Pod 應該也將此 EndpointSlice 條件設定為 true。基於相容性原因,當 Pod 正在終止時,ready 永遠不會是 true。消費者應參考 serving 條件來檢查終止中 Pod 的就緒狀態。此規則的唯一例外是用於將 spec.publishNotReadyAddresses 設定為 true 的服務。這些服務的端點將始終將 ready 條件設定為 true

Serving

功能狀態: Kubernetes v1.26 [穩定]

serving 條件幾乎與 ready 條件相同。不同之處在於,如果 EndpointSlice API 的消費者關心 Pod 在終止時的就緒狀態,則應檢查 serving 條件。

終止中

功能狀態: Kubernetes v1.22 [beta 版]

Terminating 是一種條件,表示端點是否正在終止中。對於 Pod 而言,這是指任何設定了刪除時間戳記的 Pod。

拓撲資訊

EndpointSlice 中的每個端點都可以包含相關的拓撲資訊。拓撲資訊包括端點的位置以及關於對應節點和區域的資訊。這些資訊在 EndpointSlice 上每個端點的以下欄位中提供

  • nodeName - 此端點所在的節點名稱。
  • zone - 此端點所在的區域。

管理

大多數情況下,控制平面(特別是 endpoint slice 控制器)建立和管理 EndpointSlice 物件。EndpointSlice 還有許多其他用例,例如服務網格實作,可能會導致其他實體或控制器管理額外的 EndpointSlice 集合。

為了確保多個實體可以管理 EndpointSlice 而不會互相干擾,Kubernetes 定義了標籤 endpointslice.kubernetes.io/managed-by,它指示管理 EndpointSlice 的實體。endpoint slice 控制器將 endpointslice-controller.k8s.io 設定為其管理的所有 EndpointSlice 上此標籤的值。管理 EndpointSlice 的其他實體也應為此標籤設定唯一值。

所有權

在大多數用例中,EndpointSlice 由 Service 擁有,endpoint slice 物件會追蹤該 Service 的端點。此所有權由每個 EndpointSlice 上的擁有者參照以及 kubernetes.io/service-name 標籤指示,該標籤可以簡單地查找屬於 Service 的所有 EndpointSlice。

EndpointSlice 鏡像

在某些情況下,應用程式會建立自訂的 Endpoints 資源。為了確保這些應用程式不需要同時寫入 Endpoints 和 EndpointSlice 資源,叢集的控制平面會將大多數 Endpoints 資源鏡像到對應的 EndpointSlice。

控制平面會鏡像 Endpoints 資源,除非

  • Endpoints 資源的 endpointslice.kubernetes.io/skip-mirror 標籤設定為 true
  • Endpoints 資源具有 control-plane.alpha.kubernetes.io/leader 註解。
  • 對應的 Service 資源不存在。
  • 對應的 Service 資源具有非空的選取器。

個別的 Endpoints 資源可能會轉換為多個 EndpointSlice。如果 Endpoints 資源有多個子集或包含具有多個 IP 系列(IPv4 和 IPv6)的端點,則會發生這種情況。每個子集最多 1000 個位址將被鏡像到 EndpointSlice。

EndpointSlice 的分配

每個 EndpointSlice 都有一組適用於資源內所有端點的埠。當具名埠用於 Service 時,Pod 可能最終會為同一個具名埠使用不同的目標埠號,從而需要不同的 EndpointSlice。這與子集如何與 Endpoints 分組背後的邏輯類似。

控制平面嘗試盡可能地填滿 EndpointSlice,但不會主動重新平衡它們。邏輯相當簡單明瞭

  1. 迭代現有的 EndpointSlice,移除不再需要的端點,並更新已變更的相符端點。
  2. 迭代在第一步中修改過的 EndpointSlice,並用任何需要的新端點填滿它們。
  3. 如果還有新的端點要新增,請嘗試將它們放入先前未變更的 slice 和/或建立新的 slice。

重要的是,第三步優先考慮限制 EndpointSlice 更新,而不是完美地完全分配 EndpointSlice。例如,如果有 10 個新端點要新增,並且有 2 個 EndpointSlice 各有 5 個端點的空間,則此方法將建立一個新的 EndpointSlice,而不是填滿 2 個現有的 EndpointSlice。換句話說,單個 EndpointSlice 的建立比多次 EndpointSlice 的更新更可取。

由於 kube-proxy 在每個節點上執行並監看 EndpointSlice,因此每次對 EndpointSlice 的變更都會變得相對昂貴,因為它將傳輸到叢集中的每個節點。此方法旨在限制需要傳送到每個節點的變更數量,即使這可能會導致多個未滿的 EndpointSlice。

實際上,這種不太理想的分配應該很少見。EndpointSlice 控制器處理的大多數變更都足夠小,可以放入現有的 EndpointSlice 中,如果不行,那麼無論如何很快就需要一個新的 EndpointSlice。Deployments 的滾動更新也提供了 EndpointSlice 的自然重新封裝,所有 Pod 及其對應的端點都將被替換。

重複的端點

由於 EndpointSlice 變更的性質,端點可能同時在多個 EndpointSlice 中表示。當對不同 EndpointSlice 物件的變更可能在不同時間到達 Kubernetes 客戶端監看/快取時,自然會發生這種情況。

與 Endpoints 的比較

原始的 Endpoints API 提供了一種簡單直接的方式來追蹤 Kubernetes 中的網路端點。隨著 Kubernetes 叢集和服務 (Services) 規模擴大,需要處理更多流量並將更多流量傳送到更多後端 Pod 時,原始 API 的限制變得更加明顯。最值得注意的是,其中包括擴展到更多網路端點數量的挑戰。

由於 Service 的所有網路端點都儲存在單個 Endpoints 物件中,因此這些 Endpoints 物件可能會變得非常大。對於保持穩定的 Service(在很長一段時間內具有相同的端點集),影響不太明顯;即便如此,Kubernetes 的某些用例也無法得到很好的服務。

當 Service 有大量後端端點且工作負載頻繁擴展或頻繁推出新變更時,每次更新該 Service 的單個 Endpoints 物件都意味著 Kubernetes 叢集組件之間(在控制平面內,以及節點和 API 伺服器之間)的大量流量。這種額外流量也會產生 CPU 使用方面的成本。

使用 EndpointSlice,新增或移除單個 Pod 會觸發相同數量的更新給正在監看變更的客戶端,但在大規模情況下,這些更新訊息的大小要小得多。

EndpointSlice 還實現了圍繞新功能的創新,例如雙堆疊網路和拓撲感知路由。

下一步

上次修改時間:2024 年 3 月 14 日下午 2:28 PST:新增中繼資料以使用 API 參考連結的機制 (c889d9b251)