這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)如何理解Kubernets網(wǎng)絡(luò),文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
成都創(chuàng)新互聯(lián)主要從事成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)神池,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):13518219792
不同宿主機(jī)上運(yùn)行的容器并不能通過 IP 相互訪問,那么 Kubernetes 是如何實(shí)現(xiàn)不同節(jié)點(diǎn)上 Pod 的互通?Pod 有生命周期,它的 IP 會隨著動態(tài)的創(chuàng)建和銷毀而動態(tài)變化,Kubernetes 又是怎樣對外提供穩(wěn)定的服務(wù)?今天就為大家一一解答這些疑問。
先來看一下 Docker 中的網(wǎng)絡(luò)。在啟動 Docker 服務(wù)后,默認(rèn)會創(chuàng)建一個 docker0
網(wǎng)橋(其上有一個 docker0
內(nèi)部接口),它在內(nèi)核層連通了其他的物理或虛擬網(wǎng)卡,這就將所有容器和本地主機(jī)都放到同一個物理網(wǎng)絡(luò)。
Docker 默認(rèn)指定了 docker0
接口 的 IP 地址和子網(wǎng)掩碼,讓主機(jī)和容器之間可以通過網(wǎng)橋相互通信,它還給出了 MTU(接口允許接收的最大傳輸單元),通常是 1500 Bytes,或宿主主機(jī)網(wǎng)絡(luò)路由上支持的默認(rèn)值,這些值都可以在服務(wù)啟動的時候進(jìn)行配置。
root@ubuntu:/root# ifconfig ... docker0: flags=4099mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0 ether 02:42:d2:00:10:6c txqueuelen 0 (Ethernet) ... root@ubuntu:/root# docker inspect busybox ··· "IPAddress": "172.17.0.2", ···
為了實(shí)現(xiàn)上述功能,Docker 主要用到了 linux 的 Bridge
、Network Namespace
、VETH
。
Bridge相當(dāng)于是一個虛擬網(wǎng)橋,工作在第二層網(wǎng)絡(luò)。也可以為它配置IP,工作在三層網(wǎng)絡(luò)。docker0網(wǎng)關(guān)就是通過Bridge實(shí)現(xiàn)的。
Network Namespace是網(wǎng)絡(luò)命名空間,通過Network Namespace可以建立一些完全隔離的網(wǎng)絡(luò)棧。比如通過docker network create xxx就是在建立一個Network Namespace
VETH是虛擬網(wǎng)卡的接口對,可以把兩端分別接在兩個不同的Network Namespace中,實(shí)現(xiàn)兩個原本隔離的Network Namespace的通信。
所以總結(jié)起來就是:Network Namespace做了容器和宿主機(jī)的網(wǎng)絡(luò)隔離,Bridge分別在容器和宿主機(jī)建立一個網(wǎng)關(guān),然后再用VETH將容器和宿主機(jī)兩個網(wǎng)絡(luò)空間連接起來。但這都是在同一個主機(jī)上的網(wǎng)絡(luò)實(shí)現(xiàn),如果想要在多臺主機(jī)上進(jìn)行網(wǎng)絡(luò)就得看看下面介紹的 Kubernetes 網(wǎng)絡(luò)。
Kubernetes 為了解決容器的“跨主通信”問題,提出了很多解決方案。常見思路有兩種:
直接在宿主機(jī)上建立不同宿主機(jī)上子網(wǎng)的路由規(guī)則;
通過特殊的網(wǎng)絡(luò)設(shè)備封裝二層數(shù)據(jù)幀,根據(jù)目標(biāo) IP 地址匹配到對應(yīng)的子網(wǎng)找到對應(yīng)的宿主機(jī) IP 地址,最后將轉(zhuǎn)發(fā) IP 包,目的宿主機(jī)上同樣的特殊網(wǎng)絡(luò)設(shè)備完成解封并根據(jù)本機(jī)路由表轉(zhuǎn)發(fā)。
大家所熟知的 Flannel 項(xiàng)目是 CoreOS 公司推出的容器網(wǎng)絡(luò)解決方案。它本身只是一個框架,為開發(fā)者提供容器網(wǎng)絡(luò)功能的是 Flannel 的后端實(shí)現(xiàn)。目前有如下三種具體實(shí)現(xiàn):
UDP
VXLAN
host-gw
下面的三層網(wǎng)絡(luò)指的是七層網(wǎng)絡(luò)模型中的底部的三層:網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層和物理層。
UDP 模式是最早支持,性能最差,但最容易理解和實(shí)現(xiàn)的容器跨主網(wǎng)絡(luò)方案。Flannel UDP 模式提供的是一個三層的覆蓋網(wǎng)絡(luò):首先對發(fā)出端的IP包進(jìn)行 UDP 封裝,然后在接受端進(jìn)行解封拿到原始的IP包,進(jìn)而把這個包轉(zhuǎn)發(fā)給目標(biāo)容器。它相當(dāng)于在兩個容器之間打通一條“隧道”,使得兩個容器可以直接使用 IP 通信,而不關(guān)心容器和宿主機(jī)的分布情況。
因?yàn)?Flannel 進(jìn)行 UDP 封裝和解封都是在用戶態(tài)完成,而在 Linux 系統(tǒng)中上下文切換和用戶態(tài)操作的代價非常大,這就是它性能不好的主要原因。
VXLAN 即 Virtual Extensible LAN(虛擬可擴(kuò)展局域網(wǎng)),是 Linux 內(nèi)核本身就支持的一種網(wǎng)絡(luò)虛擬化技術(shù)。VXLAN 在內(nèi)核態(tài)就完成了上面的封裝和解封工作,通過與 UDP 模式類似的“隧道”機(jī)制,構(gòu)建出覆蓋網(wǎng)絡(luò)(Overlay Network),使得連接在這個 VXLAN 二層網(wǎng)絡(luò)的“主機(jī)”可以像在局域網(wǎng)自由通信。
host-gw 模式的工作原理是將每一個 Flannel 子網(wǎng)的下一跳設(shè)置為該子網(wǎng)對應(yīng)的宿主機(jī) IP 地址。
也就是說,這臺“主機(jī)”(host)會充當(dāng)這條容器通信路徑里的“網(wǎng)關(guān)”(Getway)。Flannel host-gw 模式必須要求集群宿主機(jī)之間是二層連通的。
Calico 項(xiàng)目提供的網(wǎng)絡(luò)解決方案與 Flannel Host-gw 模式同理。但是不同于 Flannel 通過 Etcd 和宿主機(jī)的 flanneld 來維護(hù)路由信息得做法,Calio 項(xiàng)目使用BGP(邊界網(wǎng)關(guān)協(xié)議) 來自動的在整個集群中分發(fā)路由消息。它由三部分組成:
Calico 的 CNI 插件:這是 Calico 與 Kubernetes 對接的部分。 Felix:它是一個 DaemonSet,負(fù)責(zé)在宿主機(jī)插入路由規(guī)則,以及維護(hù)Calico所需的網(wǎng)絡(luò)設(shè)備等。 BIRD:它是 BGP 的客戶端,負(fù)責(zé)在集群里分發(fā)路由規(guī)則信息。
除了對路由信息的維護(hù)方式之外,Calico 項(xiàng)目和 Flannel 的 host-gw 另一個不同是它不會在宿主機(jī)上創(chuàng)建任何網(wǎng)橋設(shè)備。
CNI)是CNCF旗下的一個項(xiàng)目,由一組用于配置Linux容器的網(wǎng)絡(luò)接口的規(guī)范和庫組成,同時還包含了一些插件。CNI僅關(guān)心容器創(chuàng)建時的網(wǎng)絡(luò)分配,和當(dāng)容器被刪除時釋放網(wǎng)絡(luò)資源。其基本思想為: Kubernetes 在啟動 Infra 容器之后,就可以直接調(diào)用 CNI 網(wǎng)絡(luò)插件,為這個 Infra 容器的 Network Namespace 配置符合預(yù)期的網(wǎng)絡(luò)棧。
Kubernetes 使用 CNI 接口,維護(hù)一個單獨(dú)的網(wǎng)橋來代替 docker0。這個網(wǎng)橋就叫做 CNI 網(wǎng)橋,它在宿主機(jī)上的默認(rèn)名稱是:cni0。以 Flannel 的 VXLAN 模式為例,在 Kubernetes 環(huán)境里,它的工作方式?jīng)]有變化,只是 docker0 網(wǎng)橋替換成了 CNI 網(wǎng)橋。CNI 網(wǎng)橋只是接管所有 CNI 插件負(fù)責(zé)的,即 Kuberntes 創(chuàng)建的容器(Pod)。
Kubernetes 中 Pod 有生命周期,它的 IP 會隨著動態(tài)的創(chuàng)建和銷毀而動態(tài)變化,不能穩(wěn)定的提供服務(wù)。Kubernetes Service 定義這樣一種抽象:一個 Pod 的邏輯分組,一種可以訪問它們的策略。開發(fā)者可以通過一個 Service 的入口地址訪問其背后的一組 Pod。一旦 Service 被創(chuàng)建,Kubernetes 就會自動為它分配一個可用的 Cluster IP,在 Service 的整個生命周期中它的 Cluster IP 都不會發(fā)生改變。這樣就解決了分布式集群的服務(wù)發(fā)現(xiàn)。
一個典型的 Service 定義如下:
apiVersion: v1 kind: Service metadata: name: nginx spec: selector: app: nginx ports: - nmae: dafault protocol: TCP port: 8000 targetPort: 80
在這個 Service 例子中,筆者使用 selector 字段聲明這個 Service 只代理 app=nginx 標(biāo)簽的 pod。這個 Service 的 8000 端口代理 Pod 的 80 端口。
然后定義應(yīng)用 Delpoyment 如下:
apiVersion: v1 kind: Delpoyment metadata: name: nginx spec: selector: matchLabels: app: nginx replicas: 3 template: meatdata: lalels: app: nginx spec: containers: - name: nginx image: nginx ports: - containers: 80 protocol: TCP
被 selector 選中的 Pod,就被稱為 Serivce 的 Endpoints,你可以使用 kubectl get ep 查看它們,如下所示:
$ kubectl get endpoints nginx NAME ENDPOINTS AGE nginx 172.20.1.16:80,172.20.2.22:80,172.20.2.23:80 1m
通過該 Service 的 VIP 10.68.57.93 地址,就可以訪問到它所代理的 Pod:
$ kubectl get svc nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP 10.68.57.9380/TCP 1m $ curl 10.68.57.93 Welcome to nginx! ......Welcome to nginx!
......
這個 VIP 地址是 Kubernetes 自動為 Service 分配的。訪問 Service 的 VIP 地址和代理的 80 端口,它就為我們返回了默認(rèn)的 nginx 頁面,這種方式稱為:Cluster IP 模式的 Service。
Servcie 的訪問信息在 kubernates 集群外無效,因?yàn)樗^的 Service 的訪問接口,實(shí)際上是每臺宿主機(jī)上由 kube-proxy 生成的 iptables 規(guī)則,以及 kube-DNS 生成的 DNS 記錄。
解決外部訪問 Kubernetes 集群里創(chuàng)建的 servcie有以下幾種方法:
NodePort
LoadBalancer
下面是 NodePort 的例子:
apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: type: NodePort ports: - name: http nodePort: 30080 port: 8080 targetPort: 80 protocol: TCP
在這個 Service 定義中,聲明它的類型為 type=NodePort。此時在 ports 字段中聲明了 Service 的 8080 端口代理 Pod的80端口。
如果你不顯示聲明 nodePort 字段,Kubernetes 會為你隨機(jī)分配可用端口來設(shè)置代理,這個端口的范圍默認(rèn)為:30000-32767。這里設(shè)置為 30080。
這里就可以如此訪問這個 service:
<任何一臺宿主機(jī) IP 地址>:30080
這種方法適用于公有云上的 Kubernetes 服務(wù),通過指定一個 LoadBalancer 類型的 Service 實(shí)現(xiàn)。
apiVersion: v1 kind: Service metadata: name: example-service spec: ports: - port: 8765 targetPort: 9379 selector: app: example type: LoadBalancer
創(chuàng)建 Service 時,你可以選擇自動創(chuàng)建云網(wǎng)絡(luò)負(fù)載均衡器。這提供了一個外部可訪問的IP地址,只要您的群集在受支持的云環(huán)境中運(yùn)行,就可以將流量發(fā)送到群集節(jié)點(diǎn)上的正確端口。
為代理不同后端 Service 而設(shè)置的路由規(guī)則集合就是 Kubernetes 里的 Ingress。
舉一個例子,這里有一個訂閱系統(tǒng),它的域名是:https://wwww.example.com 。其中 http://www.example.com/book 是訂書系統(tǒng),https://www.example.com/food 是訂餐系統(tǒng)。這兩個系統(tǒng)分別由 book 和 food 兩個 Deployment 來提供服務(wù)。
apiVersion: v1 kind: Ingress metadata: name: example-ingress spec: tls: - hosts: - www.example.com secretName: example-secret rules: - host: www.example.com http: paths: - path: book backend: serviceName: book-svc servicePort: 80 - path: /food backend: serviceName: food-svc servicePort: 80
這個 yaml 文件值得關(guān)注的 rules 字段,它叫作:IngressRules。
IngressRule 的 Key 就是 host,它必須是一個標(biāo)準(zhǔn)域名格式的字符串,不能是 IP 地址。
host 字段定義的值就是 Ingress 的入口,也就是說當(dāng)用戶訪問 www.example.com 的時候,實(shí)際上訪問到的是這個 Ingress 對象。Kubernetes就能根據(jù) IngressRule 進(jìn)行下一步轉(zhuǎn)發(fā),這里定義兩個 path,它們分別對應(yīng) book 和 food 這個兩個 Deployment 的 Service。
由此不難看出,Ingress 對象其實(shí)就是 Kubernetes 項(xiàng)目對“反向代理”的一種抽象。
上述就是小編為大家分享的如何理解Kubernets網(wǎng)絡(luò)了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。