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 不能重複
# 在 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
在 worker node 上查看容器,確認 flannel、kube-proxy 已經運行
-
調整 coredns,使其分佈到 worker node 上
# -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
查看 pod 分佈情況
kubectl get pods --all-namespaces -o wide
,已經分佈到兩個節點上
查看 worker node 網卡信息,可以看到 doredns 容器對應的 veth 已經存在,而且也有了 cni 網卡
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 表
查看轉發數據庫,bridge fdb
在 work node 上查看接口,MAC 地址和 master node 上的轉發表一致
-
創建 pod ,抓包驗證
# 在 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
查看 pods 分佈情況:
用 test1 ping test2 ,在 worker 物理接口上抓包,可以看到封裝數據包的內容
UDP 實現
非 VxLAN 的 UDP 數據封裝,不推薦使用
數據經過用戶態轉發,性能低