Kubernetes 端點切片(Endpoint Slices)

2022-05-06 14:55 更新

端點切片(Endpoint Slices)

FEATURE STATE: Kubernetes v1.21 [stable]

端點切片(EndpointSlices) 提供了一種簡單的方法來跟蹤 Kubernetes 集群中的網(wǎng)絡(luò)端點 (network endpoints)。它們?yōu)?nbsp;Endpoints 提供了一種可伸縮和可拓展的替代方案。

動機(jī) 

Endpoints API 提供了在 Kubernetes 跟蹤網(wǎng)絡(luò)端點的一種簡單而直接的方法。 不幸的是,隨著 Kubernetes 集群和 服務(wù) 逐漸開始為更多的后端 Pods 處理和發(fā)送請求,原來的 API 的局限性變得越來越明顯。 最重要的是那些因為要處理大量網(wǎng)絡(luò)端點而帶來的挑戰(zhàn)。

由于任一服務(wù)的所有網(wǎng)絡(luò)端點都保存在同一個 Endpoints 資源中,這類資源可能變得 非常巨大,而這一變化會影響到 Kubernetes 組件(比如主控組件)的性能,并 在 Endpoints 變化時產(chǎn)生大量的網(wǎng)絡(luò)流量和額外的處理。 EndpointSlice 能夠幫助你緩解這一問題,還能為一些諸如拓?fù)渎酚蛇@類的額外 功能提供一個可擴(kuò)展的平臺。

Endpoint Slice 資源 

在 Kubernetes 中,?EndpointSlice ?包含對一組網(wǎng)絡(luò)端點的引用。 指定選擇器后控制面會自動為設(shè)置了 選擇算符 的 Kubernetes 服務(wù)創(chuàng)建 EndpointSlice。 這些 EndpointSlice 將包含對與服務(wù)選擇算符匹配的所有 Pod 的引用。 EndpointSlice 通過唯一的協(xié)議、端口號和服務(wù)名稱將網(wǎng)絡(luò)端點組織在一起。 EndpointSlice 的名稱必須是合法的 DNS 子域名。

例如,下面是 Kubernetes 服務(wù) ?example ?的 EndpointSlice 資源示例。

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

默認(rèn)情況下,控制面創(chuàng)建和管理的 EndpointSlice 將包含不超過 100 個端點。 你可以使用 kube-controller-manager 的 ?--max-endpoints-per-slice? 標(biāo)志設(shè)置此值,最大值為 1000。

當(dāng)涉及如何路由內(nèi)部流量時,EndpointSlice 可以充當(dāng) kube-proxy 的決策依據(jù)。 啟用該功能后,在服務(wù)的端點數(shù)量龐大時會有可觀的性能提升。

地址類型

EndpointSlice 支持三種地址類型:

  • IPv4
  • IPv6
  • FQDN (完全合格的域名)

狀況

EndpointSlice API 存儲了可能對使用者有用的、有關(guān)端點的狀況。 這三個狀況分別是 ?ready?、?serving ?和 ?terminating?。

Ready(就緒)

?ready ?狀況是映射 Pod 的 ?Ready ?狀況的。 處于運(yùn)行中的 Pod,它的 ?Ready ?狀況被設(shè)置為 ?True?,應(yīng)該將此 EndpointSlice 狀況也設(shè)置為 ?true?。 出于兼容性原因,當(dāng) Pod 處于終止過程中,?ready ?永遠(yuǎn)不會為 ?true?。 消費(fèi)者應(yīng)參考 ?serving ?狀況來檢查處于終止中的 Pod 的就緒情況。 該規(guī)則的唯一例外是將 ?spec.publishNotReadyAddresses? 設(shè)置為 ?true ?的服務(wù)。 這些服務(wù)(Service)的端點將始終將 ?ready ?狀況設(shè)置為 ?true?。

Serving(服務(wù)中)

FEATURE STATE: Kubernetes v1.20 [alpha]

?serving ?狀況與 ?ready ?狀況相同,不同之處在于它不考慮終止?fàn)顟B(tài)。 如果 EndpointSlice API 的使用者關(guān)心 Pod 終止時的就緒情況,就應(yīng)檢查此狀況。

