EndpointSlices
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 儲存關於端點的條件,這些條件可能對消費者有用。三個條件為 ready
、serving
和 terminating
。
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
條件。
注意
雖然serving
幾乎與 ready
相同,但新增它是為了防止破壞 ready
現有的含義。如果 ready
對於終止中的端點可能為 true
,則對於現有的客戶端來說可能是出乎意料的,因為從歷史上看,終止中的端點從未包含在 Endpoints 或 EndpointSlice API 中。因此,對於終止中的端點,ready
總是 false
,並且在 v1.20 版本中新增了一個新的條件 serving
,以便客戶端可以獨立於 ready
現有的語義來追蹤終止中 Pod 的就緒狀態。終止中
Kubernetes v1.22 [beta 版]
Terminating
是一種條件,表示端點是否正在終止中。對於 Pod 而言,這是指任何設定了刪除時間戳記的 Pod。
拓撲資訊
EndpointSlice 中的每個端點都可以包含相關的拓撲資訊。拓撲資訊包括端點的位置以及關於對應節點和區域的資訊。這些資訊在 EndpointSlice 上每個端點的以下欄位中提供
nodeName
- 此端點所在的節點名稱。zone
- 此端點所在的區域。
注意
在 v1 API 中,每個端點的 topology
實際上已被移除,取而代之的是專用的欄位 nodeName
和 zone
。
在 EndpointSlice
資源的 endpoint
欄位上設定任意拓撲欄位已被棄用,並且在 v1 API 中不受支援。相反地,v1 API 支援設定個別的 nodeName
和 zone
欄位。這些欄位會在 API 版本之間自動轉換。例如,v1beta1 API 中 topology
欄位中 "topology.kubernetes.io/zone"
鍵的值可以作為 v1 API 中的 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,但不會主動重新平衡它們。邏輯相當簡單明瞭
- 迭代現有的 EndpointSlice,移除不再需要的端點,並更新已變更的相符端點。
- 迭代在第一步中修改過的 EndpointSlice,並用任何需要的新端點填滿它們。
- 如果還有新的端點要新增,請嘗試將它們放入先前未變更的 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 客戶端監看/快取時,自然會發生這種情況。
注意
EndpointSlice API 的客戶端必須迭代與 Service 關聯的所有現有 EndpointSlice,並建立唯一的網路端點的完整清單。重要的是要提到端點可能會在不同的 EndpointSlice 中重複。
您可以找到關於如何執行此端點聚合和去重複的參考實作,作為 kube-proxy
中 EndpointSliceCache
程式碼的一部分。
與 Endpoints 的比較
原始的 Endpoints API 提供了一種簡單直接的方式來追蹤 Kubernetes 中的網路端點。隨著 Kubernetes 叢集和服務 (Services) 規模擴大,需要處理更多流量並將更多流量傳送到更多後端 Pod 時,原始 API 的限制變得更加明顯。最值得注意的是,其中包括擴展到更多網路端點數量的挑戰。
由於 Service 的所有網路端點都儲存在單個 Endpoints 物件中,因此這些 Endpoints 物件可能會變得非常大。對於保持穩定的 Service(在很長一段時間內具有相同的端點集),影響不太明顯;即便如此,Kubernetes 的某些用例也無法得到很好的服務。
當 Service 有大量後端端點且工作負載頻繁擴展或頻繁推出新變更時,每次更新該 Service 的單個 Endpoints 物件都意味著 Kubernetes 叢集組件之間(在控制平面內,以及節點和 API 伺服器之間)的大量流量。這種額外流量也會產生 CPU 使用方面的成本。
使用 EndpointSlice,新增或移除單個 Pod 會觸發相同數量的更新給正在監看變更的客戶端,但在大規模情況下,這些更新訊息的大小要小得多。
EndpointSlice 還實現了圍繞新功能的創新,例如雙堆疊網路和拓撲感知路由。
下一步
- 請參考使用服務連接應用程式教學
- 閱讀 EndpointSlice API 的 API 參考文件
- 閱讀 Endpoints API 的 API 參考文件