1.Kubernetes 網絡模型
Kubernetes 采用的是基於扁平地址空間的網絡模型,集群中的每個 Pod 都有自己的 IP 地址,Pod 之間不需要配置 NAT 就能直接通信。另外,同一個 Pod 中的容器共享 Pod 的 IP,能夠通過 localhost 通信。
這種網絡模型對應用開發者和管理員相當友好,應用可以非常方便地從傳統網絡遷移到 Kubernetes。每個 Pod 可被看作是一個個獨立的系統,而 Pod 中的容器則可被看做同一系統中的不同進程。
下面討論在這個網絡模型下集群中的各種實體如何通信。知識點前面都已經涉及,這里可當做復習和總結。
1.1Pod 內容器之間的通信
當 Pod 被調度到某個節點,Pod 中的所有容器都在這個節點上運行,這些容器共享相同的本地文件系統、IPC 和網絡命名空間。
不同 Pod 之間不存在端口沖突的問題,因為每個 Pod 都有自己的 IP 地址。當某個容器使用 localhost 時,意味着使用的是容器所屬 Pod 的地址空間。
比如 Pod A 有兩個容器 container-A1 和 container-A2,container-A1 在端口 1234 上監聽,當 container-A2 連接到 localhost:1234,實際上就是在訪問 container-A1。這不會與同一個節點上的 Pod B 沖突,即使 Pod B 中的容器 container-B1 也在監聽 1234 端口。
1.2Pod 之間的通信
Pod 的 IP 是集群可見的,即集群中的任何其他 Pod 和節點都可以通過 IP 直接與 Pod 通信,這種通信不需要借助任何的網絡地址轉換、隧道或代理技術。Pod 內部和外部使用的是同一個 IP,這也意味着標准的命名服務和發現機制,比如 DNS 可以直接使用。
1.3Pod 與 Service 的通信
Pod 間可以直接通過 IP 地址通信,但前提是 Pod 得知道對方的 IP。在 Kubernetes 集群中, Pod 可能會頻繁的銷毀和創建,也就是說 Pod 的 IP 不是固定的。為了解決這個問題,Service 提供了訪問 Pod 的抽象層。無論后端的 Pod 如何變化,Service 都作為穩定的前端對外提供服務。同時,Service 還提供了高可用和負載均衡功能,Service 負責將請求轉發給正確的 Pod。
1.4外部訪問
無論是 Pod 的 IP 還是 Service 的 Cluster IP,它們只能在 Kubernetes 集群中可見,對集群之外的世界,這些 IP 都是私有的。
Kubernetes 提供了兩種方式讓外界能夠與 Pod 通信:
-
NodePort
Service 通過 Cluster 節點的靜態端口對外提供服務。外部可以通過<NodeIP>:<NodePort>訪問 Service。 -
LoadBalancer
Service 利用 cloud provider 提供的 load balancer 對外提供服務,cloud provider 負責將 load balancer 的流量導向 Service。目前支持的 cloud provider 有 GCP、AWS、Azur 等。
2.kubernetes的網絡實現
網絡模型有了,如何實現呢?
為了保證網絡方案的標准化、擴展性和靈活性,Kubernetes 采用了 Container Networking Interface(CNI)規范。
CNI 是由 CoreOS 提出的容器網絡規范,它使用了插件(Plugin)模型創建容器的網絡棧。

