十二. k8s--網絡策略flannel與canal學習筆記


k8s網絡CNI之flannel

k8s網絡模型

  • Container to Container
  • Pod to Pod
  • Service to Pod
  • external to Service

常見CNI項目

  • Flannel,提供疊加網絡,基於linux TUN/TAP,使用UDP封裝IP報
    文來創建疊加網絡,並借助etcd維護網絡分配情況
  • Calico,基於BGP的三層網絡,支持網絡策略實現網絡的訪問控制。在每台機器上運行一個vRouter,利用內核轉發數據包,並借助iptables實現防火牆等功能
  • Canal,由Flannel和Calico聯合發布的一個統一網絡插件,支持網絡策略
  • Weave Net,多主機容器的網絡方案,支持去中心化的控制平面,數據平面上,通過UDP封裝實現L2 Overlay
  • Contiv,思科方案,直接提供多租戶網絡,支持L2(VLAN)、L3(BGP)、Overlay(VXLAN)
  • OpenContrail,Juniper開源
  • kube-router,K8s網絡一體化解決方案,可取代kube-proxy實現基於ipvs的Service,支持網絡策略、完美兼容BGP的高級特性

重點了解Flannel, Calico, Canal, kube-router

Flannel插件

首先,flannel會利用Kubernetes API或者etcd用於存儲整個集群的網絡配置,其中最主要的內容為設置集群的網絡地址空間,例如,設定整個集群內所有容器的IP都取自網段“10.1.0.0/16”。接着,flannel會在每個主機中運行flanneld作為agent,它會為所在主機從集群的網絡地址空間中,獲取一個小的網段subnet,本主機內所有容器的IP地址都將從中分配。然后,flanneld再將本主機獲取的subnet以及用於主機間通信的Public IP,同樣通過kubernetes API或者etcd存儲起來。最后,flannel利用各種backend mechanism,例如udp,vxlan等等,跨主機轉發容器間的網絡流量,完成容器間的跨主機通信。

大家都知道Kubernetes是通過CNI標准對接網絡插件的,但是當你去看Flannel(coreos/flannel)的代碼時,並沒有發現它實現了CNI的接口。如果你玩過其他CNI插件,你會知道還有一個二進制文件用來供kubele調用,並且會調用后端的網絡插件。對於Flannel(coreos/flannel)來說,這個二進制文件是什么呢?

這個二進制文件就對應宿主機的/etc/cni/net.d/flannel

flannel原理說明

	現在,我們來簡單看一下,如果上方Machine A中IP地址為10.1.15.2/24的容器要與下方Machine B中IP地址為10.1.16.2/24的容器進行通信,封包是如何進行轉發的。從上文可知,每個主機的flanneld會將自己與所獲取subnet的關聯信息存入etcd中,例如,subnet 10.1.15.0/24所在主機可通過IP 192.168.0.100訪問,subnet 10.1.16.0/24可通過IP 192.168.0.200訪問。反之,每台主機上的flanneld通過監聽etcd,也能夠知道其他的subnet與哪些主機相關聯。如下圖,Machine A上的flanneld通過監聽etcd已經知道subnet 10.1.16.0/24所在的主機可以通過Public 192.168.0.200訪問,而且熟悉docker橋接模式的同學肯定知道,目的地址為10.1.16.2/24的封包一旦到達Machine B,就能通過cni0網橋轉發到相應的pod,從而達到跨宿主機通信的目的。

	因此,flanneld只要想辦法將封包從Machine A轉發到Machine B就OK了,而上文中的backend就是用於完成這一任務。不過,達到這個目的的方法是多種多樣的,所以我們也就有了很多種backend。在這里我們舉例介紹的是最簡單的一種方式`hostgw`:因為`Machine A和Machine B處於同一個子網內`,它們原本就能直接互相訪問。因此最簡單的方法是:在Machine A中的容器要訪問Machine B的容器時,我們可以將Machine B看成是網關,當有封包的目的地址在subnet 10.1.16.0/24范圍內時,就將其直接轉發至B即可。而這通過下圖中那條紅色標記的路由就能完成,對於Machine B同理可得。由此,在滿足仍有subnet可以分配的條件下,我們可以將上述方法擴展到任意數目位於同一子網內的主機。而任意主機如果想要訪問主機X中subnet為S的容器,只要在本主機上添加一條目的地址為R,網關為X的路由即可。

flannel配置參數

