本篇已加入《 .NET Core on K8S學習實踐系列文章索引 》,可以點選檢視更多容器化技術相關系列文章。
一、Kubernetes網絡模型
我們都知道Kubernetes作為容器編排引擎,它有一個強大又複雜的網絡模型,也牽引出了Pod網絡、Service網絡、ClusterIP、NodePort、Ingress等多個概念。這裡我們采用楊波老師(
架構師楊波)模仿TCP/IP協定棧總結的一個K8S網絡模型圖來看看K8S的四個抽象層次,進而了解一下K8S的網絡。本小節的文字主要引用自楊波老師關于K8S網絡模型的文章及CloudMan的《每天5分鐘玩轉Kubernetes》一書。
根據上圖模型中展示的四個層次,從0到3,除了第0層,每一層都是建構于前一層之上。
(1)第0層:節點主機互通互聯
主要保證K8S節點(實體或虛拟機)之間能夠正常IP尋址和互通的網絡,這個一般由底層(公有雲或資料中心)網絡基礎設施支援,這裡我們無需過多關心。
(2)第1層:Pod虛拟機互聯
在一個Pod中可以運作一個或多個容器,且Pod中所有容器使用同一個網絡namespace,即相同的IP和端口空間,可以直接用localhost通信,而且還可以共享存儲(本質是通過将Volume挂載到Pod中的每個容器)。
(3)第2層:服務發現和負載均衡
在K8S叢集中,Pod的IP并不是固定的,可能會頻繁地銷毀和建立執行個體,為了解決此問題,Service提供了通路Pod的抽象層。即無論後端Pod如何變化,Service都作為穩定的前端對外提供服務。此外,Service還提供了高可用和負載均衡的功能,它負責将請求轉發給正确的Pod。
(4)第3層:外部流量接入
K8s的Service網絡隻是一個叢集内部網絡,叢集外部是無法直接通路的。為此,想要将應用暴露出去讓公網能夠通路,K8S提供了兩種方式:
① NodePort:使Service通過Cluster節點的靜态端口對外提供服務,外部可以通過 NodeIP:NodePort 來通路Service。
② LoadBalancer:使Service利用Cloud Provider提供的Load Balancer對外提供服務,Cloud Provider負責将Load Balancer的流量導向Service。目前支援的Cloud Provider包括AWS、Azure、阿裡雲、騰訊雲等。
More:關于K8S網絡的更多基本原理與講解,強力推薦閱讀波波老師的以下文章:
二、傳說中的CNI規範
為了保證網絡方案的标準化、擴充性和靈活性,K8S采用了CNI(Container Networking Interface)規範。CNI是一個Pod網絡內建标準,簡化了K8S和不同Pod網絡實作技術的內建。CNI最大的優點就是支援多種容器runtime,而不僅僅是Docker。目前已經有多種支援K8S的網絡方案,包括 Flannel、Calico、Canal等,它們都實作了CNI規範,是以無論我們選擇哪種具體方案,它們的網絡模型都是一緻的。
More:關于CNI的更多基本原理與講解,推薦閱讀陳Sir的文章《
K8S網絡詳解:CNI與CNI網絡模型》
三、Network Policy
3.1 關于Network Policy
Network Policy是K8S的一種資源,它使K8S可以通過Label選擇Pod,并指定其他Pod或外界如何與這些Pod通信。換句話說,當Pod被定義了Network Policy時,隻有Policy允許的流量才能通路Pod(預設情況下,任何來源的流量都可以通路Pod,是沒有限制的)即幫助K8S實作更為精細的流量控制,實作租戶隔離機制。
But,并不是所有K8S網絡方案都支援Network Policy,比如Flannel就不支援,而Calico是支援的。
3.2 Network Policy實踐
3.2.1 部署Canal
想要部署Canal,需要切換網絡方案,這裡我們使用最簡單粗暴的方式:重建目前K8S叢集
kubeadm reset # 在每個節點上執行一次
然後,重新對Master節點進行初始化:
kubeadm init \
--apiserver-advertise-address=192.168.2.100 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.13.3 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16
在兩個Node節點上執行以下指令重新加入叢集:(注意這裡的token請填寫你的Master節點初始化後的輸出結果)
kubeadm join 192.168.2.100:6443 --token ekqxk2.iiu5wx5bbnbdtxsw --discovery-token-ca-cert-hash \
sha256:c50bb83d04f64f4a714b745f04682b27768c1298f331e697419451f3550f2d05
最後,通過以下指令部署Canal:(參考自
K8S官方文檔)
kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/canal.yaml
此時,再次令驗證的叢集結果如下:
(1)叢集節點狀态
(2)Pod狀态
3.2.2 部署測試應用
這裡通過一個httpd應用來示範Network Policy,該應用的yaml定義如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd
spec:
replicas: 3
selector:
matchLabels:
name: networkpolicy-demo
template:
metadata:
labels:
name: networkpolicy-demo
spec:
containers:
- name: httpd
image: httpd:latest
ports:
- containerPort: 80
imagePullPolicy: IfNotPresent
---
kind: Service
apiVersion: v1
metadata:
name: httpd-svc
spec:
type: NodePort
ports:
- protocol: TCP
nodePort: 31000
port: 8080
targetPort: 80
selector:
name: networkpolicy-demo
通過kubectl将其部署到K8S叢集:
kubectl apply -f httpd-demo.yaml
這時候三個httpd Pod已經成功Running:
由于定義的是NodePort方式暴露服務,這裡我們在叢集外部通路Service看看:
由于目前并沒有建立任何Network Policy,這裡我們可以通過建立一個Pod應用(我們熟悉的busybox)來驗證一下是否可以在K8S叢集内部随意通路該httpd應用:
kubectl run busybox --rm -it --image=busybox /bin/sh
從上圖可以知道,它可以正常通路到Service,也可以正常ping到Pod節點。
3.2.3 測試Network Policy有效性
現在我們建立一個Network Policy,其配置檔案yaml如下:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: access-httpd
spec:
podSelector:
matchLabels:
name: networkpolicy-demo
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
ports:
- protocol: TCP
port: 80
該Network Policy定義了如下規則:
(1)應用于所有 label 為 name : networkpolicy-demo 的Pod,這裡即剛剛建立的三個httpd pod。
(2)ingress中定義了隻有 label 為 access : "true" 的Pod才能通路應用。
(3)即使通過Policy也隻能通路80端口
通過kubectl将其應用到K8S叢集中:
kubectl apply -f networkpolicy.yaml
下面再次在busybox pod中驗證Network Policy的有效性:
從上圖中可以看到,已經無法再成功通路Service,也無法再ping通三個Pod節點。
這個時候,叢集外也無法再通過NodePort通路到Service:
如果想要讓測試Pod(busybox)能通路到應用了Network Policy的httpd應用,我們可以對busybox pod加一個label就可以:
kubectl run busybox --rm -it --image=busybox --labels="access=true" /bin/sh
運作後的驗證結果如下,可以通路到Service,但Ping卻被禁止:
但是,此時叢集節點(k8s-master與兩個node)與叢集仍然無法通路到應用了Network Policy的httpd應用,如果想要讓它們也通路到,則需要修改Network Policy做一個類似于開防火牆白名單的操作(注意下面的ipBlock配置):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: access-httpd
spec:
podSelector:
matchLabels:
name: networkpolicy-demo
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
- ipBlock:
cidr: 192.168.2.0/24
ports:
- protocol: TCP
port: 80
再次應用到K8S叢集後,再來通過叢集外部的通路者浏覽器試試:
可以看到,已經可以正常通路啦!
四、小結
本文簡單介紹了Kubernetes的4層網絡模型、CNI 容器網絡接口規範 以及 Network Policy,并通過改造K8S叢集的網絡配置從Flannel到Canal來驗證Network Policy的有效性。對于Kubernetes的網絡模型的原理與介紹,強烈推薦閱讀楊波老師的《Kubernetes網絡三部曲》,它的傳送門位于下方的參考資料清單中。最後,希望能夠對初學者的你有所幫助!
參考資料
(1)CloudMan,《
每天5分鐘玩轉Kubernetes(2)李振良,《
一天入門Kubernets教程(3)馬哥(馬永亮),《
Kubernetes快速入門(4)Liang,《
K8S CNI網絡最強對比(5)楊波,《
K8S網絡三部曲(6)陳Sir,《