CNI 的優點是支持多種容器 runtime,不僅僅是 Docker。CNI 的插件模型支持不同組織和公司開發的第三方插件,這對運維人員來說很有吸引力,可以靈活選擇適合的網絡方案。
目前已有多種支持 Kubernetes 的網絡方案,比如 Flannel、Calico、Canal、Weave Net 等。因為它們都實現了 CNI 規范,用戶無論選擇哪種方案,得到的網絡模型都一樣,即每個 Pod 都有獨立的 IP,可以直接通信。區別在於不同方案的底層實現不同,有的采用基於 VxLAN 的 Overlay 實現,有的則是 Underlay,性能上有區別。再有就是是否支持 Network Policy。
3.kubernetes的Network Policy
Network Policy 是 Kubernetes 的一種資源。Network Policy 通過 Label 選擇 Pod,並指定其他 Pod 或外界如何與這些 Pod 通信。
默認情況下,所有 Pod 是非隔離的,即任何來源的網絡流量都能夠訪問 Pod,沒有任何限制。當為 Pod 定義了 Network Policy,只有 Policy 允許的流量才能訪問 Pod。
不過,不是所有的 Kubernetes 網絡方案都支持 Network Policy。比如 Flannel 就不支持,Calico 是支持的。我們接下來將用 Canal 來演示 Network Policy。Canal 這個開源項目很有意思,它用 Flannel 實現 Kubernetes 集群網絡,同時又用 Calico 實現 Network Policy。
3.1部署 Canal
部署 Canal 與部署其他 Kubernetes 網絡方案非常類似,都是在執行了 kubeadm init 初始化 Kubernetes 集群之后通過 kubectl apply 安裝相應的網絡方案。也就是說,沒有太好的辦法直接切換使用不同的網絡方案,基本上只能重新創建集群。
要銷毀當前集群,最簡單的方法是在每個節點上執行 kubeadm reset。然后就可以按照我們在前面 “部署 Kubernetes Cluster” 一章的 “初始化 Master” 小節中的方法初始化集群。
kubeadm init --apiserver-advertise-address 10.0.0.11 --pod-network-cidr=10.244.0.0/16

執行下面的命令部署 Canal
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/canal/rbac.yaml kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/canal/canal.yaml
部署成功后,可以查看到 Canal 相關組件:

不出意外這幾個容器是起不來的,因為默認下載的鏡像是從谷歌的鏡像站下載(需要使用科學上網手段)
看了下日志,驗證了我的說法

4.Network Policy實踐
為了演示 Network Policy,我們先部署一個 httpd 應用,其配置文件 httpd.yaml 為

httpd 有三個副本,通過 NodePort 類型的 Service 對外提供服務。部署應用:

當前沒有定義任何 Network Policy,驗證應用可以被訪問:
-
啟動一個 busybox Pod,可以訪問 Service,也可以 Ping 到副本 Pod。

2. 集群節點可以訪問 Service, 也可以 Ping 到副本 Pod。


3.可以通過映射端口訪問宿主機的web

現在創建如下 Network Policy:

① 定義將此 Network Policy 中的訪問規則應用於 label 為 run: httpd 的 Pod,即 httpd 應用的三個副本 Pod。
② ingress 中定義只有 label 為 access: "true" 的 Pod 才能訪問應用。
③ 只能訪問 80 端口。
通過 kubectl apply 創建 Network Policy。

驗證 Network Policy 的有效性:
1.busybox Pod 已經不能訪問 Service。(flannel網絡不支持networkpolicy需要改成 canal或者 Calico)

如果 Pod 添加了 label access: "true" 就能訪問到應用,但 Ping 已經被禁止。

2.集群節點已經不能訪問 Service, 也 Ping 不到副本 Pod。
3.集群外(10.0.0.1)已經不能訪問 Service。
如果希望讓集群節點和集群外(10.0.01)也能夠訪問到應用,可以對 Network Policy 做如下修改:

重新apply 一下配置文件就可以在pod集群內不加label參數訪問和pod集群外宿主機通過30000端口訪問。
除了通過 ingress 限制進入的流量,也可以用 egress 限制外出的流量。大家可以參考官網相關文檔和示例,這里就不贅述了。
5.小結
Kubernetes 采用的是扁平化的網絡模型,每個 Pod 都有自己的 IP,並且可以直接通信。
CNI 規范使得 Kubernetes 可以靈活選擇多種 Plugin 實現集群網絡。
Network Policy 則賦予了 Kubernetes 強大的網絡訪問控制機制(相當於linux的防火牆功能)。