盡管 ?serving ?與 ?ready ?幾乎相同,但是它是為防止破壞 ?ready ?的現(xiàn)有含義而增加的。 如果對于處于終止中的端點,?ready ?可能是 ?true?,那么對于現(xiàn)有的客戶端來說可能是有些意外的, 因為從始至終,Endpoints 或 EndpointSlice API 從未包含處于終止中的端點。 出于這個原因,?ready ?對于處于終止中的端點 總是 ?false?, 并且在 v1.20 中添加了新的狀況 ?serving?,以便客戶端可以獨(dú)立于 ?ready ?的現(xiàn)有語義來跟蹤處于終止中的 Pod 的就緒情況。

Terminating(終止中)

FEATURE STATE: Kubernetes v1.20 [alpha]

?Terminating ?是表示端點是否處于終止中的狀況。 對于 Pod 來說,這是設(shè)置了刪除時間戳的 Pod。

拓?fù)湫畔?nbsp;

EndpointSlice 中的每個端點都可以包含一定的拓?fù)湫畔ⅰ?nbsp;拓?fù)湫畔ǘ它c的位置,對應(yīng)節(jié)點、可用區(qū)的信息。 這些信息體現(xiàn)為 EndpointSlices 的如下端點字段:

  • ?nodeName ?- 端點所在的 Node 名稱;
  • ?zone ?- 端點所處的可用區(qū)。

在 v1 API 中,逐個端點設(shè)置的 ?topology ?實際上被去除,以鼓勵使用專用 的字段 ?nodeName ?和 ?zone?。
對 ?EndpointSlice ?對象的 ?endpoint ?字段設(shè)置任意的拓?fù)浣Y(jié)構(gòu)信息這一操作已被 廢棄,不再被 v1 API 所支持。取而代之的是 v1 API 所支持的 ?nodeName ?和 ?zone ?這些獨(dú)立的字段。這些字段可以在不同的 API 版本之間自動完成轉(zhuǎn)譯。 例如,v1beta1 API 中 ?topology ?字段的 ?topology.kubernetes.io/zone? 取值可以 在 v1 API 中通過 ?zone ?字段訪問。

管理 

通常,控制面(尤其是端點切片的 控制器) 會創(chuàng)建和管理 EndpointSlice 對象。EndpointSlice 對象還有一些其他使用場景, 例如作為服務(wù)網(wǎng)格(Service Mesh)的實現(xiàn)。這些場景都會導(dǎo)致有其他實體 或者控制器負(fù)責(zé)管理額外的 EndpointSlice 集合。

為了確保多個實體可以管理 EndpointSlice 而且不會相互產(chǎn)生干擾,Kubernetes 定義了 標(biāo)簽 ?endpointslice.kubernetes.io/managed-by?,用來標(biāo)明哪個實體在管理某個 EndpointSlice。端點切片控制器會在自己所管理的所有 EndpointSlice 上將該標(biāo)簽值設(shè)置 為 ?endpointslice-controller.k8s.io?。 管理 EndpointSlice 的其他實體也應(yīng)該為此標(biāo)簽設(shè)置一個唯一值。

屬主關(guān)系 

在大多數(shù)場合下,EndpointSlice 都由某個 Service 所有,(因為)該端點切片正是 為該服務(wù)跟蹤記錄其端點。這一屬主關(guān)系是通過為每個 EndpointSlice 設(shè)置一個 屬主(owner)引用,同時設(shè)置 ?kubernetes.io/service-name? 標(biāo)簽來標(biāo)明的, 目的是方便查找隸屬于某服務(wù)的所有 EndpointSlice。

EndpointSlice 鏡像 

在某些場合,應(yīng)用會創(chuàng)建定制的 Endpoints 資源。為了保證這些應(yīng)用不需要并發(fā) 的更改 Endpoints 和 EndpointSlice 資源,集群的控制面將大多數(shù) Endpoints 映射到對應(yīng)的 EndpointSlice 之上。

