虛擬 IP 和服務代理
Kubernetes 叢集中的每個 節點都執行一個 kube-proxy(除非您已部署了自定義元件來替代 kube-proxy
)。
kube-proxy
元件負責為 type
為除 ExternalName
之外的 Service 實現虛擬 IP 機制。kube-proxy
的每個例項都會監視 Kubernetes 控制平面,以便新增和移除 Service 和 EndpointSlice 物件。對於每個 Service,kube-proxy
會呼叫適當的 API(取決於 kube-proxy
模式)來配置節點,以捕獲到 Service 的 clusterIP
和 port
的流量,並將該流量重定向到 Service 的某個端點(通常是 Pod,也可能是使用者提供的任意 IP 地址)。一個控制迴圈確保每個節點上的規則都與 API 伺服器指示的 Service 和 EndpointSlice 狀態可靠地同步。
使用 iptables 模式的 Service 虛擬 IP 機制
有時會有人問,為什麼 Kubernetes 依賴代理來將入站流量轉發到後端。其他方法呢?例如,是否可以配置具有多個 A 記錄(IPv6 為 AAAA)的 DNS 記錄,並依賴輪詢名稱解析?
使用代理來實現 Service 有幾個原因
- DNS 實現長期以來都未能遵守記錄 TTL,並且會在名稱查詢應過期後繼續快取結果。
- 有些應用程式只執行一次 DNS 查詢,並無限期地快取結果。
- 即使應用程式和庫進行了正確的重新解析,DNS 記錄的低 TTL 或零 TTL 也會給 DNS 帶來很高的負載,從而難以管理。
在本頁稍後,您可以閱讀有關各種 kube-proxy
實現的工作原理。總的來說,您應該注意,當執行 kube-proxy
時,核心級別規則可能會被修改(例如,可能會建立 iptables 規則),這些規則在某些情況下可能不會被清理,直到您重啟。因此,只有理解了在計算機上執行低級別、特權網路代理服務所帶來的後果的管理員才能執行 kube-proxy
。儘管 kube-proxy
可執行檔案支援 cleanup
函式,但該函式並非官方功能,因此只能按原樣使用。
此參考中的一些詳細資訊會引用一個示例:一個無狀態影像處理工作負載的後端 Pod,執行三個副本。這些副本是可互換的——前端不關心使用哪個後端。雖然構成後端集合的實際 Pod 可能會發生變化,但前端客戶端不需要知道這一點,也不需要自己跟蹤後端集合。
代理模式
kube-proxy
以不同的模式啟動,這由其配置決定。
在 Linux 節點上,kube-proxy
的可用模式包括
iptables
- 一種模式,其中
kube-proxy
使用 iptables 配置資料包轉發規則。 ipvs
- 一種模式,其中
kube-proxy
使用 ipvs 配置資料包轉發規則。 nftables
- 一種模式,其中
kube-proxy
使用 nftables 配置資料包轉發規則。
Windows 上 kube-proxy
只有一種可用模式
kernelspace
- 一種模式,其中
kube-proxy
在 Windows 核心中配置資料包轉發規則
iptables
代理模式
此代理模式僅在 Linux 節點上可用。
在此模式下,kube-proxy
使用核心 netfilter 子系統的 iptables API 配置資料包轉發規則。對於每個端點,它會安裝 iptables 規則,這些規則預設會隨機選擇一個後端 Pod。
示例
例如,考慮頁面前面描述的影像處理應用程式。當建立後端 Service 時,Kubernetes 控制平面會分配一個虛擬 IP 地址,例如 10.0.0.1。在此示例中,假設 Service 埠為 1234。叢集中的所有 kube-proxy
例項都會觀察到新 Service 的建立。
當節點上的 kube-proxy
看到新 Service 時,它會安裝一系列 iptables 規則,將流量從虛擬 IP 地址重定向到為每個 Service 定義的更多 iptables 規則。每個 Service 的規則連結到每個後端端點的進一步規則,而每個端點的規則(使用目標 NAT)將流量重定向到後端。
當客戶端連線到 Service 的虛擬 IP 地址時,iptables 規則會生效。選擇一個後端(基於會話親和性或隨機選擇),並將資料包重定向到後端,而無需重寫客戶端 IP 地址。
當流量透過 type: NodePort
Service 或負載均衡器進入時,會執行相同的基本流程,儘管在這些情況下客戶端 IP 地址確實會被更改。
最佳化 iptables 模式的效能
在 iptables 模式下,kube-proxy
為每個 Service 建立少量 iptables 規則,為每個端點 IP 地址建立少量 iptables 規則。在擁有數萬個 Pod 和 Service 的叢集中,這意味著數萬條 iptables 規則,並且當 Service(或其 EndpointSlices)發生更改時,kube-proxy
可能需要很長時間才能更新核心中的規則。您可以透過 kube-proxy
配置檔案中 iptables
部分的選項來調整 kube-proxy
的同步行為(透過 kube-proxy --config <path>
指定)。
...
iptables:
minSyncPeriod: 1s
syncPeriod: 30s
...
minSyncPeriod
minSyncPeriod
引數設定在嘗試將 iptables 規則與核心重新同步之間的最小持續時間。如果設定為 0s
,則 kube-proxy
每次更改任何 Service 或 EndpointSlice 時都會立即同步規則。這在非常小的叢集中效果很好,但在短時間內發生大量更改時會導致大量重複工作。例如,如果您有一個由 100 個 Pod 的 Deployment 支援的 Service,並且刪除了該 Deployment,那麼在 minSyncPeriod: 0s
的情況下,kube-proxy
將逐個從 iptables 規則中刪除 Service 的端點,總共會進行 100 次更新。透過更大的 minSyncPeriod
,多個 Pod 刪除事件將聚合在一起,因此 kube-proxy
可能最終只進行 5 次更新,每次刪除 20 個端點,這在 CPU 使用方面效率更高,並且會更快地同步完整的更改集。
minSyncPeriod
的值越大,可以聚合的工作就越多,但缺點是每次更改最多可能需要等待完整的 minSyncPeriod
才能得到處理,這意味著 iptables 規則花費更長的時間與當前 API 伺服器狀態不同步。
預設值 1s
在大多數叢集中應該效果很好,但在非常大的叢集中,可能需要將其設定為更大的值。特別是,如果 kube-proxy
的 sync_proxy_rules_duration_seconds
指標顯示平均時間遠大於 1 秒,那麼提高 minSyncPeriod
可能會使更新更有效。
更新舊版 minSyncPeriod
配置
舊版本的 kube-proxy
在每次同步時都會更新所有 Service 的所有規則;這導致大型叢集出現效能問題(更新延遲),並且推薦的解決方案是設定更大的 minSyncPeriod
。自 Kubernetes v1.28 起,kube-proxy
的 iptables 模式使用更精簡的方法,僅在 Service 或 EndpointSlices 實際發生更改時才進行更新。
如果您之前覆蓋了 minSyncPeriod
,則應嘗試刪除該覆蓋,讓 kube-proxy
使用預設值(1s
)或至少是升級前所用值的一個較小值。
如果您執行的不是 Kubernetes 1.34 的 kube-proxy
,請檢查您實際執行的版本相關的行為和建議。
syncPeriod
syncPeriod
引數控制一些與 Service 和 EndpointSlice 的單獨更改不直接相關的同步操作。特別是,它控制 kube-proxy
注意到外部元件何時干擾了 kube-proxy
的 iptables 規則。在大型叢集中,kube-proxy
還每 syncPeriod
執行一次某些清理操作,以避免不必要的工作。
在大多數情況下,增加 syncPeriod
不會明顯影響效能,但在過去,將其設定為非常大的值(例如 1h
)有時很有用。現在不推薦這樣做,並且很可能會損害功能而非提高效能。
IPVS 代理模式
此代理模式僅在 Linux 節點上可用。
在 ipvs
模式下,kube-proxy
使用核心 IPVS 和 iptables API 來建立規則,將流量從 Service IP 重定向到端點 IP。
IPVS 代理模式基於 netfilter 鉤子函式,該函式類似於 iptables 模式,但使用雜湊表作為底層資料結構並在核心空間工作。這意味著 IPVS 模式下的 kube-proxy
相比 iptables 模式下的 kube-proxy
具有更低的延遲來重定向流量,並在同步代理規則時具有更好的效能。與 iptables 代理模式相比,IPVS 模式還支援更高的網路流量吞吐量。
IPVS 為將流量負載均衡到後端 Pod 提供了更多選項,這些選項是
rr
(Round Robin):流量在後端伺服器之間平均分配。wrr
(Weighted Round Robin):流量根據伺服器的權重路由到後端伺服器。權重較高的伺服器接收新連線並獲得比權重較低的伺服器更多的請求。lc
(Least Connection):將更多流量分配給連線數較少的伺服器。wlc
(Weighted Least Connection):將更多流量路由到連線數相對其權重較少的伺服器,即連線數除以權重。lblc
(Locality based Least Connection):發往同一 IP 地址的流量會被髮送到同一後端伺服器,前提是該伺服器未過載且可用;否則,流量會被髮送到連線數較少的伺服器,並保留供將來分配。lblcr
(Locality Based Least Connection with Replication):發往同一 IP 地址的流量會被髮送到連線數最少的伺服器。如果所有後端伺服器都過載,它會選擇一個連線數較少的伺服器並將其新增到目標集。如果目標集在指定時間內未更改,則會從集中移除負載最高的伺服器,以避免高度複製。sh
(Source Hashing):透過查詢基於源 IP 地址的靜態分配的雜湊表來將流量傳送到後端伺服器。dh
(Destination Hashing):透過查詢基於目標地址的靜態分配的雜湊表來將流量傳送到後端伺服器。sed
(Shortest Expected Delay):將流量轉發到預期延遲最短的後端伺服器。預期延遲為(C + 1) / U
,其中C
是伺服器上的連線數,U
是伺服器的固定服務速率(權重)。nq
(Never Queue):如果存在空閒伺服器,則將流量傳送到該伺服器,而不是等待快速的伺服器;如果所有伺服器都忙,則該演算法將回退到sed
行為。mh
(Maglev Hashing):根據Google 的 Maglev hashing 演算法分配入站作業。此排程程式有兩個標誌:mh-fallback
,它在選定的伺服器不可用時啟用回退到其他伺服器,以及mh-port
,它將源埠號新增到雜湊計算中。使用mh
時,kube-proxy
始終設定mh-port
標誌,而不啟用mh-fallback
標誌。在 proxy-mode=ipvs 中,mh
的工作方式類似於源雜湊(sh
),但增加了埠。
這些排程演算法透過 kube-proxy
配置中的 ipvs.scheduler
欄位進行配置。
注意
要執行 kube-proxy
的 IPVS 模式,您必須在啟動 kube-proxy
之前在節點上使 IPVS 可用。
當 kube-proxy
在 IPVS 代理模式下啟動時,它會驗證 IPVS 核心模組是否可用。如果未檢測到 IPVS 核心模組,則 kube-proxy
將退出並顯示錯誤。
使用 IPVS 模式的 Service 虛擬 IP 地址機制
nftables
代理模式
Kubernetes v1.33 [stable]
(預設啟用:true)此代理模式僅在 Linux 節點上可用,並且需要核心 5.13 或更高版本。
在此模式下,kube-proxy
使用核心 netfilter 子系統的 nftables API 配置資料包轉發規則。對於每個端點,它會安裝 nftables 規則,這些規則預設會隨機選擇一個後端 Pod。
nftables API 是 iptables API 的後繼者,旨在提供比 iptables 更好的效能和可擴充套件性。nftables
代理模式能夠比 iptables
模式更快、更有效地處理 Service 端點的更改,並且還能更有效地在核心中處理資料包(儘管這僅在擁有數萬個 Service 的叢集中才顯現出來)。
截至 Kubernetes 1.34,nftables
模式仍然相對較新,並且可能與所有網路外掛不相容;請參閱您的網路外掛文件。
從 iptables
模式遷移到 nftables
希望從預設的 iptables
模式切換到 nftables
模式的使用者應注意,在 nftables
模式下,某些功能的工作方式略有不同。
NodePort 介面:在
iptables
模式下,預設情況下,NodePort Service 在所有本地 IP 地址上都可訪問。這通常不是使用者想要的,因此nftables
模式預設為--nodeport-addresses primary
,這意味著使用type: NodePort
的 Service 僅在節點的 IPv4 和/或 IPv6 主要地址上可訪問。您可以透過為該選項指定顯式值來覆蓋此設定:例如,--nodeport-addresses 0.0.0.0/0
監聽所有(本地)IPv4 IP。type: NodePort
**Service on127.0.0.1
**:在iptables
模式下,如果--nodeport-addresses
範圍包含127.0.0.1
(並且未傳遞選項--iptables-localhost-nodeports false
),則type: NodePort
的 Service 甚至在“localhost”(127.0.0.1
)上也可訪問。在nftables
模式(和ipvs
模式)下,這將不起作用。如果您不確定是否依賴此功能,可以檢查kube-proxy
的iptables_localhost_nodeports_accepted_packets_total
指標;如果它非零,則意味著某個客戶端已透過 localhost/loopback 連線到type: NodePort
Service。NodePort 與防火牆的互動:
kube-proxy
的iptables
模式試圖與過於激進的防火牆相容;對於每個type: NodePort
Service,它會新增規則以接受該埠上的入站流量,以防流量被防火牆阻止。這種方法與基於 nftables 的防火牆不相容,因此kube-proxy
的nftables
模式在此不做任何處理;如果您有本地防火牆,必須確保它已正確配置以允許 Kubernetes 流量透過(例如,允許 NodePort 範圍上的入站流量)。Conntrack bug 解決方法:Linux 核心 6.1 之前的版本存在一個 bug,可能導致到 Service IP 的長期 TCP 連線以“Connection reset by peer”錯誤關閉。
kube-proxy
的iptables
模式為此 bug 安裝瞭解決方法,但後來發現此解決方法會在某些叢集中導致其他問題。nftables
模式預設不安裝任何解決方法,但您可以檢查kube-proxy
的iptables_ct_state_invalid_dropped_packets_total
指標,以檢視您的叢集是否依賴於此解決方法,如果是,您可以使用選項--conntrack-tcp-be-liberal
執行kube-proxy
來解決nftables
模式下的問題。
kernelspace
代理模式
此代理模式僅在 Windows 節點上可用。
kube-proxy
在 Windows虛擬過濾平臺 (VFP) 中配置資料包過濾規則,這是 Windows vSwitch 的一個擴充套件。這些規則處理節點級別虛擬網路中的封裝資料包,並重寫資料包,以使目標 IP 地址(和第 2 層資訊)正確,以便將資料包路由到正確的目標。Windows VFP 類似於 Linux 的 nftables
或 iptables
等工具。Windows VFP 擴充套件了Hyper-V Switch,最初是為了支援虛擬機器網路而實現的。
當節點上的 Pod 將流量傳送到虛擬 IP 地址,並且 kube-proxy
選擇了一個不同節點上的 Pod 作為負載均衡目標時,kernelspace
代理模式會將該資料包重寫為目標是目標後端 Pod。Windows主機網路服務 (HNS) 確保配置了資料包重寫規則,以便返回流量看起來像是來自虛擬 IP 地址,而不是特定的後端 Pod。
kernelspace
模式的直接伺服器返回
Kubernetes v1.34 [穩定]
(預設啟用:true)作為基本操作的替代方案,託管 Service 後端 Pod 的節點可以直接應用資料包重寫,而不是將此負擔放在執行客戶端 Pod 的節點上。這稱為直接伺服器返回。
要使用此功能,您必須執行 kube-proxy
並使用 --enable-dsr
命令列引數**並**啟用 WinDSR
功能門。
直接伺服器返回還可以最佳化 Pod 返回流量的情況,即使兩個 Pod 都在同一節點上執行。
會話親和性
在這些代理模型中,發往 Service IP:Port 的流量被代理到適當的後端,而客戶端對此一無所知 Kubernetes 或 Services 或 Pods。
如果您想確保來自特定客戶端的連線每次都傳遞到同一 Pod,可以透過將 Service 的 .spec.sessionAffinity
設定為 ClientIP
來基於客戶端 IP 地址選擇會話親和性(預設為 None
)。
會話粘性超時
您還可以透過為 Service 適當地設定 .spec.sessionAffinityConfig.clientIP.timeoutSeconds
來設定最大會話粘性時間。(預設值為 10800,相當於 3 小時)。
注意
在 Windows 上,不支援為 Service 設定最大會話粘性時間。分配 IP 地址給 Service
與實際路由到固定目標的 Pod IP 地址不同,Service IP 實際上不是由單個主機響應的。相反,kube-proxy
使用資料包處理邏輯(如 Linux iptables)來定義虛擬 IP 地址,這些地址會根據需要進行透明重定向。
當客戶端連線到 VIP 時,它們的流量會自動傳輸到適當的端點。Service 的環境變數和 DNS 實際上是根據 Service 的虛擬 IP 地址(和埠)填充的。
避免衝突
Kubernetes 的主要理念之一是您不應面臨因自身過錯而導致操作失敗的情況。對於 Service 資源的設計,這意味著不讓您選擇自己的 IP 地址,因為該選擇可能與其他人的選擇發生衝突。這是隔離失敗。
為了讓您為 Service 選擇 IP 地址,我們必須確保沒有兩個 Service 會發生衝突。Kubernetes 透過從為 API Server 配置的 service-cluster-ip-range
CIDR 範圍中為每個 Service 分配其自己的 IP 地址來做到這一點。
IP 地址分配跟蹤
為了確保每個 Service 獲得唯一的 IP 地址,一個內部分配器在建立每個 Service 之前,會原子地更新 etcd 中的全域性分配對映。對映物件必須存在於登錄檔中,Service 才能獲得 IP 地址分配,否則建立將失敗並顯示一條訊息,表明無法分配 IP 地址。
在控制平面中,一個後臺控制器負責建立該對映(支援從使用記憶體鎖定的舊版本 Kubernetes 遷移)。Kubernetes 還使用控制器來檢查無效分配(例如,由於管理員干預)以及清理不再被任何 Service 使用的已分配 IP 地址。
使用 Kubernetes API 進行 IP 地址分配跟蹤
Kubernetes v1.33 [stable]
(預設啟用:true)控制平面用一個修改後的實現替換現有的 etcd 分配器,該實現使用 IPAddress 和 ServiceCIDR 物件而不是內部全域性分配對映。與 Service 關聯的每個叢集 IP 地址隨後引用一個 IPAddress 物件。
啟用功能門還會用一個替代項替換後臺控制器,該替代項處理 IPAddress 物件並支援從舊分配器模型遷移。Kubernetes 1.34 不支援從 IPAddress 物件遷移到內部分配對映。
修改後分配器的一個主要優點是它消除了可用於 Service 叢集 IP 地址的 IP 地址範圍的大小限制。啟用 MultiCIDRServiceAllocator
後,IPv4 沒有限制,對於 IPv6,您可以使用 /64 或更小的 IP 地址網路掩碼(與舊實現的 /108 相反)。
透過 API 使 IP 地址分配可用意味著您作為叢集管理員可以允許使用者檢查分配給其 Service 的 IP 地址。Kubernetes 擴充套件(如 Gateway API)可以使用 IPAddress API 來擴充套件 Kubernetes 的固有網路功能。
以下是使用者查詢 IP 地址的簡短示例
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 2001:db8:1:2::1 <none> 443/TCP 3d1h
kubectl get ipaddresses
NAME PARENTREF
2001:db8:1:2::1 services/default/kubernetes
2001:db8:1:2::a services/kube-system/kube-dns
Kubernetes 還允許使用者使用 ServiceCIDR 物件動態定義 Service 的可用 IP 範圍。在啟動期間,一個名為 kubernetes
的預設 ServiceCIDR 物件會從 kube-apiserver 的 --service-cluster-ip-range
命令列引數值建立。
kubectl get servicecidrs
NAME CIDRS AGE
kubernetes 10.96.0.0/28 17m
使用者可以建立或刪除新的 ServiceCIDR 物件來管理 Service 的可用 IP 範圍。
cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: ServiceCIDR
metadata:
name: newservicecidr
spec:
cidrs:
- 10.96.0.0/24
EOF
servicecidr.networking.k8s.io/newcidr1 created
kubectl get servicecidrs
NAME CIDRS AGE
kubernetes 10.96.0.0/28 17m
newservicecidr 10.96.0.0/24 7m
Kubernetes 叢集的發行版或管理員可能希望控制新增到叢集的新 Service CIDR 不會與其他屬於特定 IP 範圍的網路發生重疊,或者只是簡單地保留每個叢集只有一個 ServiceCIDR 的現有行為。實現此目的的驗證 Admission 策略示例是
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "servicecidrs-default"
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["networking.k8s.io"]
apiVersions: ["v1","v1beta1"]
operations: ["CREATE", "UPDATE"]
resources: ["servicecidrs"]
matchConditions:
- name: 'exclude-default-servicecidr'
expression: "object.metadata.name != 'kubernetes'"
variables:
- name: allowed
expression: "['10.96.0.0/16','2001:db8::/64']"
validations:
- expression: "object.spec.cidrs.all(i , variables.allowed.exists(j , cidr(j).containsCIDR(i)))"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: "servicecidrs-binding"
spec:
policyName: "servicecidrs-default"
validationActions: [Deny,Audit]
---
Service 虛擬 IP 地址的 IP 地址範圍
Kubernetes v1.26 [stable]
Kubernetes 使用以下公式 min(max(16, cidrSize / 16), 256)
將 ClusterIP
範圍劃分為兩個段,基於配置的 service-cluster-ip-range
的大小。該公式意味著結果永不小於 16 或大於 256,它們之間有一個漸進的步進函式。
Kubernetes 傾向於透過從上層選擇來分配動態 IP 地址給 Service,這意味著如果您想為 type: ClusterIP
Service 分配特定 IP 地址,則應從較低段手動分配 IP 地址。這種方法減少了分配衝突的風險。
流量策略
您可以設定 .spec.internalTrafficPolicy
和 .spec.externalTrafficPolicy
欄位來控制 Kubernetes 如何將流量路由到健康的(“ready”)後端。
內部流量策略
Kubernetes v1.26 [stable]
您可以設定 .spec.internalTrafficPolicy
欄位來控制從內部源的流量如何路由。有效值為 Cluster
和 Local
。將該欄位設定為 Cluster
以將內部流量路由到所有就緒端點,設定為 Local
以僅路由到就緒的節點本地端點。如果流量策略為 Local
且沒有節點本地端點,則流量將被 kube-proxy
丟棄。
外部流量策略
您可以設定 .spec.externalTrafficPolicy
欄位來控制從外部源的流量如何路由。有效值為 Cluster
和 Local
。將該欄位設定為 Cluster
以將外部流量路由到所有就緒端點,設定為 Local
以僅路由到就緒的節點本地端點。如果流量策略為 Local
且沒有節點本地端點,則 kube-proxy
不會轉發任何相關 Service 的流量。
如果指定了 Cluster
,則所有節點都是合格的負載均衡目標,*前提是*節點未被刪除且 kube-proxy
健康。在此模式下:負載均衡器健康檢查配置為將目標指向 Service 代理的就緒埠和路徑。對於 kube-proxy
,這評估為:${NODE_IP}:10256/healthz
。kube-proxy
將返回 HTTP 程式碼 200 或 503。kube-proxy
的負載均衡器健康檢查端點返回 200 如果
kube-proxy
健康,這意味著它能夠進行網路程式設計並且在此過程中沒有超時(超時定義為:2 ×
iptables.syncPeriod
);並且節點未被刪除(Node 沒有設定刪除時間戳)。
kube-proxy
返回 503 並將節點標記為不合格,因為它支援終止節點的連線排水。從 Kubernetes 管理的負載均衡器的角度來看,當節點正在/被刪除時,會發生一些重要的事情。
正在刪除時
kube-proxy
將開始使其就緒探測失敗,並有效地將節點標記為不合格接收負載均衡器流量。負載均衡器健康檢查失敗會導致支援連線排水的負載均衡器允許現有連線終止,並阻止新連線建立。
已刪除時
- Kubernetes 雲控制器管理器中的 Service 控制器會從引用的合格目標集中移除該節點。從負載均衡器的後端目標集中移除任何例項會立即終止所有連線。這也是為什麼
kube-proxy
在節點刪除時首先會使健康檢查失敗的原因。
對於 Kubernetes 供應商來說,重要的是要注意,如果任何供應商將 kube-proxy
的就緒探測配置為活躍探測:那麼 kube-proxy
將在節點刪除時開始不斷重啟,直到節點完全刪除。kube-proxy
暴露了 /livez
路徑,與 /healthz
路徑不同,它不考慮節點的刪除狀態,只考慮其網路程式設計的進度。因此,對於任何想要為 kube-proxy
定義活躍探測的人來說,/livez
是推薦的路徑。
部署 kube-proxy
的使用者可以透過評估指標來檢查就緒/活躍狀態:proxy_livez_total
/ proxy_healthz_total
。這兩個指標都發布兩個序列,一個帶有 200 標籤,一個帶有 503 標籤。
對於 Local
Service:kube-proxy
將返回 200 如果
kube-proxy
健康/就緒,並且- 在相關節點上有本地端點。
節點刪除不影響 kube-proxy
關於負載均衡器健康檢查的返回程式碼。原因如下:刪除節點可能會導致入站中斷,如果所有端點同時在該節點上執行。
Kubernetes 專案建議雲提供商整合程式碼將負載均衡器健康檢查配置為指向 Service 代理的 healthz 埠。如果您正在使用或實現自己的虛擬 IP 實現來替代 kube-proxy
,您應該設定一個類似的健康檢查埠,其邏輯與 kube-proxy
實現匹配。
發往終止端點的流量
Kubernetes v1.28 [stable]
如果 ProxyTerminatingEndpoints
功能門在 kube-proxy
中啟用且流量策略為 Local
,則該節點的 kube-proxy
使用更復雜的演算法來選擇 Service 的端點。啟用該功能後,kube-proxy
會檢查節點是否具有本地端點以及所有本地端點是否被標記為終止。如果存在本地端點且所有本地端點都正在終止,則 kube-proxy
會將流量轉發到這些終止的端點。否則,kube-proxy
始終優先將流量轉發到未終止的端點。
這種終止端點的轉發行為是為了允許 NodePort
和 LoadBalancer
Service 在使用 externalTrafficPolicy: Local
時優雅地排水連線。
隨著部署進行滾動更新,負載均衡器後面的節點可能會從該部署的 N 個副本轉換到 0 個副本。在某些情況下,外部負載均衡器可以在健康檢查探測之間將流量傳送到具有 0 個副本的節點。路由到終止端點可確保正在縮減 Pod 的節點能夠優雅地接收並排水到這些終止 Pod 的流量。當 Pod 完成終止時,外部負載均衡器應已看到節點的健康檢查失敗,並已將節點完全從後端池中移除。
流量分佈
Kubernetes v1.33 [stable]
(預設啟用:true)Kubernetes Service 中的 spec.trafficDistribution
欄位允許您表達將流量路由到 Service 端點的偏好。
PreferClose
- 這會優先將流量傳送到與客戶端同一區域的端點。EndpointSlice 控制器會使用
hints
更新 EndpointSlices 來傳達此偏好,kube-proxy
然後會使用這些資訊進行路由決策。如果客戶端所在區域沒有可用的端點,流量將為該客戶端進行叢集範圍路由。
Kubernetes v1.34 [beta]
(預設啟用:true)在 Kubernetes 1.34 中,有兩個附加值可用(除非 PreferSameTrafficDistribution
功能門被停用)
PreferSameZone
- 這與
PreferClose
含義相同,但更明確。(最初的意圖是PreferClose
後來可能包含“偏好同一區域”之外的功能,但這已不再計劃。將來,PreferSameZone
將成為此功能的推薦值,而PreferClose
將被視為其已棄用的別名。) PreferSameNode
- 這會優先將流量傳送到與客戶端同一節點的端點。與
PreferClose
/PreferSameZone
一樣,EndpointSlice 控制器會使用hints
更新 EndpointSlices,表明某個切片應用於特定節點。如果客戶端節點沒有可用的端點,則 Service 代理將回退到“同一區域”行為,如果沒有同一區域的端點,則回退到叢集範圍。
在 trafficDistribution
沒有值的情況下,預設策略是將流量均勻分佈到叢集中的所有端點。
與 service.kubernetes.io/topology-mode: Auto
的比較
trafficDistribution
欄位(帶 PreferClose
/PreferSameZone
)以及使用 service.kubernetes.io/topology-mode: Auto
註解的舊版“拓撲感知路由”功能都旨在優先處理同一區域的流量。但是,它們的方法存在關鍵差異
service.kubernetes.io/topology-mode: Auto
嘗試根據可分配的 CPU 資源按區域比例分配流量。此啟發式方法包括安全措施(例如,對於少量端點的回退行為),為了可能更好的負載均衡而犧牲了一些可預測性。trafficDistribution: PreferClose
旨在更簡單、更可預測:“如果區域中有端點,它們將接收該區域的所有流量;如果區域中沒有端點,流量將分配到其他區域”。這種方法提供了更高的可預測性,但這意味著您負責避免端點過載。
如果設定了 service.kubernetes.io/topology-mode
註解為 Auto
,它將優先於 trafficDistribution
。將來可能會棄用該註解,以 trafficDistribution
欄位為準。
與流量策略的互動
與 trafficDistribution
欄位相比,流量策略欄位(externalTrafficPolicy
和 internalTrafficPolicy
)旨在提供更嚴格的流量區域性性要求。trafficDistribution
與它們的互動方式如下:
流量策略的優先順序:對於給定的 Service,如果流量策略(
externalTrafficPolicy
或internalTrafficPolicy
)設定為Local
,它將優先於相應流量型別(外部或內部)的trafficDistribution
。trafficDistribution
的影響:對於給定的 Service,如果流量策略(externalTrafficPolicy
或internalTrafficPolicy
)設定為Cluster
(預設),或者未設定這些欄位,則trafficDistribution
將指導相應流量型別(外部或內部)的路由行為。這意味著將嘗試將流量路由到與客戶端同一區域的端點。
使用流量分佈控制的注意事項
使用 trafficDistribution
的 Service 將嘗試將流量路由到(健康的)拓撲內的端點,即使這意味著某些端點接收的流量遠多於其他端點。如果您沒有足夠數量的端點與客戶端在同一拓撲(“同一區域”、“同一節點”等)中,則端點可能會過載。如果入站流量未在拓撲中成比例分佈,這種情況尤其可能發生。為緩解此問題,請考慮以下策略:
Pod 拓撲擴散約束:使用 Pod 拓撲擴散約束將 Pod 均勻分佈到區域或節點。
區域特定部署:如果您正在使用“同一區域”流量分發,但預計不同區域會看到不同的流量模式,則可以為每個區域建立單獨的 Deployment。這種方法允許獨立的應用程式獨立擴充套件。此外,在 Kubernetes 專案本身之外的生態系統中,也有可用的工作負載管理外掛可以幫助解決此問題。
下一步
要了解更多關於 Service 的資訊,請閱讀使用 Service 連線應用程式。
您還可以