K8s中Pod的服務(wù)發(fā)現(xiàn)
Pod是怎么找到請求的Pod的,pod之間又是怎么負載均衡的(iptables模式下)
01
iptables知識
想知道這個問題,首先需要了解一些iptables知識。
五條鏈
Iptables是linux內(nèi)核集成的IP信息過濾規(guī)則,負責(zé)將發(fā)往主機的網(wǎng)絡(luò)包進行分發(fā),轉(zhuǎn)換等。當客戶端請求服務(wù)器的某個服務(wù)時,請求信息會先通過網(wǎng)卡進入服務(wù)器內(nèi)核,這時iptables會對包進行過濾,決定這些包是發(fā)往用戶態(tài)的服務(wù)進程或是轉(zhuǎn)發(fā)出去到別的主機。而決定這些路徑的方式在iptables中稱為鏈,剛進入內(nèi)核的請求流會經(jīng)過PREROUTING鏈,根據(jù)路由規(guī)則判斷是是不是發(fā)往本機請求,是則走INPUT鏈進入本機用戶態(tài)進程,否則會走FORWARD鏈并匹配對應(yīng)的規(guī)則最后流出本機;如果是本機發(fā)出的請求會走OUTPUT鏈并進一步到POSTROUTINE鏈流出本機,或轉(zhuǎn)發(fā)到其他機器或回復(fù)信息給客戶端。

總結(jié)上述幾條鏈:
PREROUTINE:流入本機路由前
POSTROUTINE:流出本機路由前
FORWARD:轉(zhuǎn)發(fā)路徑
OUTPUT:由本機用戶程序發(fā)出的
INPUT:發(fā)送至本機用戶程序的
兩個動作
SNAT
源地址轉(zhuǎn)換,是指將報文發(fā)送方的ip地址轉(zhuǎn)換,這樣當相應(yīng)方回復(fù)請求時,回復(fù)的是發(fā)送方的地址。
示例

當client發(fā)送請求給server時,需要經(jīng)過gateway,如果gateway不對包進行源地址轉(zhuǎn)換(SNAT),發(fā)往server的網(wǎng)絡(luò)包攜帶的源地址依然是client,server會對該源地址響應(yīng),但client并不識別server的地址,會導(dǎo)致該條請求出現(xiàn)錯誤。
DNAT
目標地址轉(zhuǎn)換,是將報文的目標地址轉(zhuǎn)換,起到請求轉(zhuǎn)發(fā)到別的目的地的作用。
02
k8s基礎(chǔ)知識? ??
需要了解k8s中的幾種IP類型。
虛擬IP
虛IP(下文稱VIP)有ClusterIP(即serviceIP),是集群自己生成的,ping不通,并和PodIP不處于同一網(wǎng)段,避免請求發(fā)生混亂。當創(chuàng)建一個service時,k8s會為該service指派一個IP地址,并會被集群中的所有kube-proxy觀察到,kube-proxy從而會安裝一系列的iptables規(guī)則到宿主機,kube-dns也會相應(yīng)的插入一條域名解析IP的規(guī)則。請求到來的時候,如果符合規(guī)則,iptables會將VIP轉(zhuǎn)化為實際的IP并使用。
實際IP
實IP分別有PodIP等,該IP是由CNI插件分配的,在k8s集群啟動時候,需要安裝CNI插件,通常是一個DaemonSet控制器控制,保證每臺節(jié)點都有該進程。他的作用是在集群內(nèi)部產(chǎn)生一套網(wǎng)絡(luò),并給每個pod插上”網(wǎng)線”,保證pod與節(jié)點,pod與pod是互通的。
Pod之間通信的方式可以通過實際的PodIP,但是該IP會隨著pod的變化而變化,不適合用該方式,也可以通過ClusterIP的方式通信,比較穩(wěn)定,但是不容易被記住,還可以通過svc.ns這種域名的格式,該方法請求kube-dns域名解析得到域名對應(yīng)的IP。
03
案例學(xué)習(xí)? ??
接下來根據(jù)一個案例探討一下。
案例介紹
集群中有兩個gateway-pod,service類型為NodePort,暴露端口給集群外部,接收外界請求并負載均衡,并將請求轉(zhuǎn)發(fā)到下游pod。
有一個basedao pod,負責(zé)接收gateway pod發(fā)來的請求并響應(yīng),對應(yīng)的service名稱是sts-basedao,命名空間名稱是basedao。
Kube-dns pod將域名解析成IP地址,并返回給發(fā)送方。