控制面對 Endpoints 資源進(jìn)行映射的例外情況有:

  • Endpoints 資源上標(biāo)簽 ?endpointslice.kubernetes.io/skip-mirror? 值為 ?true?。
  • Endpoints 資源包含標(biāo)簽 ?control-plane.alpha.kubernetes.io/leader?。
  • 對應(yīng)的 Service 資源不存在。
  • 對應(yīng)的 Service 的選擇算符不為空。

每個 Endpoints 資源可能會被翻譯到多個 EndpointSlices 中去。 當(dāng) Endpoints 資源中包含多個子網(wǎng)或者包含多個 IP 地址族(IPv4 和 IPv6)的端點時, 就有可能發(fā)生這種狀況。 每個子網(wǎng)最多有 1000 個地址會被鏡像到 EndpointSlice 中。

EndpointSlices 的分布問題 

每個 EndpointSlice 都有一組端口值,適用于資源內(nèi)的所有端點。 當(dāng)為服務(wù)使用命名端口時,Pod 可能會就同一命名端口獲得不同的端口號,因而需要 不同的 EndpointSlice。這有點像 Endpoints 用來對子網(wǎng)進(jìn)行分組的邏輯。

控制面嘗試盡量將 EndpointSlice 填滿,不過不會主動地在若干 EndpointSlice 之間 執(zhí)行再平衡操作。這里的邏輯也是相對直接的:

  1. 列舉所有現(xiàn)有的 EndpointSlices,移除那些不再需要的端點并更新那些已經(jīng) 變化的端點。
  2. 列舉所有在第一步中被更改過的 EndpointSlices,用新增加的端點將其填滿。
  3. 如果還有新的端點未被添加進(jìn)去,嘗試將這些端點添加到之前未更改的切片中, 或者創(chuàng)建新切片。

這里比較重要的是,與在 EndpointSlice 之間完成最佳的分布相比,第三步中更看重 限制 EndpointSlice 更新的操作次數(shù)。例如,如果有 10 個端點待添加,有兩個 EndpointSlice 中各有 5 個空位,上述方法會創(chuàng)建一個新的 EndpointSlice 而不是 將現(xiàn)有的兩個 EndpointSlice 都填滿。換言之,與執(zhí)行多個 EndpointSlice 更新操作 相比較,方法會優(yōu)先考慮執(zhí)行一個 EndpointSlice 創(chuàng)建操作。

由于 kube-proxy 在每個節(jié)點上運(yùn)行并監(jiān)視 EndpointSlice 狀態(tài),EndpointSlice 的 每次變更都變得相對代價較高,因為這些狀態(tài)變化要傳遞到集群中每個節(jié)點上。 這一方法嘗試限制要發(fā)送到所有節(jié)點上的變更消息個數(shù),即使這樣做可能會導(dǎo)致有 多個 EndpointSlice 沒有被填滿。

在實踐中,上面這種并非最理想的分布是很少出現(xiàn)的。大多數(shù)被 EndpointSlice 控制器 處理的變更都是足夠小的,可以添加到某已有 EndpointSlice 中去的。并且,假使無法 添加到已有的切片中,不管怎樣都會快就會需要一個新的 EndpointSlice 對象。 Deployment 的滾動更新為重新為 EndpointSlice 打包提供了一個自然的機(jī)會,所有 Pod 及其對應(yīng)的端點在這一期間都會被替換掉。

重復(fù)的端點 

由于 EndpointSlice 變化的自身特點,端點可能會同時出現(xiàn)在不止一個 EndpointSlice 中。鑒于不同的 EndpointSlice 對象在不同時刻到達(dá) Kubernetes 的監(jiān)視/緩存中, 這種情況的出現(xiàn)是很自然的。 使用 EndpointSlice 的實現(xiàn)必須能夠處理端點出現(xiàn)在多個切片中的狀況。 關(guān)于如何執(zhí)行端點去重(deduplication)的參考實現(xiàn),你可以在 ?kube-proxy? 的 ?EndpointSlice ?實現(xiàn)中找到。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號