測試技能提升篇—k8s的網(wǎng)絡(luò)核心概念
絕大多數(shù)剛剛接觸k8s的同學(xué)都會被其中的網(wǎng)絡(luò)相關(guān)知識點搞得暈頭轉(zhuǎn)向!各種IP,包括:Node IP,ClusterIP,Node IP糾結(jié)是啥東東?internet是怎樣訪問k8s的?k8s內(nèi)部各個pod之間又是如何通信的?本文就為大家來解決上述問題。
K8s中網(wǎng)絡(luò)核心概念介紹
Node IP
Node節(jié)點的IP地址,即物理網(wǎng)卡的IP地址。
NodePort可以是物理機的IP(也可能是虛擬機IP)。每個Service都會在Node節(jié)點上開通一個端口,外部可以通過NodeIP:NodePort即可訪問Service里的Pod,和我們訪問服務(wù)器部署的項目一樣,IP:端口/項目名。
Cluster IP
Service的IP地址,此為虛擬IP地址。外部網(wǎng)絡(luò)無法ping通,只有k8s集群內(nèi)部訪問使用。Cluster IP是一個虛擬的IP,但更像是一個偽造的IP網(wǎng)絡(luò),原因有以下幾點:
1.Cluster IP僅僅作用于k8s Service這個對象,并由k8s管理和分配P地址。
2.Cluster IP無法被ping,他沒有一個“實體網(wǎng)絡(luò)對象”來響應(yīng)。
3.Cluster IP只能結(jié)合Service Port組成一個具體的通信端口,單獨的Cluster IP不具備通信的基礎(chǔ),并且他們屬于k8s集群這樣一個封閉的空間。
4.在不同Service下的pod節(jié)點在集群間相互訪問可以通過Cluster IP。
Pod IP
Pod IP是每個Pod的IP地址,他是Docker Engine根據(jù)docker網(wǎng)橋的IP地址段進行分配的,通常是一個虛擬的二層網(wǎng)絡(luò)
- 同Service下的pod可以直接根據(jù)Pod IP相互通信。
- 不同Service下的pod在集群間pod通信要借助于 cluster IP。
- pod和集群外通信,要借助于node IP。
簡單地總結(jié):外部訪問時,先到Node節(jié)點網(wǎng)絡(luò),再轉(zhuǎn)到service網(wǎng)絡(luò),最后代理給pod網(wǎng)絡(luò)。
K8s如何實現(xiàn)網(wǎng)絡(luò)通信
三條核心原則
- 默認情況下,Linux 將所有的進程都分配到 root network namespace,以使得進程可以訪問外部網(wǎng)絡(luò)。
- K8s為每一個 Pod 都創(chuàng)建了一個 network namespace。
- 在 K8s中,Pod 是一組 docker 容器的集合,這一組 docker 容器將共享一個 network namespace。Pod 中所有的容器都使用該 network namespace 提供的同一個 IP 地址以及同一個端口空間。所有的容器都可以通過 localhost 直接與同一個 Pod 中的另一個容器通信。
容器與容器之間網(wǎng)絡(luò)通信
pod中每個docker容器和pod在一個網(wǎng)絡(luò)命名空間內(nèi),所以ip和端口等等網(wǎng)絡(luò)配置,都和pod一樣,主要通過一種機制就是,docker的一種網(wǎng)絡(luò)模式,container,新創(chuàng)建的Docker容器不會創(chuàng)建自己的網(wǎng)卡,配置自己的 IP,而是和一個指定的容器共享 IP、端口范圍等
pod與pod之間網(wǎng)絡(luò)通信
從 Pod 的視角來看,Pod 是在其自身所在的 network namespace 與同節(jié)點上另外一個 network namespace 進程通信。在Linux上,不同的 network namespace 可以通過 Virtual Ethernet Device (opens new window) 或 veth pair (兩塊跨多個名稱空間的虛擬網(wǎng)卡)進行通信。為連接 pod 的 network namespace,可以將 veth pair 的一段指定到 root network namespace,另一端指定到 Pod 的 network namespace。每一組 veth pair 類似于一條網(wǎng)線,連接兩端,并可以使流量通過。節(jié)點上有多少個 Pod,就會設(shè)置多少組 veth pair。下圖展示了 veth pair 連接 Pod 到 root namespace 的情況:
為了讓 Pod 可以互相通過 root network namespace 通信,我們將使用 network bridge(網(wǎng)橋)。Linux Ethernet bridge 是一個虛擬的 Layer 2 網(wǎng)絡(luò)設(shè)備,可用來連接兩個或多個網(wǎng)段。網(wǎng)橋的工作原理是,在源于目標之間維護一個轉(zhuǎn)發(fā)表,通過檢查通過網(wǎng)橋的數(shù)據(jù)包的目標地址和該轉(zhuǎn)發(fā)表來決定是否將數(shù)據(jù)包轉(zhuǎn)發(fā)到與網(wǎng)橋相連的另一個網(wǎng)段。橋接代碼通過網(wǎng)絡(luò)中具備唯一性的網(wǎng)卡MAC地址來判斷是否橋接或丟棄數(shù)據(jù)。網(wǎng)橋?qū)崿F(xiàn)了ARP協(xié)議來發(fā)現(xiàn)鏈路層與 IP 地址綁定的 MAC 地址。當網(wǎng)橋收到數(shù)據(jù)幀時,網(wǎng)橋?qū)⒃摂?shù)據(jù)幀廣播到所有連接的設(shè)備上(除了發(fā)送者以外),對該數(shù)據(jù)幀做出相應(yīng)的設(shè)備被記錄到一個查找表中。后續(xù)網(wǎng)橋再收到發(fā)向同一個 IP 地址的流量時,將使用查找表來找到對應(yīng)的 MAC 地址,并轉(zhuǎn)發(fā)數(shù)據(jù)包。下圖中cbr0就是網(wǎng)橋。
不同Node間通信原理
通常,集群中每個節(jié)點都被分配了一個 CIDR 網(wǎng)段(簡單的理解CIDR可以把幾個標準網(wǎng)絡(luò)合成一個大的網(wǎng)絡(luò)),指定了該節(jié)點上的 Pod 可用的 IP 地址段。一旦發(fā)送到該 CIDR 網(wǎng)段的流量到達節(jié)點,就由節(jié)點負責將流量繼續(xù)轉(zhuǎn)發(fā)給對應(yīng)的 Pod。下圖展示了兩個節(jié)點之間的數(shù)據(jù)報文傳遞過程。
pod與service之間網(wǎng)絡(luò)通信
Pod 的 IP 地址并非是固定不變的,隨著 Pod 的重新調(diào)度(例如水平伸縮、應(yīng)用程序崩潰、節(jié)點重啟等),Pod 的 IP 地址將會出現(xiàn)又消失。此時,Pod 的客戶端無法得知該訪問哪個 IP 地址。k8s中,Service 的概念用于解決此問題。Service管理了多個Pods,每個Service有一個虛擬的ip,要訪問service管理的Pod上的服務(wù)只需要訪問你這個虛擬ip就可以了,這個虛擬ip是固定的,當service下的pod規(guī)模改變、故障重啟、node重啟時候,對使用service的用戶來說是無感知的,因為他們使用的service的ip沒有變。當數(shù)據(jù)包到達Service虛擬ip后,數(shù)據(jù)包會被通過k8s給該servcie自動創(chuàng)建的負載均衡器路由到背后的pod容器。
我們知道Service 是 k8s中的一種服務(wù)發(fā)現(xiàn)機制,總結(jié)核心功能如下:
- 通常通過service來關(guān)聯(lián)pod并提供對外訪問接口。
- Service 實現(xiàn)負載均衡,可將請求均衡分發(fā)到選定這一組 Pod 中。
- Service 通過 label selector 選定一組 Pod。
Service的ip分配策略
k8s的一個設(shè)計哲學(xué)是:盡量避免非人為錯誤產(chǎn)生的可能性。就設(shè)計 Service 而言,k8s應(yīng)該將您選擇的端口號與其他人選擇的端口號隔離開。為此,k8s為每一個 Service 分配一個該 Service 專屬的 IP 地址。為了確保每個 Service 都有一個唯一的 IP 地址,k8s在創(chuàng)建 Service 之前,先更新 etcd 中的一個全局分配表,如果更新失?。ɡ?IP 地址已被其他 Service 占用),則 Service 不能成功創(chuàng)建。k8s使用一個后臺控制器檢查該全局分配表中的 IP 地址的分配是否仍然有效,并且自動清理不再被 Service 使用的 IP 地址。
Service的dns解析
k8s集群中運行了一組 DNS Pod,配置了對應(yīng)的 Service,并由 k8s將 DNS Service 的 IP 地址配置到節(jié)點上的容器中以便解析 DNS names。集群中的每一個 Service(包括 DNS 服務(wù)本身)都將被分配一個 DNS name。默認情況下,客戶端 Pod 的 DNS 搜索列表包括 Pod 所在的名稱空間以及集群的默認域。例如:
假設(shè)名稱空間 A中有一個 Service 名為 foo:
- 名稱空間 A中的 Pod 可以通過 nslookup foo 查找到該 Service。
- 名稱空間 B中的 Pod 可以通過 nslookup foo.A 查找到該 Service。
Internet與k8s的網(wǎng)絡(luò)通信
讓Internet流量進入k8s集群,這特定于配置的網(wǎng)絡(luò),可以在網(wǎng)絡(luò)堆棧的不同層來實現(xiàn):
- NodePort
NodePort 服務(wù)是引導(dǎo)外部流量到你的服務(wù)的最原始方式。NodePort,正如這個名字所示,在所有節(jié)點(虛擬機)上開放一個特定端口,任何發(fā)送到該端口的流量都被轉(zhuǎn)發(fā)到對應(yīng)服務(wù)。
- Service LoadBalancer
如果你想要直接暴露服務(wù),這就是默認方式。所有通往你指定的端口的流量都會被轉(zhuǎn)發(fā)到對應(yīng)的服務(wù)。它設(shè)有過濾條件,路由等功能。值得一提的是,如果是在本地開發(fā)測試環(huán)境里頭搭建的K8s,一般不支持Load Balancer也沒必要,因為通過NodePort做測試訪問就夠了。但是在生產(chǎn)環(huán)境或者公有云上的K8s,基本都支持自動創(chuàng)建Load Balancer。
- Ingress控制器
它處于多個服務(wù)的前端,扮演著“智能路由”或者集群入口的角色。它的本質(zhì)上就是K8s集群中的一個比較特殊的Service(發(fā)布Kind: Ingress)。這個Service提供的功能主要就是7層反向代理(也可以提供安全認證,監(jiān)控,限流和SSL證書等高級功能),功能類似Nginx。Ingress對外暴露出去是通過HostPort(80/443),可以和上面LoadBalancer對接起來。有了這個Ingress Service,我們可以做到只需購買一個LB+IP,就可以通過Ingress將內(nèi)部多個(甚至全部)服務(wù)暴露出去,Ingress會幫忙做代理轉(zhuǎn)發(fā)。