Kubernetes網(wǎng)絡(luò)模型分析

前一篇文章赖临,介紹了Docker容器的網(wǎng)絡(luò)模型惯豆。

容器是要被K8S編排卑硫、管理的踏施。而K8S又有自己的網(wǎng)絡(luò)模型幌羞。我們繼續(xù)學(xué)習(xí)斋陪、實驗瘤运,來理解K8S是怎么樣處理網(wǎng)絡(luò)流量的翰撑。

實驗之前罩旋,先分清楚K8S里面的三種IP地址啊央,和三種端口。

三種IP地址:

  1. Cluster IP:K8S在創(chuàng)建Service時涨醋,生成的虛擬IP地址瓜饥。需要與Service Port合到一起,成為一個有效的通信端口浴骂。該IP地址用于集群內(nèi)部的訪問乓土。

  2. Node IP:集群節(jié)點的IP地址。節(jié)點可能是物理機溯警,也可能是虛擬機趣苏。該地址真實存在于物理網(wǎng)絡(luò)。集群外部梯轻,可以通過該地址訪問到集群內(nèi)的節(jié)點食磕。

  3. Pod IP:K8S創(chuàng)建Pod時,為該Pod分配的IP地址喳挑。該地址在集群外不可見彬伦。具體的IP地址網(wǎng)段、以及Pod之間通信的方式蟀悦,取決于集群創(chuàng)建時選用的CNI模型媚朦。本文選用了Flannel做為CNI,但不涉及CNI的分析日戈。

三種端口:

  1. port:是集群Service偵聽的端口询张,與前面的Cluster IP合到一起,即Cluster IP:port浙炼,提供了集群內(nèi)部訪問Service的入口份氧。在K8S的yaml文件里面,port就是Service Port的縮寫弯屈。這是K8S創(chuàng)建Service時蜗帜,默認(rèn)的方式。

    個人感覺资厉,這個名字其實挺容易讓人混淆的厅缺,還不如直接用關(guān)鍵字ServicePort來的清楚。

  2. nodePort:是在節(jié)點上偵聽的端口宴偿。通過Node IP:nodePort的形式湘捎,提供了集群外部訪問集群中Service的入口。

  3. targetPort:是在Pod上偵聽的端口窄刘,比如運行Nginx的Pod窥妇,會在80端口上監(jiān)聽HTTP請求。所有對Service Port和Node Port的訪問娩践,最后都會被轉(zhuǎn)發(fā)到Target Port來處理活翩。

下面烹骨,開始我們的實驗。


一. 安裝K8S集群

如果還沒有集群的話材泄,可以參考我的另一篇文章沮焕,先去把環(huán)境搭建好:基于Ubuntu安裝Kubernetes集群指南

二. 創(chuàng)建Deployment

隨便找個目錄脸爱,執(zhí)行如下命令遇汞,創(chuàng)建一個yaml文件:

$ vi nginx_deployment.yaml

輸入這些內(nèi)容后,按:wq保存簿废、退出空入,得到nginx_deployment.yaml文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

這個Deployment將會生成2個副本的Pod,每個Pod里面都運行nginx族檬,Pod開放80端口歪赢。

然后用該yaml文件,去創(chuàng)建K8S資源:

$ kubectl apply -f nginx_deployment.yaml 
deployment.apps/nginx-deployment configured
$ kubectl get pods -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP           NODE                   NOMINATED NODE   READINESS GATES
nginx-deployment-55f598f8d-49l2v   1/1     Running   0          87m   10.244.0.2   ycwang-ubuntu          <none>           <none>
nginx-deployment-55f598f8d-pxp6x   1/1     Running   0          87m   10.244.1.4   ycwang-ubuntu-worker   <none>           <none>

可以看到单料,兩個Pod已經(jīng)在運行埋凯,并且它們有各自的IP。

此時扫尖,通過Pod IP即可訪問Nginx:

$ wget 10.244.0.2
Connecting to 10.244.0.2:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 615 [text/html]
Saving to: ‘index.html’

index.html                                              100%[===============================================================================================================================>]     615  --.-KB/s    in 0s      

 (62.7 MB/s) - ‘index.html’ saved [615/615]

