一 Pod和SVC網絡
1.1 實踐准備及原理
Docker實現了不同的網絡模式,Kubernetes也以一種不同的方式來解決這些網絡模式的挑戰。本完整實驗深入剖析Kubernetes在網絡層是如何實現及工作的。
實驗節點架構:
如上圖所示,Kubernetes的網絡模型要求每個Node上的容器都可以相互訪問。默認的Docker網絡模型提供了一個IP地址段是172.17.0.0/16的docker0網橋。每個容器都會在這個子網內獲得IP地址,並且將docker0網橋的IP地址(172.17.42.1)作為其默認網關。需要注意的是,Docker宿主機外面的網絡不需要知道任何關於這個172.17.0.0/16的信息或者知道如何連接到其內部,因為Docker的宿主機針對容器發出的數據,在物理網卡地址后面都做了IP偽裝MASQUERADE(隱含NAT)。也就是說,在網絡上看到的任何容器數據流都來源於那台Docker節點的物理IP地址。這里所說的網絡都指連接這些主機的物理網絡。
默認的Docker網絡模型簡單便捷,但需要依賴端口映射的機制。在Kubernetes的網絡模型中,每台主機上的docker0網橋都是可以被路由到的。也就是說,在部署了一個Pod時,在同一個集群內,各主機都可以訪問其他主機上的Pod IP,並不需要在主機上做端口映射。
因此,可以在網絡層將Kubernetes的節點看作一個路由器,其網絡架構如下:
二 Pod和SVC實驗
2.1 檢查環境
[root@k8smaster02 ~]# ifconfig #node1上檢查網絡地址
由上可知,有一個docker0網橋和一個本地eth0地址的網絡端口。
2.2 創建RC
[root@k8smaster01 study]# vi frontend-controller.yaml
1 apiVersion: v1 2 kind: ReplicationController 3 metadata: 4 name: frontend 5 labels: 6 name: frontend 7 spec: 8 replicas: 1 9 selector: 10 name: frontend 11 template: 12 metadata: 13 labels: 14 name: frontend 15 spec: 16 containers: 17 - name: php-redis 18 image: kubeguide/guestbook-php-frontend 19 env: 20 - name: GET_HOSTS_FROM 21 value: env 22 ports: 23 - containerPort: 80 24 hostPort: 80
[root@k8smaster01 study]# kubectl create -f frontend-controller.yaml
2.3 再次檢查網絡
[root@k8smaster01 study]# kubectl get pods -o wide
Kubernetes為這個Pod找了一個主機172.24.8.71(k8smaster01) 來運行它。另外,這個Pod獲得了一個在k8smaster01的docker0網橋上的IP地址。
[root@k8smaster01 study]# docker ps #k8smaster01上查看正在運行的容器
第2個運行的是一個google_containers/pause:latest的鏡像,而且這個容器已經做了端口映射。
[root@k8smaster01 study]# docker inspect c6578085541b | grep NetworkMode #查看容器的網絡模型
"NetworkMode": "default",
[root@k8smaster01 study]# docker inspect da8251102c93 | grep NetworkMode
"NetworkMode": "container:c6578085541b6f47ab624134d0ed0be352b30b42379493a71a8fc913d829989c",
解釋:第1個容器是運行了“google_containers/pause:latest”鏡像的容器,它使用了Docker默認的網絡模型bridge(默認網絡模型即為橋接);
第2個容器,也就是在RC/Pod中定義運行的php-redis容器,使用了非默認的網絡配置和映射容器的模型,指定了映射目標容器為“google_containers/pause:latest”。
2.4 網絡模型釋義
首先,一個Pod內的所有容器都需要共用同一個IP地址,這就意味着一定要使用網絡的容器映射模式。然而,為什么不能只啟動第1個Pod中的容器,而將第2個Pod中的容器關聯到第1個容器呢?
Kubernetes主要基於如下兩個覺得考慮:
首先,如果在Pod內有多個容器的話,則可能很難連接這些容器;
其次,后面的容器還要依賴第1個被關聯的容器,如果第2個容器關聯到第1個容器,且第1個容器異常的話,第2個容器也將異常。
啟動一個基礎容器,然后將Pod內的所有容器都連接到基礎容器相對容易。因為只需要為基礎的這個Google_containers/pause容器執行端口映射規則,這也簡化了端口映射的過程。所以啟動Pod后的網絡模型類似下圖:
實際上,應用容器直接監聽了這些端口,和google_containers/pause容器共享了同一個網絡堆棧。這就是為什么在Pod內部實際容器的端口映射都顯示到google_containers/pause容器上了。
[root@k8smaster01 study]# docker port c6578085541b #通過dockerport命令來檢驗端口轉發
80/tcp -> 0.0.0.0:80
綜上所述,google_containers/pause容器實際上只是負責接管這個Pod的Endpoint。
2.5 發布SVC
Service允許我們在多個Pod之間抽象一些服務,而且服務可以通過提供在同一個Service的多個Pod之間的負載均衡機制來支持水平擴展。
[root@k8smaster01 study]# vi frontend-service.yaml
1 apiVersion: v1 2 kind: Service 3 metadata: 4 name: frontend 5 labels: 6 name: frontend 7 spec: 8 ports: 9 - port: 80 10 selector: 11 name: frontend
[root@k8smaster01 study]# kubectl create -f frontend-service.yaml
[root@k8smaster01 study]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend ClusterIP 10.254.176.53 <none> 80/TCP 45s
釋義:如上可知Kubernetes集群已經為這個服務分配了一個虛擬IP地址10.254.176.53,這個IP地址是在Kubernetes的Portal Network中分配的。 而這個Portal Network的地址范圍是我們在Kubmaster上啟動API服務進程時,使用--service-cluster-ip-range=xx命令行參數指定:
[root@k8smaster01 study]# cat /etc/systemd/system/kube-apiserver.service | grep 10.254
--service-cluster-ip-range=10.254.0.0/16 \
注意:這個IP段可以是任何段,只要不和docker0或者物理網絡的子網沖突即可。選擇任意其他網段的原因是這個網段將不會在物理網絡和docker0網絡上進行路由。這個Portal Network針對每一個Node都有局部的特殊性,實際上它存在的意義是讓容器的流量都指向默認網關(也就是docker0網橋)。
2.6 確認驗證
當所有的Pod都運行起來,Service將會把客戶端請求負載分發到包含“name=frontend”標簽的所有Pod上。
注意:本實驗更詳細的步驟參考:https://blog.csdn.net/qq_31136839/article/details/99778434。