天天看點

ASP.NET Core on K8S深入學習(11)K8S網絡知多少一、Kubernetes網絡模型二、傳說中的CNI規範三、Network Policy四、小結參考資料

本篇已加入《 .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,《