查看一下各個pod的IP,該IP是實際的IP。
[centos@guozhao-50?~]$?kubectl?get?pod?--all-namespaces?-owideNAMESPACE?????NAME????????????????????????????????IP????????????????????basedao???????sts-basedao-0??????????????????????10.34.0.2gateway???????sts-gateway-59d5fdbc54-4d6kv? ?????10.40.0.0gateway???????sts-gateway-59d5fdbc54-dmncq???????10.34.0.1?kube-system???coredns-6c76c8bb89-kztxk???????????10.32.0.4
查看一下三種pod對應(yīng)service的IP,可以看到gateway service代理的30001端口映射到了外部的31001端口。
[centos@guozhao-50?~]$ kubectl?get?svc?--all-namespacesNAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEbasedao svc-basedao ClusterIP 10.111.143.22330003/TCP 70m gateway svc-gateway NodePort 10.102.103.130001:31001/TCP 70m kube-system???kube-dns???????????????ClusterIP???10.96.0.10???????????????53/UDP,53/TCP,9153/TCP???14d
client發(fā)起請求
通過iptables-save命令可以查看到所有的iptables規(guī)則。
當client發(fā)起請求時,會請求服務(wù)器對應(yīng)的端口,對應(yīng)NodePort端口,我們來查看對應(yīng)的iptables規(guī)則,會經(jīng)過PREROUTING,跳轉(zhuǎn)到KUBE-SERVICES規(guī)則。
-A?PREROUTING?-m?comment?--comment?"kubernetes?service?portals"?-j KUBE-SERVICES在KUBE-SERVICE中找到符合的規(guī)則,--dst-type LOCAL 代表本地,會繼續(xù)跳轉(zhuǎn)到KUBE-NODEPORTS
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS該請求會跳轉(zhuǎn)到KUBE-MARK-MASQ給請求打一個標簽,并跳轉(zhuǎn)到下一條規(guī)則KUBE-SVC-4QJQIYWH2AWK2TSA。
-A?KUBE-NODEPORTS?-p?tcp?-m?comment?--comment?"gateway/svc-gateway:gateway-port"?-m?tcp?--dport?31001?-j?KUBE-MARK-MASQ-A KUBE-NODEPORTS -p tcp -m comment --comment "gateway/svc-gateway:gateway-port" -m tcp --dport 31001 -j KUBE-SVC-4QJQIYWH2AWK2TSA
跟隨上條規(guī)則有兩條規(guī)則與其對應(yīng),--probability 0.50000000000代表有0.5的概率進入上面的規(guī)則,如果沒有進入上面規(guī)則,就會進入下面的規(guī)則,負載均衡也就是在iptables層面實現(xiàn)的。
-A KUBE-SVC-4QJQIYWH2AWK2TSA -m comment --comment "gateway/svc-gateway:gateway-port" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-XEQTQPKSTZECBET2-A KUBE-SVC-4QJQIYWH2AWK2TSA -m comment --comment "gateway/svc-gateway:gateway-port" -j KUBE-SEP-OCFEUGRRJNZZEOHZ
分別查看兩個規(guī)則對應(yīng)的下一條規(guī)則,該規(guī)則指定了目標地址,執(zhí)行了DNAT操作進行目標地址轉(zhuǎn)發(fā),分別對應(yīng)了兩個pod實例的實際IP地址,請求會跟隨這條規(guī)則轉(zhuǎn)發(fā)到實際的gateway。
-A?KUBE-SEP-XEQTQPKSTZECBET2?-p?tcp?-m?comment?--comment?"gateway/svc-gateway:gateway-port"?-m?tcp?-j?DNAT?--to-destination?10.34.0.1:30001-A KUBE-SEP-OCFEUGRRJNZZEOHZ -p tcp -m comment --comment "gateway/svc-gateway:gateway-port" -m tcp -j DNAT --to-destination 10.40.0.0:30001
在最終發(fā)出請求之前會走POSTROUTING鏈,會對該請求做一個SNAT操作,MASQUERADE代表執(zhí)行了SNAT操作修改了請求源地址。
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE
gateway發(fā)起請求
此時gateway收到了來自client的請求,他會向basedao發(fā)起請求,請求方式是通過域名即sts-basedao.basedao:30002格式。該請求會發(fā)送給dns服務(wù)器進行解析返回一個實際IP地址,當然,該地址也是一個VIP。
在pod被創(chuàng)建時候,就會在pod中創(chuàng)建dns服務(wù)配置文件,nameserver代表dns服務(wù)器的IP地址,默認是集群中的kube-dns地址,search代表域名拼接規(guī)則。可以看出,該地址和kube-dns的VIP是相同的。

接下來該pod會發(fā)出請求到kube-dns的VIP
由于是在主機上發(fā)出,會走OUTPUT鏈,進而進入到KUBE-SERVICES
-A?OUTPUT?-m?comment?--comment?"kubernetes?service?portals"?-j?KUBE-SERVICES滿足KUBE-SERVICES的該條規(guī)則,繼續(xù)跳轉(zhuǎn)到KUBE-SVC-ERIFXISQEP7F7OF4,再次跳轉(zhuǎn)到KUBE-SEP-ZT5TVM6PMFDFQAMO。
-A KUBE-SERVICES -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp cluster IP" -m tcp --dport 53 -j KUBE-SVC-ERIFXISQEP7F7OF4-A?KUBE-SVC-ERIFXISQEP7F7OF4?-m?comment?--comment?"kube-system/kube-dns:dns-tcp"?-j?KUBE-SEP-ZT5TVM6PMFDFQAMO
最終進行DNAT目標地址轉(zhuǎn)發(fā)到dns實際的pod,最終dns返回給gateway由域名解析到的ip。
-A KUBE-SEP-ZT5TVM6PMFDFQAMO -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp" -m tcp -j DNAT --to-destination 10.32.0.4:53當gateway得到真實的IP,該IP就是basedao的VIP,gateway會使用該VIP發(fā)起請求,依然會對應(yīng)到相應(yīng)的iptables規(guī)則,完成VIP到IP的映射得到basedao pod的實際地址,并向?qū)嶋H地址發(fā)送數(shù)據(jù)包,這里便不再贅述。
04
總結(jié)? ??
由于Pod的IP地址不是持久的,所以盡量建議采用ClusterIP或者域名的方式請求集群中的其他pod,而這兩種方式是通過Linux內(nèi)核的iptables規(guī)則實現(xiàn)的。使用iptables規(guī)則也有缺點,當集群中有過多的服務(wù)Pod,相應(yīng)的各臺宿主機iptables規(guī)則就會增加,這增加了網(wǎng)絡(luò)的復(fù)雜度與跟蹤難度,會給后期運維帶來一定的困難。
05
參考文章? ??
《iptables詳解》http://www.zsythink.net/archives/1199
《k8s中文文檔》https://v1-16.docs.kubernetes.io/zh/
《深入剖析Kubernetes》極客時間
推薦閱讀
