iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Kubernetes

從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作系列 第 5

Day 05|Service 背後的秘密 — kube-proxy 與流量轉發機制

  • 分享至 

  • xImage
  •  

前言

昨天我們體驗了三種 Service 類型,知道 Service 能提供穩定入口、自動負載均衡。

但你有沒有想過:當流量打到 Service 的 ClusterIP,到底是「誰」在背後把封包轉給正確的 Pod?

答案不是魔法,而是一套很具體的機制:Label Selector 決定「轉給誰」,kube-proxy 決定「怎麼轉」。

今天我們會從三個層面拆解 Service 的運作原理:

  1. Label Selector — Service 怎麼知道後端有哪些 Pod?
  2. Endpoints — Selector 的結果存在哪裡?
  3. kube-proxy — 流量轉發的真正執行者(iptables / nftables / IPVS)

以下操作皆在 master 節點 執行,沿用 Day 4 的 php-apache Deployment 與 Service。


一、Label Selector — Service 怎麼找到 Pod?

Service 不是靠 Pod 名稱或 IP 來找後端的,而是靠 Label(標籤)

看看 Pod 上的 Label

kubectl get pods --show-labels

你會看到每個 Pod 都帶著 app=php-apache 這個標籤。

看看 Service 的 Selector

kubectl describe svc php-apache

https://ithelp.ithome.com.tw/upload/images/20260807/20181928kt3c43sJl5.png

在輸出中找到 Selector 欄位:

Selector: app=php-apache

這代表什麼? Kubernetes 會持續找出叢集中所有帶有 app=php-apache Label 的 Pod。只要 Pod 符合 Selector 條件且處於 Ready 狀態,Service 就可以將流量轉送到這些 Pod。

💡 Label Selector 的核心邏輯:

Service 不關心 Pod 叫什麼名字、IP 是多少,它只看 Label 有沒有 match

這就是為什麼 Pod 重建後(名字和 IP 都變了),Service 依然能找到它 — 因為新 Pod 的 Label 沒變。

實驗:手動改 Label,Pod 會被踢出 Service 嗎?

挑其中一個 Pod,把它的 Label 改掉:

kubectl label pod php-apache-6d768f465b-6drng app=removed --overwrite

kubectl get pods --show-labels 確認一下:

https://ithelp.ithome.com.tw/upload/images/20260807/20181928lLR6gbJsYn.png

可以看到 php-apache-6d768f465b-6drng 的 Label 已經從 app=php-apache 變成 app=removed,因此不再符合 Service 的 Selector 條件,也就不會再接收到 Service 轉送的流量。

Service 透過 Selector 找到的 Pod 清單,會被記錄在 Endpoints(或更新的 EndpointSlice)裡,你可以用以下指令確認目前有幾個 Pod 在 Service 後面:

# 查看 EndpointSlice(推薦,1.33+)
kubectl get endpointslices -l kubernetes.io/service-name=php-apache

# 或傳統方式
kubectl get endpoints php-apache

https://ithelp.ithome.com.tw/upload/images/20260807/20181928YopJV08HSn.png

簡單來說,Endpoints 就是一份動態的 Pod IP + Port 清單,每當 Pod 新增、刪除或變成 Not Ready,它都會自動更新。kube-proxy 就是靠讀取這份清單來決定流量要轉給誰。

💡 這個實驗證明了:Label 是 Service 和 Pod 之間唯一的連結。改掉 Label = 斷開連線。

Endpoints vs EndpointSlice

舊的 Endpoints 會將所有後端端點集中在同一個物件中。當 Pod 數量很多時,每次更新都需要處理整份資料。

EndpointSlice 則會將端點拆分成多個 Slice(預設每個 Slice 最多約 100 個端點),當後端發生變動時,只需更新受影響的 Slice,因此在效能與擴展性上更適合大型叢集。

Kubernetes 1.33 起已將 Endpoints API 標記為 deprecated,建議優先使用 EndpointSlice。


二、kube-proxy — 真正做轉發的人

現在我們知道 Service 靠 Label 找到 Pod,結果存在 Endpoints 裡。但 實際把封包從 ClusterIP 轉到 Pod IP 的是誰?

答案是 kube-proxy