$ wget 10.244.1.4
Connecting to 10.244.1.4:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 615 [text/html]
Saving to: ‘index.html.1’

index.html.1                                            100%[===============================================================================================================================>]     615  --.-KB/s    in 0s      

 (84.2 MB/s) - ‘index.html.1’ saved [615/615]

但從集群外白对,是無法訪問這兩個IP地址的。

三. 創(chuàng)建Service

生成一個新的yaml文件换怖,用來創(chuàng)建Service資源甩恼。

$ vi nginx_svc.yaml

輸入這些內(nèi)容后,按:wq保存沉颂、退出条摸。

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  labels:
    run: nginx-svc
spec:
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
  selector:
    app: nginx

這個Service使用app=nginx標(biāo)簽選擇器,來選擇對應(yīng)的Pod铸屉,做為Service的后端钉蒲。Service的類型是默認(rèn)的Service Port,所以不必寫出來彻坛。

Service監(jiān)聽在8080端口顷啼,集群內(nèi)部可以通過ClusterIP:8080進行訪問,并把流量轉(zhuǎn)發(fā)到Pod的80端口進行實際的業(yè)務(wù)處理昌屉。

執(zhí)行命令钙蒙,用該yaml文件去創(chuàng)建Service:

$ kubectl apply -f nginx_svc.yaml 
service/nginx-svc created
$ kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    145m
nginx-svc    ClusterIP   10.104.112.175   <none>        8080/TCP   3s

可以看到,該Service已經(jīng)創(chuàng)建成功怠益。并且出現(xiàn)了一個新的IP地址:10.104.112.175仪搔。這就是我們前面介紹的第一種IP地址:Cluster IP瘾婿。

通過該虛擬的IP地址蜻牢,加上指定的8080端口烤咧,即可實現(xiàn)集群內(nèi)部對Service的訪問:

$ wget 10.104.112.175:8080
Connecting to 10.104.112.175:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 615 [text/html]
Saving to: ‘index.html’

index.html                                              100%[===============================================================================================================================>]     615  --.-KB/s    in 0s      

 (60.4 MB/s) - ‘index.html’ saved [615/615]

那么,K8S是如何訪問這個不存在的虛擬IP地址的呢抢呆?

四. 分析Cluster IP訪問流程

先看一下這個Service的信息:

$ kubectl describe service nginx-svc 
Name:              nginx-svc
Namespace:         default
Labels:            run=nginx-svc
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.104.112.175
IPs:               10.104.112.175
Port:              <unset>  8080/TCP
TargetPort:        80/TCP
Endpoints:         10.244.0.2:80,10.244.1.4:80
Session Affinity:  None
Events:            <none>

這個Service對應(yīng)了后端的兩個Pod:10.244.0.2:80,10.244.1.4:80煮嫌。

就是說,對于10.104.112.175:8080的訪問抱虐,最后會被轉(zhuǎn)發(fā)到10.244.0.2:80或者10.244.1.4:80昌阿。

這要感謝iptables在后面默默的干活。

查看目前iptables的情況:

$ sudo iptables-save | grep 10.104.112.175
......
-A KUBE-SERVICES -d 10.104.112.175/32 -p tcp -m comment --comment "default/nginx-svc cluster IP" -m tcp --dport 8080 -j KUBE-SVC-HL5LMXD5JFHQZ6LN
......

對于10.104.112.175的訪問恳邀,會被跳轉(zhuǎn)到規(guī)則:KUBE-SVC-HL5LMXD5JFHQZ6LN懦冰。

繼續(xù)查看這條規(guī)則:

$ sudo iptables-save | grep KUBE-SVC-HL5LMXD5JFHQZ6LN
-A KUBE-SVC-HL5LMXD5JFHQZ6LN -m comment --comment "default/nginx-svc -> 10.244.0.2:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-T5AFCZ323NYPWW2A
-A KUBE-SVC-HL5LMXD5JFHQZ6LN -m comment --comment "default/nginx-svc -> 10.244.1.4:80" -j KUBE-SEP-RQ66ZV5Y2RYOH2X3

