一 Pod和SVC網路 1.1 實踐準備及原理 Docker實現了不同的網路模式,Kubernetes也以一種不同的方式來解決這些網路模式的挑戰。本完整實驗深入剖析Kubernetes在網路層是如何實現及工作的。 實驗節點架構: 如上圖所示,Kubernetes的網路模型要求每個Node上的容器都可 ...
一 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.yaml1 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.yaml1 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網橋)。