kube-proxy 是跑在每一個 Node 上的元件,它會:

  1. 監聽 API Server 上 Service 和 Endpoints 的變化
  2. 設定轉發規則,讓打到 ClusterIP 的流量被導向真正的 Pod

確認 kube-proxy 正在運行

kubectl get pods -n kube-system -l k8s-app=kube-proxy

每個 Node 上都會有一個 kube-proxy Pod(以 DaemonSet 方式部署)。

查看 kube-proxy 的模式

kubectl get configmap kube-proxy -n kube-system -o yaml | grep mode

你會看到 mode 欄位,常見的值是 "" (空字串 = 預設 iptables)、"nftables""ipvs"


三、iptables vs nftables vs IPVS — 三種轉發模式的差異

kube-proxy 支援三種轉發模式,它們都能完成工作,但方式和效能各有不同。

iptables 模式(預設)

iptables 是 Linux 核心內建的封包過濾框架。在這個模式下,kube-proxy 會把每個 Service 的轉發規則寫成 iptables 規則鏈

讓我們來看看目前系統上的 iptables 規則。這裡用 -t nat 指定查看 NAT 表(因為 DNAT 轉發發生在這裡),-S 則是以指令格式列出所有規則:

sudo iptables -t nat -S KUBE-SERVICES

你會看到每個 Service 都對應一串規則,透過 DNAT(Destination NAT)將 ClusterIP 的流量轉發到後端 Pod IP。

https://ithelp.ithome.com.tw/upload/images/20260807/20181928s5sZjMppVP.png

iptables 的運作方式:

iptables

Client → ClusterIP:80
         ↓ (iptables DNAT)
         Pod-1:80  (機率 33%)
         Pod-2:80  (機率 33%)
         Pod-3:80  (機率 34%)

⚠️ iptables 模式的限制

  • iptables 規則主要依序進行匹配,當 Service 與 Endpoint 數量增加時,規則數量也會隨之增加。
  • 大量 Service 與後端 Pod 可能產生數千甚至上萬條 iptables 規則。
  • 當 Service 或後端端點發生變化時,kube-proxy 需要同步更新相關規則。
  • 在大規模叢集中,大量規則的同步與更新可能增加處理時間,並影響網路效能。

nftables 模式

nftables 是 Linux 核心中較新的封包過濾與封包處理框架,也被視為 iptables 的後繼技術。kube-proxy 在 Kubernetes 1.29 引入 nftables 模式(Alpha),並於 Kubernetes 1.33 達到 GA(General Availability,正式穩定版)。

nftables 的優勢:

  • 使用 map 等資料結構進行查找,相較於 iptables 的大量規則匹配,在 Service 數量較多時具有更好的效能與擴展性。
  • 支援更具增量性的規則更新,只需處理自上次同步後發生變化的 Service 與 Endpoint,不需要每次處理整份規則集。
  • 不需要像 IPVS 模式一樣依賴額外的 IPVS 核心模組與相關虛擬介面,整體架構較為直接。
  • nftables 是目前 Linux 網路封包處理的重要發展方向,也被 Kubernetes 視為 kube-proxy 未來較推薦的模式。

如何切換到 nftables 模式?

nftables 不需要額外的核心模組,直接編輯 kube-proxy 的 ConfigMap:

kubectl edit configmap kube-proxy -n kube-system

mode 改成 "nftables",然後重啟 kube-proxy:

kubectl rollout restart daemonset kube-proxy -n kube-system

驗證切換成功:

kubectl logs -n kube-system -l k8s-app=kube-proxy | grep "Using nftables"

nftables 的定位

nftables 是 kube-proxy 較新的代理模式,主要用來改善 iptables 在大規模叢集中的效能與規則更新效率。

相較於 iptables,nftables 可以利用 map 等資料結構進行更有效率的查找,並支援較具增量性的規則更新,因此在 Service 與 Endpoint 數量較多時具有更好的擴展性。

目前 iptables 仍是 kube-proxy 的預設模式,但 Kubernetes 已將 nftables 視為未來建議採用的方向,並建議原本使用 IPVS 的環境評估遷移至 nftables。


IPVS 模式

IPVS(IP Virtual Server)是 Linux 核心中專門做負載均衡的模組,效能遠優於 iptables。