Network,全局CIDR格式的IPv4網絡,字符串格式,必選
SubnetLen,子網,默認為24位
SubnetMin,分配給節點的起始子網
SubnetMax,分配給節點的最大子網
Backend,flannel要使用的后端

flannel初始配置

[root@master bin]# cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true

flannel后端實現原理

host-gw

	hostgw是最簡單的backend,它的原理非常簡單,直接添加路由,將目的主機當做網關,直接路由原始封包。例如,我們從etcd中監聽到一個EventAdded事件:subnet為10.1.15.0/24被分配給主機Public IP 192.168.0.100,hostgw要做的工作非常簡單,在本主機上添加一條目的地址為10.1.15.0/24,網關地址為192.168.0.100,輸出設備為上文中選擇的集群間交互的網卡即可。對於EventRemoved事件,刪除對應的路由即可。

VxLAN

當有一個EventAdded到來時,flanneld如何進行配置的,以及封包是如何在flannel網絡中流動的。
![](https://img2018.cnblogs.com/blog/1120683/201909/1120683-20190922231904502-1162560950.png)

如上圖所示,當主機B加入flannel網絡時,和其他所有backend一樣,它會將自己的subnet 10.1.16.0/24和Public IP 192.168.0.101寫入etcd中,和其他backend不一樣的是,它還會將vtep設備flannel.1的mac地址也寫入etcd中。

之后,主機A會得到EventAdded事件,並從中獲取上文中B添加至etcd的各種信息。這個時候,它會在本機上添加三條信息:

  1. 路由信息:所有通往目的地址10.1.16.0/24的封包都通過vtep設備flannel.1設備發出,發往的網關地址為10.1.16.0,即主機B中的flannel.1設備。

  2. fdb信息:MAC地址為MAC B的封包,都將通過vxlan首先發往目的地址192.168.0.101,即主機B

  3. arp信息:網關地址10.1.16.0的地址為MAC B

現在有一個容器網絡封包要從A發往容器B,和其他backend中的場景一樣,封包首先通過網橋轉發到主機A中。此時通過,查找路由表,該封包應當通過設備flannel.1發往網關10.1.16.0。通過進一步查找arp表,我們知道目的地址10.1.16.0的mac地址為MAC B。到現在為止,vxlan負載部分的數據已經封裝完成。由於flannel.1是vtep設備,會對通過它發出的數據進行vxlan封裝(這一步是由內核完成的,相當於udp backend中的proxy),那么該vxlan封包外層的目的地址IP地址該如何獲取呢?事實上,對於目的mac地址為MAC B的封包,通過查詢fdb,我們就能知道目的主機的IP地址為192.168.0.101。 最后,封包到達主機B的eth0,通過內核的vxlan模塊解包,容器數據封包將到達vxlan設備flannel.1,封包的目的以太網地址和flannel.1的以太網地址相等,三層封包最終將進入主機B並通過路由轉發達到目的容器。
![](https://img2018.cnblogs.com/blog/1120683/201909/1120683-20190922232039088-1750456590.png)

虛擬網絡數據幀添加到VxLAN首部后,封裝在物理網絡UDP報文中,到達目地主機后,去掉物理網絡報文頭部及VxLAN首部,再將報文交付給目的終端

VxLAN后端使用隧道網絡轉發會導致一定和流量開銷,VxLAN DirectRouting模式,通過添加必要的路由信息使用節點的二層網絡直接發送Pod通信報文,僅在跨IP網絡時,才啟用隧道方式。這樣,在不跨IP網絡時,性能基本接近二層物理網絡

已經創建的flannel的網絡配置修改后不會生效, 只能刪掉flannel, 修改yaml文件后重新創建, 所以一定要提前確定好網絡配置
# k8s網絡策略之canal

canal安裝

curl https://docs.projectcalico.org/v3.9/manifests/canal.yaml -O
kubectl apply -f canal.yaml

NetworkPolicy相關術語

kubectl explain networkpolicy.spec講解:

  • egress 出站流量規則 可以根據ports和to去定義規則。ports下可以指定目標端口和協議。to(目標地址):目標地址分為ip地址段、pod、namespace
  • ingress 入站流量規則 可以根據ports和from。ports下可以指定目標端口和協議。from(來自那個地址可以進來):地址分為ip地址段、pod、namespace
  • podSelector 定義NetworkPolicy的限制范圍。直白的說就是規則應用到那個pod上。podSelector: {},留空就是定義對當前namespace下的所有pod生效。沒有定義白名單的話 默認就是Deny ALL (拒絕所有)
  • policyTypes 指定那個規則 那個規則生效,不指定就是默認規則。

實驗

創建兩個namespace

kubectl create namespace dev
kubectl create namespace prod

創建pod

apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1

管理入站流量

kubectl explain networkpolicy.spec.ingress
NetworkPolicy屬於名稱空間級別
參數:
from,源地址對象列表,多個項目間邏輯關系為或,若為空,表示匹配一切源地址;若至少有一個值,則僅允許列表中流量通過
ports,可被訪問的端口對象列表,多個項目間為邏輯或,若為空,表示匹配Pod的所有端口;若至少有一個值,則僅允許訪問指定的端口

拒絕所有入站流量的規則:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-policy
spec:
  podSelector: {}
  policyTypes:
  - Ingress
沒有定義Ingress規則, 但是寫到了policyTypes里, 就表示默認拒絕入方向訪問, 沒有寫Egress, 表示默認允許出方向訪問
``` [root@master networkpolicy]# kubectl apply -f deny-all.yaml -n dev networkpolicy.networking.k8s.io/deny-all-policy created ``` ### 允許所有入站流量的規則:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
spec:
  podSelector: {}   # 匹配所有Pod
  ingress:
  - {}              # 定義為空, 表示允許訪問
  policyTypes: ["Ingress"]

放入特定入站流量

僅定義from將默認允許本地Pod所有端口;僅定義ports將默認允許所有源端點;同時定義from和ports時,是邏輯與關系
多個from之間是邏輯或關系
多個ports之間是邏輯或關系
from與ports間是邏輯與關系
from下ipBlock、namespaceSelector、podSelector同時使用多個時,為邏輯或關系
# 為pod打標簽
[root@master manifests]# kubectl label pod myapp -n dev app=myapp --overwrite
pod/myapp labeled
[root@master manifests]# kubectl get pod -n dev --show-labels
NAME    READY   STATUS    RESTARTS   AGE   LABELS
myapp   1/1     Running   0          29m   app=myapp
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-myapp-ingress
  name: default
spec:
  podSelector:         # 該規則只在當前的namespace下,攜帶app: myapp標簽的pod生效。限制請求的類型包括Ingress和Egress
    matchLabels:
      app: myapp
  policyTypes: ["Ingress"]
  ingress:
  - from:
    - ipBlock:                  # 網絡地址塊
        cidr: 10.244.0.0/16     # 允許某個網段訪問
        except:                 # 排除某個網段或ip訪問(只拒絕掉10.244.1.5)          
        - 10.244.1.5/32
    - podSelector:              # 攜帶了app: myapp標簽的pod可以訪問
        matchLabels:
          app: myapp
    ports:
    - protocol: TCP
      port: 80

管理出站流量

拒絕所有出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
spec:
  podSelector: {}
  policyTypes: ["Egress"]

放行特定的出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-tomcat-egress
spec:
  podSelector:
    matchLabels:
      app: tomcat
  policyTypes: ["Egress"]
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: nginx
  - ports:
    - protocol: TCP
      port: 80
  - to:
    - podSelector:
        matchLabels:
          app: mysql
    ports:
    - protocol: TCP
      port: 3306
對app=tomcat的Pod,限制只能訪問app=nginx的80端口和app=mysql的3306端口

隔離名稱空間

隔離名稱空間,應該放行與kube-system名稱空間中Pod的通信,以實現監控和名稱解析等各種管理功能

kubectl explain networkpolicy.spec.ingress.from.namespaceSelector.matchExpressions
kubectl explain networkpolicy.spec.egress.to.namespaceSelector.matchExpressions
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: namespace-deny-all
  namespace: default
spec:
  policyTypes: ["Ingress","Egress"]
  podSelector: {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: namespace-
  namespace: default
spec:
  policyTypes: ["Ingress","Egress"]
  podSelector: {}
  ingress:
  - from:
    - namespaceSelector:
        matchExpressions:
        - key: name
          operator: In
          values: ["default","kube-system"]
  egress:
  - to:
    - namespaceSelector:
        matchExpressions:
        - key: name
          operator: In
          values: ["default","kube-system"]

參考鏈接

https://pdf.us/2019/03/27/3129.html

https://my.oschina.net/jxcdwangtao/blog/1624486

https://www.cnblogs.com/YaoDD/p/7681811.html

https://www.cnblogs.com/xzkzzz/p/9952716.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM