flannel
是一種 CNI 解決方案,也可以為 Dokcer 提供服務,對 k8s 而言,是一個網絡插件。
- 實作了 CNI 的網絡控制平面軟體
- 屬于 coreOS 的子項目
- 通過配置主機路由或者 overlay,避免對實體路由器進行配置
- VxLAN
- UDP
- Host-GW
和 k8s 內建時,運作在 work node 上面,監聽 k8s master 的狀态,共用 k8s 的控制節點的 etcd 作為自己的資料庫。

安裝
實驗節點分布
- master node
# 初始化 master 節點 sudo kubeadm reset sudo kubeadm init --config kubadm.yaml # 下載下傳 flannel 配置檔案 wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml # 修改配置檔案,net-json 改為 k8s 安裝的 podSubnet,type 預設為 vxlan net-conf.json: | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan" } } # 部署 kubectl apply -f kube-flannel.yml # 檢視 kubectl get pods --all-namespaces --- NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-66bff467f8-m7ghl 0/1 ContainerCreating 0 11m kube-system coredns-66bff467f8-mgnj7 0/1 ContainerCreating 0 11m kube-system etcd-x-vm 1/1 Running 0 11m kube-system kube-apiserver-x-vm 1/1 Running 1 11m kube-system kube-controller-manager-x-vm 1/1 Running 0 11m kube-system kube-flannel-ds-amd64-g7hl9 1/1 Running 0 35s kube-system kube-proxy-5x7l5 1/1 Running 0 11m kube-system kube-scheduler-x-vm 1/1 Running 0 11m # 多次檢視,可以看到 coredns Pending -> ContainerCreating -> Running,因為 flannel 初始化初始化完成之後,k8s 認為目前節點可用,就建立了 coredns
-
worker node
安裝 docker、kubeadm,關閉 swap,加入到叢集中,hostname 不能重複
在 worker node 上檢視容器,确認 flannel、kube-proxy 已經運作# 在 master node 上初始化完成之後,會輸出如下 token kubeadm join 192.168.121.137:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:719b052641c7681b770f9609e82d6a8001ef9aa1125db6cea7b1a452d555c34a # 加入完成後,在 master node 上檢視 kubectl get nodes NAME STATUS ROLES AGE VERSION worker Ready <none> 52s v1.18.4 x-vm Ready master 23m v1.18.4
k8s flannel 插件 基本通信原理flannel - 調整 coredns,使其分布到 worker node 上
檢視 pod 分布情況# -n 指定 namespace,先删除 kubectl scale -n kube-system deployment.v1.apps/coredns --replicas=0 # 再将數量調整為 2,期望結果是兩個 codedns 的 pod 分布到兩個節點上 kubectl scale -n kube-system deployment.v1.apps/coredns --replicas=2
,已經分布到兩個節點上kubectl get pods --all-namespaces -o wide
檢視 worker node 網卡資訊,可以看到 doredns 容器對應的 veth 已經存在,而且也有了 cni 網卡k8s flannel 插件 基本通信原理flannel k8s flannel 插件 基本通信原理flannel
host-gw 實作
基本原理
在 kube-net 網絡實作中:
- 同 node 中的 pod 互相通信是通過 cbr0 網橋二層互通
- 跨 node 通信是通過主機的預設路由,路由到實體網絡中進行資料轉發,此時需要在實體路由器上進行路由相關的配置
部署 flannel 時,将配置檔案中
net-json
字段的
Type
修改為
host-gw
。
Flannel host-gw 實作方案中,由于 linux 具有路由轉發功能,是以可以将實體路由器相關的配置下沉到 work node (主機)上,由主機進行路由,類似于DVR,也避免了單點故障。
Flannel 連接配接 k8s 的資料庫,每個 node 上的 flanned 程序知道所有 podSubnet 對應的 node,進而在主機的網絡空間中配置 podSubnet 的路由指向對應的 node。
Flannel 環境中連接配接 pod 的 Linuxbridge 為 cni0(kube-net 是 cbr0),所有的 work node 必須在同一個二層網絡中(添加路由時必須是二層可達才會生效)
實操
Flannel 安裝完成後,檢視路由資訊:
# 在 master node 上建立一個臨時的 pod,使用 nodeSelector 指定運作的 node
kubectl run -it --rm --restart=Never test1 --image busybox --overrides='{"apiVersion": "v1","spec": {"nodeSelector": {"kubernetes.io/hostname": "x-vm"}}}' sh
# 新開一個視窗,在 work node 上建立一個臨時的 pod
kubectl run -it --rm --restart=Never test2 --image busybox --overrides='{"apiVersion": "v1","spec": {"nodeSelector": {"kubernetes.io/hostname": "worker"}}}' sh
新開一個視窗,檢查一個 pod 運作情況,可以看到分布在兩個 node 上,IP 分别是 11.0.0.5 和 11.0.1.3
用 pod test1 去 ping test2,在 work node 上抓包
可以從實體網卡抓到兩個 pod 之間的通信流量
在 pod test1 上 traceroute test2,可以看到路徑經過了 work node 到達 test2
VxLAN 實作
基本原理
- Ethernet Frame 封裝到 UDP 中
- 不考慮實體網絡沖突問題
- 封裝需要額外的 50 位元組(網卡預設 MTU 為 1450)
- 允許 woker node 分布到三層網絡中
VxLAN 資料包封裝:
Flannel VxLAN 基于 Linux 原生的方式實作 VxLAN
# Linux 通過 VxLAN 位元組口實作 VxLAN 的封裝解封裝
ip link add vxlan0 type vxlan id 1 \
remote 192.168.121.137 \
local 192.168.121.138 \
dstport 8472 \
dev eth0
# 通過監聽端口來攔截資料進行封裝解封裝
Flannel 的 VxLAN 實作
Flannel 會在 node 上額外建立
flannel.<vni>
裝置,挂載的 ip 為目前 node podSubnet 的第 0 個位址作為 VTEP 位址。
當有多個 node 時,如果按照 Linux 原生方式實作 VxLAN 時,每個 node 都要和其他 node 建立 VxLAN 隧道,也就是每個 node 上都要建立多個類型為 vxlan 的 netdev 裝置,這樣子接口的數量就是 n^2。
為了避免這種情況,flannel 添加 flannel.vni 子接口的時候,并沒有指定 remote ip,而是添加了對端 flannel.vni 的靜态 arp 表項,并添加二層轉規則(bridge fdb 檢視),如果是發往對端的 flannel.vni 的 MAC 位址的話,從本端子接口發出,且指定了遠端的 VTEP 位址。
實操
- 清理 host-gw 環境,修改配置檔案,重新部署 flannel
# 删除 flannel kubectl delete -f kube-flannel.yml # 删除 coredns kubectl scale -n kube-system deployment.v1.apps/coredns --replicas=0 # 修改 kube-flannel.yml 中 net-json type 為 vxlan # 重新部署 kubectl apply -f kube-flannel.yml # 添加 coredns kubectl scale -n kube-system deployment.v1.apps/coredns --replicas=2
-
檢視網卡資訊
ip addr,可以看到 vni 接口
檢視 arp 表k8s flannel 插件 基本通信原理flannel 檢視轉發資料庫,bridge fdbk8s flannel 插件 基本通信原理flannel 在 work node 上檢視接口,MAC 位址和 master node 上的轉發表一緻k8s flannel 插件 基本通信原理flannel k8s flannel 插件 基本通信原理flannel - 建立 pod ,抓包驗證
檢視 pods 分布情況:# 在 master node 上建立一個臨時的 pod,使用 nodeSelector 指定運作的 node kubectl run -it --rm --restart=Never test1 --image busybox --overrides='{"apiVersion": "v1","spec": {"nodeSelector": {"kubernetes.io/hostname": "x-vm"}}}' sh # 新開一個視窗,在 work node 上建立一個臨時的 pod kubectl run -it --rm --restart=Never test2 --image busybox --overrides='{"apiVersion": "v1","spec": {"nodeSelector": {"kubernetes.io/hostname": "worker"}}}' sh
用 test1 ping test2 ,在 worker 實體接口上抓包,可以看到封裝資料包的内容k8s flannel 插件 基本通信原理flannel k8s flannel 插件 基本通信原理flannel
UDP 實作
非 VxLAN 的 UDP 資料封裝,不推薦使用
資料經過使用者态轉發,性能低