iptables把對10.104.112.175的訪問,采用輪詢的負(fù)載均衡策略谣沸,依次轉(zhuǎn)發(fā)給:10.244.0.2:80和10.244.1.4:80刷钢。

從而實現(xiàn)了在集群內(nèi)部對Cluster IP:port的訪問,并自帶了負(fù)載均衡功能乳附。

另外内地,這些iptables規(guī)則的增刪改都是由運行在每個節(jié)點的kube-proxy來實現(xiàn)的。

五. 創(chuàng)建NodePort類型的Service

現(xiàn)在赋除,我們把Service的類型改成NodePort阱缓。

$ vi nginx_svc.yaml

輸入如下內(nèi)容,并按:wq保存举农、退出:

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  labels:
    run: nginx-svc
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    nodePort: 30000
    protocol: TCP
  selector:
    app: nginx

在這個yaml文件荆针,把Service的類型指定為NodePort,并在每個Node上并蝗,偵聽30000端口祭犯。對30000端口的訪問,最后會被轉(zhuǎn)發(fā)到Pod的80端口滚停。

先把之前的Service和Deployment都刪掉沃粗,再用新的yaml文件重新創(chuàng)建:

$ kubectl delete -f nginx_svc.yaml 
service "nginx-svc" deleted
$ kubectl delete -f nginx_deployment.yaml 
deployment.apps "nginx-deployment" deleted
$ kubectl apply -f nginx_deployment.yaml 
deployment.apps/nginx-deployment created
$ kubectl apply -f nginx_svc.yaml 
service/nginx-svc created

查看Service和Pod的具體信息:

$ kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          3h41m
nginx-svc    NodePort    10.110.65.131   <none>        8080:30000/TCP   10s
$ kubectl get pods -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP           NODE                   NOMINATED NODE   READINESS GATES
nginx-deployment-55f598f8d-ls786   1/1     Running   0          11m   10.244.1.6   ycwang-ubuntu-worker   <none>           <none>
nginx-deployment-55f598f8d-pj2xk   1/1     Running   0          11m   10.244.0.3   ycwang-ubuntu          <none>           <none>

確認(rèn)都在正常運行了。

此時键畴,可以在集群內(nèi)最盅,通過Node IP:NodePort進行訪問,此節(jié)點的IP是192.168.111.128:

$ wget 192.168.111.128:30000
Connecting to 192.168.111.128:30000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 615 [text/html]
Saving to: ‘index.html’

index.html                                              100%[===============================================================================================================================>]     615  --.-KB/s    in 0s      

 (87.4 MB/s) - ‘index.html’ saved [615/615]

也可以在集群外的Windows機器起惕,通過Node IP:NodePort進行訪問:

$ curl 192.168.111.128:30000
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   615  100   615    0     0   207k      0 --:--:-- --:--:-- --:--:--  300k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a >nginx.org</a>.<br/>
Commercial support is available at
<a >nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

六. 分析Node IP:NodePort訪問流程

我們繼續(xù)探究涡贱,訪問Node IP:NodePort是怎么被轉(zhuǎn)到Pod上面去的?

答案依然是iptables:

$ sudo iptables-save | grep 30000
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx-svc" -m tcp --dport 30000 -j KUBE-EXT-HL5LMXD5JFHQZ6LN

對30000端口的訪問惹想,會被跳轉(zhuǎn)到規(guī)則:KUBE-EXT-HL5LMXD5JFHQZ6LN问词。

而KUBE-EXT-HL5LMXD5JFHQZ6LN,又被跳轉(zhuǎn)到:KUBE-SVC-HL5LMXD5JFHQZ6LN

$ sudo iptables-save | grep KUBE-EXT-HL5LMXD5JFHQZ6LN
-A KUBE-EXT-HL5LMXD5JFHQZ6LN -j KUBE-SVC-HL5LMXD5JFHQZ6LN

KUBE-SVC-HL5LMXD5JFHQZ6LN這條規(guī)則的具體內(nèi)容:

