深入 K8s 网络原理(二)- Service iptables 模式分析
- 1. 概述
- 2. 準(zhǔn)備 Service 和 Pods 資源
-
3. K8s 里 Service 的實(shí)現(xiàn)原理
- 3.1 kube-proxy 組件
- 3.2 iptables 簡(jiǎn)介
-
3.3 iptables 規(guī)則
- 3.3.1 Service,Pod 和 Host 信息
- 3.3.2 從 NodePort 入手尋找 iptables 規(guī)則
- 3.3.3 從 PREROUTING 和 OUTPUT 鏈尋找 K8s 相關(guān)子鏈
- 3.3.4 總結(jié)下
- 4. 總結(jié)
1. 概述
接上一篇《深入 K8s 網(wǎng)絡(luò)原理(一)- Flannel VXLAN 模式分析》,今天我們繼續(xù)來(lái)分析 Kubernetes Service 的實(shí)現(xiàn)原理。
2. 準(zhǔn)備 Service 和 Pods 資源
鏡像和上一篇一樣;
Deployment 的 YAML 如下:
nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:test1
ports:
- containerPort: 80
對(duì)應(yīng)的 Service YAML 如下:
nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- protocol: TCP
port: 80
nodePort: 30007
3. K8s 里 Service 的實(shí)現(xiàn)原理
Kubernetes 提供了幾種不同類型的 Service,包括:
-
ClusterIP:這是最常見(jiàn)的 Service 類型,為 Service 提供一個(gè)集群內(nèi)部的 IP 地址,使得 Service 只能在集群內(nèi)部訪問(wèn)。 -
NodePort:這種類型的 Service 在每個(gè)節(jié)點(diǎn)上開(kāi)放一個(gè)端口(NodePort),從而允許從集群外部通過(guò) <NodeIP>:<NodePort> 訪問(wèn) Service。 -
LoadBalancer:這種類型的 Service 通常由云提供商支持,它會(huì)在集群外部創(chuàng)建一個(gè)負(fù)載均衡器,將外部流量分發(fā)到集群內(nèi)的 Pods。 -
ExternalName:通過(guò)返回一個(gè)名字(而非 IP 地址)來(lái)指向外部服務(wù)。
接著具體來(lái)看 Service 的實(shí)現(xiàn)。
3.1 kube-proxy 組件
Kubernetes 集群中每個(gè)節(jié)點(diǎn)上會(huì)運(yùn)行一個(gè)關(guān)鍵組件 kube-proxy,它負(fù)責(zé)為 Service 對(duì)象實(shí)現(xiàn)網(wǎng)絡(luò)代理,使得網(wǎng)絡(luò)流量可以透明地定向到后端 Pods。kube-proxy 支持幾種不同的代理模式,最常見(jiàn)的是 iptables 模式和 IPVS 模式。
- iptables 模式
- 在這種模式下,kube-proxy 使用 iptables 規(guī)則來(lái)捕獲到達(dá) Service 的流量,并將其重定向到后端 Pods。每當(dāng) Service 或 Pod 發(fā)生變化時(shí),kube-proxy 都會(huì)更新 iptables 規(guī)則。
- iptables 模式是最簡(jiǎn)單且廣泛使用的,但在大規(guī)模集群中可能會(huì)面臨性能問(wèn)題,因?yàn)槊總€(gè)網(wǎng)絡(luò)包都需要通過(guò)不短的規(guī)則鏈進(jìn)行處理。
- IPVS (IP Virtual Server) 模式
- IPVS 模式使用內(nèi)核的 IPVS 功能,該功能提供了內(nèi)置的負(fù)載均衡功能。與 iptables 相比,IPVS 可以處理更大規(guī)模的流量,擁有更好的性能和更復(fù)雜的負(fù)載均衡算法(最少連接等)。
- 在這種模式下,kube-proxy 會(huì)創(chuàng)建一個(gè)虛擬服務(wù)器,為每個(gè) Service 分配一個(gè)虛擬 IP(VIP),并將流量負(fù)載均衡到后端 Pods。
以 kube-proxy 的 iptables 模式為例,我們具體來(lái)看下 Service 創(chuàng)建后,iptables 是如何將 Service 流量轉(zhuǎn)到 pods 上的。
3.2 iptables 簡(jiǎn)介
簡(jiǎn)單介紹下 iptables:
iptables是一種在 Linux 系統(tǒng)中廣泛使用的工具,它允許管理員配置內(nèi)核的 netfilter 模塊,以控制網(wǎng)絡(luò)數(shù)據(jù)包的流入流出。這個(gè)工具提供了一個(gè)框架,用于定義規(guī)則,這些規(guī)則決定了如何處理經(jīng)過(guò)網(wǎng)絡(luò)接口的數(shù)據(jù)包。iptables 的核心功能主要包括:
- 數(shù)據(jù)包過(guò)濾:iptables 最常用于過(guò)濾數(shù)據(jù)包,即決定哪些數(shù)據(jù)包可以通過(guò)網(wǎng)絡(luò)接口,哪些應(yīng)該被阻止。
- 網(wǎng)絡(luò)地址轉(zhuǎn)換 (NAT):它可以用于修改數(shù)據(jù)包的源或目的地址,常用于路由和隱藏內(nèi)部網(wǎng)絡(luò)結(jié)構(gòu)。
- 端口轉(zhuǎn)發(fā):iptables 可以重定向到特定端口的數(shù)據(jù)流,用于設(shè)置端口轉(zhuǎn)發(fā)。
剛從鋪灰的硬盤(pán)里發(fā)現(xiàn)一張三年前畫(huà)的 iptables 相關(guān)的圖(我都忘記這個(gè)圖應(yīng)該叫啥名字了):
3.3 iptables 規(guī)則
下面具體看下 Service 對(duì)應(yīng)的 iptables 規(guī)則。
3.3.1 Service,Pod 和 Host 信息
前面創(chuàng)建了 Service 和 Deployment,對(duì)應(yīng)的 Service 和 Pod 資源如下:
kgsvc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort 10.107.33.105 <none> 80:30007/TCP 152m
kgpoowide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment-7fbb8f4b4c-89bds 1/1 Running 0 155m 10.244.2.4 minikube-m03
nginx-deployment-7fbb8f4b4c-d29zm 1/1 Running 0 155m 10.244.1.5 minikube-m02
此外,我的 K8s 集群包括3個(gè)節(jié)點(diǎn),nodes 的 ip/hostname 信息如下:
192.168.49.2 minikube
192.168.49.3 minikube-m02
192.168.49.4 minikube-m03
3.3.2 從 NodePort 入手尋找 iptables 規(guī)則
現(xiàn)在進(jìn)到 minikube 節(jié)點(diǎn),也就是 K8s 主節(jié)點(diǎn),查看下 nat 表的鏈信息,過(guò)濾下 NodePort 端口 30007:
sudo iptables -t nat -L | grep 30007
KUBE-EXT-V2OKYYMBY3REGZOG tcp -- anywhere anywhere /* default/nginx-service */ tcp dpt:30007
可以看到一條鏈:KUBE-EXT-V2OKYYMBY3REGZOG,具體看下這條鏈的信息:
sudo iptables -t nat -L KUBE-EXT-V2OKYYMBY3REGZOG -v
Chain KUBE-EXT-V2OKYYMBY3REGZOG (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SVC-V2OKYYMBY3REGZOG all -- any any anywhere anywhere
從這里可以看到 KUBE-EXT-V2OKYYMBY3REGZOG 有一條子鏈 KUBE-SVC-V2OKYYMBY3REGZOG。繼續(xù)看 KUBE-SVC-V2OKYYMBY3REGZOG 鏈:
sudo iptables -t nat -L KUBE-SVC-V2OKYYMBY3REGZOG -v
Chain KUBE-SVC-V2OKYYMBY3REGZOG (2 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-J2DHXTF62PN2AN4F all -- any any anywhere anywhere /* default/nginx-service -> 10.244.1.5:80 */ statistic mode random probability 0.50000000000
0 0 KUBE-SEP-A4R5AW5RLMEQF7RP all -- any any anywhere anywhere /* default/nginx-service -> 10.244.2.4:80 */
進(jìn)一步可以找到兩條 KUBE-SVC-V2OKYYMBY3REGZOG 的子鏈 KUBE-SEP-J2DHXTF62PN2AN4F 和 KUBE-SEP-A4R5AW5RLMEQF7RP,這里對(duì)應(yīng)2個(gè) pods。以 KUBE-SEP-J2DHXTF62PN2AN4F 為例繼續(xù)跟:
sudo iptables -t nat -L KUBE-SEP-J2DHXTF62PN2AN4F -v
Chain KUBE-SEP-J2DHXTF62PN2AN4F (1 references)
pkts bytes target prot opt in out source destination
0 0 DNAT tcp -- any any anywhere anywhere /* default/nginx-service */ tcp to:10.244.1.5:80
到這里 target 不再是其他鏈,而是 DNAT,也就是請(qǐng)求 Service 的 NodePort 最終流量被 DNAT 到了 10.244.1.5:80 和 10.244.2.4:80 這兩個(gè) Endpoints,它們分別對(duì)應(yīng)2個(gè) pods。
3.3.3 從 PREROUTING 和 OUTPUT 鏈尋找 K8s 相關(guān)子鏈
先看 PREROUTING:
sudo iptables -t nat -L PREROUTING -v
Chain PREROUTING (policy ACCEPT 5 packets, 300 bytes)
pkts bytes target prot opt in out source destination
99 5965 KUBE-SERVICES all -- any any anywhere anywhere /* kubernetes service portals */
可以看到入向流量全部都會(huì)經(jīng)過(guò) KUBE-SERVICES 鏈處理。繼續(xù)看 OUTPUT:
sudo iptables -t nat -L OUTPUT -v
Chain OUTPUT (policy ACCEPT 3355 packets, 202K bytes)
pkts bytes target prot opt in out source destination
29961 1801K KUBE-SERVICES all -- any any anywhere anywhere /* kubernetes service portals */
同樣全部出向流量也被 KUBE-SERVICES 鏈處理。繼續(xù)看下 KUBE-SERVICES 鏈:
sudo iptables -t nat -L KUBE-SERVICES -v
Chain KUBE-SERVICES (2 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SVC-V2OKYYMBY3REGZOG tcp -- any any anywhere 10.107.33.105 /* default/nginx-service cluster IP */ tcp dpt:http
3391 203K KUBE-NODEPORTS all -- any any anywhere anywhere /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL
可以看到2條子鏈,一個(gè)是表示 Nginx Service 的 Cluster IP 的子鏈 KUBE-SVC-V2OKYYMBY3REGZOG,另外一個(gè)是表示集群 NodePort 的 KUBE-NODEPORTS 子鏈。KUBE-SVC-V2OKYYMBY3REGZOG 在前面已經(jīng)具體看過(guò)了,那么 KUBE-NODEPORTS 子鏈具體又包含啥信息呢:
sudo iptables -t nat -L KUBE-NODEPORTS -v
Chain KUBE-NODEPORTS (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-EXT-V2OKYYMBY3REGZOG tcp -- any any anywhere anywhere /* default/nginx-service */ tcp dpt:30007
可以看到當(dāng) TCP 流量的目的端口是 30007 的時(shí)候,就會(huì)匹配到 KUBE-EXT-V2OKYYMBY3REGZOG 子鏈,KUBE-EXT-V2OKYYMBY3REGZOG 子鏈的內(nèi)容前面已經(jīng)具體看過(guò)了。換言之,每多創(chuàng)建一個(gè) NodePort 類型的 Service,kube-proxy 就會(huì)在 KUBE-NODEPORTS 子鏈下新掛一條 KUBE-EXT-XXX 子鏈。
3.3.4 總結(jié)下
IP 包進(jìn)出主機(jī)都會(huì)經(jīng)過(guò) KUBE-SERVICES 鏈,進(jìn)而根據(jù) destination 地址匹配到不同的子鏈:
- 如果目的地址是某個(gè) Service 的 Cluster IP,那么就匹配到具體的 KUBE-SVC-XXX 處理;
- 否則,就匹配到 KUBE-NODEPORTS 處理;流量匹配到 KUBE-NODEPORTS 后,會(huì)進(jìn)一步根據(jù) tcp 目的端口 來(lái)匹配具體的子鏈 KUBE-EXT-XXX;
如果流量匹配到 KUBE-EXT-XXX 子鏈,端口命中,那么下一條依舊是表示 Cluster IP 的 KUBE-SVC-XXX,所以兩條子鏈在這里匯合。而 KUBE-SVC-XXX 鏈上的規(guī)則會(huì)進(jìn)一步將 IP 包匹配到 KUBE-SEP-XXX 子鏈上,這些子鏈表達(dá)的是“Service Endpoints”。默認(rèn)情況下 KUBE-SVC-XXX 會(huì)根據(jù) Pod 數(shù)量按照相等的概率將流量分流到多個(gè) KUBE-SEP-XXX 上進(jìn)一步匹配。而 KUBE-SEP-XXX 鏈會(huì)執(zhí)行類似“DNAT to:10.244.1.5:80”過(guò)程,最終將一開(kāi)始請(qǐng)求 Service 的流量就丟給了 Pod。
所以,當(dāng)你通過(guò) NodePort/ClusterIP 方式訪問(wèn) pods 的時(shí)候,以兩副本為例,整體流量匹配過(guò)程大致如下圖:
4. 總結(jié)
不總結(jié)。明天見(jiàn)。
總結(jié)
以上是生活随笔為你收集整理的深入 K8s 网络原理(二)- Service iptables 模式分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 苹果xr发烫正常吗
- 下一篇: 睡前100个小故事在线读