IPVS

IPVS 的優勢:

  • 使用 hash table 查找,時間複雜度 O(1),不隨 Service 數量增加而變慢
  • 支援更多負載均衡演算法(Round Robin、Least Connections、Source Hashing 等)
  • 規則更新是增量式的,不需要整組重寫

如何切換到 IPVS 模式?

先確認 Node 上有載入必要的核心模組:

sudo modprobe ip_vs
sudo modprobe ip_vs_rr
sudo modprobe ip_vs_wrr
sudo modprobe ip_vs_sh
lsmod | grep ip_vs

然後編輯 kube-proxy 的 ConfigMap:

kubectl edit configmap kube-proxy -n kube-system

mode 改成 "ipvs",然後重啟 kube-proxy:

kubectl rollout restart daemonset kube-proxy -n kube-system

驗證切換成功:

kubectl logs -n kube-system -l k8s-app=kube-proxy | grep "Using ipvs"

如果看到 Using ipvs Proxier 就代表成功了。

什麼時候會使用 IPVS?

  • 當叢集中有大量 Service 與 Endpoint,iptables 規則數量過多、效能開始受到影響時,可考慮使用 IPVS。
  • IPVS 支援多種負載均衡演算法,例如 Round Robin、Least Connection 等。
  • IPVS 過去常用於大型 Kubernetes 叢集,但隨著 nftables 模式成熟,新建環境已不建議優先選擇 IPVS,可優先評估 nftables。

三種模式比較

比較項目 iptables nftables IPVS
查找方式 規則匹配,規模增大時成本較高 Map / Set 查找,接近 O(1) Hash-based 查找
負載均衡方式 隨機選擇後端 隨機選擇後端 支援 RR、LC、SH 等多種 scheduler
規則更新 仍需處理與整體規模相關的規則更新 增量更新,只處理變動的 Service / Endpoint 增量更新
額外核心模組 不需要 不需要 需載入 ip_vs 等核心模組
適合情境 相容性優先、一般規模叢集 新建中大型叢集,較推薦 既有大型叢集或特定需求
目前狀態 預設模式 Kubernetes 1.33 GA,需手動啟用 可用,但新環境不建議優先採用

四、完整流量路徑圖

把今天學到的串起來,一個請求從 Client 到 Pod 的完整路徑:

Client
  │
  ▼
Service(ClusterIP)
  │
  │  ① Service 的 Selector 定義要選取哪些 Pod
  │     → 控制平面更新 EndpointSlice
  │
  │  ② kube-proxy 監看 Service / EndpointSlice
  │     → 設定流量轉送規則
  │
  ▼
kube-proxy(iptables / nftables / IPVS)
  │
  │  根據轉送規則選擇一個 Endpoint
  │  並將流量導向對應的 Pod
  │
  ▼
Pod(實際處理請求)

小結

今天我們拆解了 Service 背後的完整機制:

元件 角色 說明
Label Selector 定義後端 Pod Service 透過 Label Selector 指定哪些 Pod 屬於自己的後端。
EndpointSlice 記錄後端端點 控制平面根據 Selector 結果,動態維護可供 Service 使用的後端 IP 與 Port。
kube-proxy 設定流量轉送規則 執行於各個 Node,監看 Service 與 EndpointSlice,並建立對應的流量轉送規則。
iptables / nftables / IPVS 實作封包轉送 kube-proxy 可透過不同的 Linux 核心機制實作 Service 流量轉送,其中 nftables 是目前較新的方案。

今天我們先把 Service 的運作方式拆清楚,了解它如何透過 Selector、EndpointSlice 與 kube-proxy,將流量穩定導向後端 Pod。

不過,Service 解決的是「如何存取一組 Pod」的問題。當系統裡開始出現多個 Service,而且這些服務都需要對外提供 HTTP/HTTPS 存取時,就會遇到下一個問題:這些外部流量要怎麼統一管理與分流?

明天我們會接著介紹 Ingress,看看它如何透過單一入口與路由規則,將不同網域或路徑的流量導向對應的 Service!


參考資源


上一篇
Day 04|Service — 為 Pod 提供穩定的存取入口
下一篇
Day 06|Ingress — 統一管理外部流量入口
系列文
從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言