$ sudo iptables-save | grep KUBE-SVC-HL5LMXD5JFHQZ6LN
-A KUBE-SERVICES -d 10.110.65.131/32 -p tcp -m comment --comment "default/nginx-svc cluster IP" -m tcp --dport 8080 -j KUBE-SVC-HL5LMXD5JFHQZ6LN
-A KUBE-SVC-HL5LMXD5JFHQZ6LN -m comment --comment "default/nginx-svc -> 10.244.0.3:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-PU7AOSZG6OVFMASF
-A KUBE-SVC-HL5LMXD5JFHQZ6LN -m comment --comment "default/nginx-svc -> 10.244.1.6:80" -j KUBE-SEP-OZ4KTOWKCOJKYUPL

跟Cluster IP的做法一樣嘀粱,iptables把對Node IP:NodePort的訪問激挪,采用輪詢的負(fù)載均衡策略辰狡,依次轉(zhuǎn)發(fā)給:10.244.0.3:80和10.244.1.6:80這兩個Endpoints。

K8S里面的網(wǎng)絡(luò)訪問流程差不多就這樣了垄分。它采用了一個很巧妙的設(shè)計宛篇,去中心化、讓每個節(jié)點都承擔(dān)了負(fù)載均衡的功能薄湿。


補充點題外話叫倍,在Node IP:NodePort這種模式下,直接訪問節(jié)點還是會有點問題的豺瘤。

因為客戶需要指定某個Node進行訪問吆倦。這樣會帶來單點問題;而且坐求,客戶按理不應(yīng)該知道逼庞、也不需要知道具體的Node和它的IP。

所以瞻赶,在實際應(yīng)用中赛糟,可以在K8S集群外部,搭建一個負(fù)載均衡器砸逊¤的希客戶訪問此負(fù)載均衡器,再由該負(fù)載均衡器把流量分發(fā)到各個Node上师逸。很多云廠商也已經(jīng)帶了這樣的功能司倚。

但是,既然外部有了支持各種負(fù)載均衡算法的職業(yè)選手篓像,把流量分發(fā)到各個Node上动知。如果Node收到后,再次用iptables進行負(fù)載均衡员辩,就沒有什么意義了盒粮。不清楚Google為什么要這么設(shè)計?

是不是可以考慮在K8S里面內(nèi)置一個負(fù)載均衡的模塊奠滑,專門運行在某個Node上丹皱。在NodePort模式下,可以選擇啟用該模塊宋税,由它來專門提供客戶訪問的入口并做負(fù)載均衡摊崭,然后此刻各個Node上的iptables負(fù)載均衡可以禁用了?期待各路高人高見……

BTW一下杰赛,既然都說到了負(fù)載均衡呢簸,捆綁推銷一下我的另一篇文章吧:負(fù)載均衡算法的實現(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市根时,隨后出現(xiàn)的幾起案子嘿架,更是在濱河造成了極大的恐慌,老刑警劉巖啸箫,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伞芹,居然都是意外死亡忘苛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門唱较,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扎唾,“玉大人,你說我怎么就攤上這事南缓⌒赜觯” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵汉形,是天一觀的道長纸镊。 經(jīng)常有香客問我,道長概疆,這世上最難降的妖魔是什么逗威? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮岔冀,結(jié)果婚禮上凯旭,老公的妹妹穿的比我還像新娘。我一直安慰自己使套,他們只是感情好罐呼,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著侦高,像睡著了一般嫉柴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奉呛,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天差凹,我揣著相機與錄音,去河邊找鬼侧馅。 笑死危尿,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的馁痴。 我是一名探鬼主播谊娇,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了济欢?” 一聲冷哼從身側(cè)響起赠堵,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎法褥,沒想到半個月后茫叭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡半等,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年揍愁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杀饵。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡莽囤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出切距,到底是詐尸還是另有隱情朽缎,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布谜悟,位于F島的核電站话肖,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏葡幸。R本人自食惡果不足惜狼牺,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望礼患。 院中可真熱鬧是钥,春花似錦、人聲如沸缅叠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肤粱。三九已至弹囚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間领曼,已是汗流浹背鸥鹉。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留庶骄,地道東北人毁渗。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像单刁,于是被迫代替她去往敵國和親灸异。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容