Ensp 模擬 Calico 跨網段 Bgp 網絡
之前詳細介紹了calico的ipip、vxlan、bgp模式, 但是所有的k8s節點都是同網段的, 本篇使用ensp和workstation在自己家里就可以模擬測試跨網段k8s集群calico方案的純bgp模式。
架構搭建
本測試搭建的是"每機柜獨立自治系統"架構, 參考:The *AS Per Rack* model[1]
跨網段k8s集群架構
整個架構分為ensp部分和workstation部分, ensp部分主要是搭建出R1和R2的ebgp關系以及分別在R1和R2上添加各自網段內的k8s節點的bgp peer,workstation部分為構建跨網端的k8s集群。因為192.168.219.0/24網段的主機加入集群需要依賴ensp中的路由, 操作的順序是先搭建出ensp的網絡部分再將新節點加到k8s中繼而配置bgp。現有k8s集群有三臺服務器均通過橋接聯網, 一臺master節點兩臺普通節點, 分別如下
- k8s-master:10.30.81.127
- k8s-node1:10.30.81.128
- k8s-node2:10.30.81.130
ensp配置
按照上圖搭建出ensp部分的網絡設備連接拓撲, 然后分別配置R1、R2和兩朵云, R1和R2上配置如下
- :'
- R1上配置
- '
- # 接口ip配置
- int g0/0/0
- ip a 20.20.20.10 24
- int g0/0/1
- ip a 10.30.81.118 24
- int g0/0/2
- ip a 30.30.30.10 24
- # 設置靜態路由, 跳到下一個網段
- ip route-static 192.168.219.0 24 20.20.20.20
- ip route-static 192.168.219.0 24 30.30.30.20
- # bgp配置, 把同AS內的ibgp peer也配置了
- bgp 64512
- peer 10.30.81.127 as-number 64512
- peer 10.30.81.128 as-number 64512
- peer 10.30.81.130 as-number 64512
- peer 192.168.219.10 as-number 64513
- peer 192.168.219.10 ebgp-max-hop 5
- peer 192.168.219.10 connect-interface g0/0/1
- peer 10.30.81.127 reflect-client
- peer 10.30.81.128 reflect-client
- peer 10.30.81.130 reflect-client
- display bgp peer
- display bgp ip-routing
- display ip interface br
- display ip routing-table
- :'
- R2上配置
- '
- # 接口ip配置
- int g0/0/0
- ip a 192.168.219.10 24
- int g0/0/1
- ip a 20.20.20.20 24
- int g0/0/2
- ip a 30.30.30.20 24
- # 設置靜態路由, 跳到下一個網段
- ip route-static 10.30.81.0 24 20.20.20.10
- ip route-static 10.30.81.0 24 30.30.30.10
- # bgp配置, 把同AS內的ibgp peer也配置了
- bgp 64513
- peer 10.30.81.118 as-number 64512
- peer 10.30.81.118 ebgp-max-hop 5
- peer 10.30.81.118 connect-interface g0/0/0
- peer 192.168.219.20 as-number 64513
- peer 192.168.219.40 as-number 64513
- peer 192.168.219.20 reflect-client
- peer 192.168.219.40 reflect-client
- display bgp peer
- display bgp ip-routing
- display ip interface br
- display ip routing-table
按如上配置好后R1和R2, 并且配置好兩朵云后, 在R2上ping 10.30.81.118是可以成功的了, 并且我們也可以觀察到R1和R2已經建立起了EBGP關系。但是從R2上ping k8s集群的任何一臺主機都不通, 而是會報host unreachable, 因為k8s節點主機上并沒有回程路由, 它們并不知道將icmp的replay包發往往R1, 因此需要在三臺主機上添加路由
- # 此時添加如下路由也不會有效, 因為從R2上發出來的ping包源ip不是192.1168.219.0/24網段的
- route add -n 192.168.219.0/24 gw 10.30.81.118 dev ens33
- echo route add -n 192.168.219.0/24 gw 10.30.81.118 dev ens33 >> /etc/rc.local
- ip route add 192.168.219.0/24 via 10.30.81.118 dev ens33
- # 添加如下路由才會在R2上ping通現有k8s集群節點。 可以在ping通后刪除掉, 因為R2只是中間節點而已
- route add -n 20.20.20.0/24 gw 10.30.81.118 dev ens33
- route add -n 30.30.30.0/24 gw 10.30.81.118 dev ens33
在k8s所有節點添加了如上的路由就可以在R2上ping通所有的k8s節點了
新機器加入k8s集群
創建虛機并配置它的網絡為nat模式,配置它們的網卡和路由, 注意不要讓它們有10.30.81.0/24網段的路由指向vmnet8。網卡配置如下
- # 網卡配置如下
- [root@k8s-node4 ~]# cat ifcfg-ens33
- TYPE=Ethernet
- DNS1=8.8.8.8
- IPADDR=192.168.219.40
- NETMASK=255.255.255.0
- GATEWAY=192.168.219.10
- BOOTPROTO=static
- DEFROUTE=yes
- IPV4_FAILURE_FATAL=no
- NAME=ens33
- UUID=6ef9b5bf-31c1-43b9-89d6-b8e89ab3c9c3
- DEVICE=ens33
- ONBOOT=yes
- # 下面的路由可以不加
- route add -net 10.30.81.0/24 gw 192.168.219.10 dev ens33
之后就是節點加入k8s的準備
系統配置, 如下
- echo "Stop Firewalld"
- systemctl stop firewalld
- systemctl disable firewalld
- sed -ie 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
- setenforce 0
- echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
- echo "net.bridge.bridge-nf-call-ip6tables = 1" >>/etc/sysctl.conf
- echo "net.bridge.bridge-nf-call-iptables = 1" >>/etc/sysctl.conf
- echo "net.bridge.bridge-nf-call-arptables = 1" >>/etc/sysctl.conf
- swapoff -a
- echo swapoff -a >> /etc/rc.local
- sysctl -p
從已k8s集群節點中將kubeadm、kubelet、kubectl的二進制文件拷貝到/usr/bin目錄下,設置kubelet開機自啟,kubelet的配置如下
- [Unit]
- Description=kubelet: The Kubernetes Node Agent
- Documentation=https://kubernetes.io/docs/
- Wants=network-online.target
- After=network-online.target
- [Service]
- ExecStart=/usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2 --fail-swap-on=false
- Restart=always
- StartLimitInterval=0
- RestartSec=10
- [Install]
- WantedBy=multi-user.target
安裝docker
從已有k8s集群節點中將calico相關的容器鏡像、kube-proxy鏡像導出并給導入到新節點中。集群已經存在了, k8s控制平面的apiserver、etcd、controller-manager、scheduler鏡像可以不拷到新節點。
使用kubeadm將新節點加入k8s集群
驗證跨網段之間的通信是走了ensp網絡的, 從k8s-master上跟蹤到k8s-node3的路由路徑, 下一跳中存在20.20.20.20為R2的接口
- [root@k8s-master ~]# traceroute 192.168.219.20
- traceroute to 192.168.219.20 (192.168.219.20), 30 hops max, 60 byte packets
- 1 10.30.81.118 (10.30.81.118) 18.396 ms 79.412 ms 79.396 ms
- 2 20.20.20.20 (20.20.20.20) 79.387 ms 79.380 ms 83.814 ms
- 3 k8s-node3 (192.168.219.20) 108.104 ms 112.777 ms 117.847 ms
通過如上搭建出了5節點的跨網段k8s集群, 如下
- [root@k8s-node4 ~]# kubectl get node -o wide
- NAME STATUS ROLES AGE VERSION INTERNAL-IP
- k8s-master Ready control-plane,master 45d v1.20.0 10.30.81.127
- k8s-node1 Ready <none> 45d v1.20.0 10.30.81.128
- k8s-node2 Ready <none> 9d v1.20.0 10.30.81.130
- k8s-node3 Ready <none> 20h v1.20.0 192.168.219.20
- k8s-node4 Ready <none> 20h v1.20.0 192.168.219.40
calico配置bgp
配置bgp需要使用calicoctl工具, 自己準備好, 配置bgp主要分為以下步驟
- 確認calico部署是純BGP模式
- 關閉BGP默認的full mesh模式
- 修改指定主機k8s-node3和k8s-node4的bgp as number值為64513
- 給所有主機打標簽進行bgp as分組, 滿足bpg peer選擇特定的peer對等體
- 創建bgp peer, 通過第四步打的標簽讓rr client與rr建立ibgp關系
確認calico-node的如下兩個配置為Never
- - name: CALICO_IPV4POOL_IPIP
- value: "Never"
- - name: CALICO_IPV4POOL_VXLAN
- value: "Never"
calico的bgp模式默認是full mesh的, 將其關閉
- calicoctl get bgpconfiguration default -o yaml
- apiVersion: projectcalico.org/v3
- items:
- - apiVersion: projectcalico.org/v3
- kind: BGPConfiguration
- metadata:
- creationTimestamp: "2021-09-05T06:23:50Z"
- name: default
- resourceVersion: "555583"
- uid: 9438105f-cdd8-4315-8694-6d4885c76c85
- spec:
- logSeverityScreen: Info
- nodeToNodeMeshEnabled: false # 修改為false后calicoctl apply -f bgpconfiguration.yaml
- kind: BGPConfigurationList
- metadata:
- resourceVersion: "580613"
將calico節點k8s-node3和k8s-node4的bgp as number設置為64513
- calicoctl get node k8s-node3 -o yaml > node3.yaml
- apiVersion: projectcalico.org/v3
- kind: Node
- metadata:
- annotations:
- projectcalico.org/kube-labels: '{"beta.kubernetes.io/arch":"amd64","beta.kubernetes.io/os":"linux","kubernetes.io/arch":"amd64","kubernetes.io/hostname":"k8s-node3","kubernetes.io/os":"linux"}'
- creationTimestamp: "2021-09-04T14:03:35Z"
- labels:
- beta.kubernetes.io/arch: amd64
- beta.kubernetes.io/os: linux
- kubernetes.io/arch: amd64
- kubernetes.io/hostname: k8s-node3
- kubernetes.io/os: linux
- name: k8s-node3
- resourceVersion: "580885"
- uid: 64f44ad1-f537-43f3-9f0e-d5d5b80adba2
- spec:
- addresses:
- - address: 192.168.219.20/24
- type: CalicoNodeIP
- - address: 192.168.219.20
- type: InternalIP
- bgp:
- asNumber: 64513 # 添加這一行
- ipv4Address: 192.168.219.20/24
- orchRefs:
- - nodeName: k8s-node3
- orchestrator: k8s
- status:
- podCIDRs:
- - 10.244.4.0/24
給節點打標簽
- :'
- 給as64512的節點打標簽
- '
- kubectl label nodes k8s-master as-group=as64512
- kubectl label nodes k8s-master as-id=as64512
- kubectl label nodes k8s-node1 as-group=as64512
- kubectl label nodes k8s-node1 as-id=as64512
- kubectl label nodes k8s-node2 as-group=as64512
- kubectl label nodes k8s-node2 as-id=as64512
- :'
- 給as64513的節點打標簽
- '
- kubectl label nodes k8s-node3 as-group=as64513
- kubectl label nodes k8s-node3 as-id=as64513
- kubectl label nodes k8s-node4 as-group=as64513
- kubectl label nodes k8s-node4 as-id=as64513
- :'
- 后面部署pod測試跨網段節點的pod間的通信使用
- '
- kubectl label nodes k8s-master node=master
- kubectl label nodes k8s-node4 node=node4
- kubectl label nodes k8s-node3 node=node3
- kubectl label nodes k8s-node2 node=node2
- kubectl label nodes k8s-node1 node=node1
創建calico的bgp peer實例, 因為在ensp配置部分已經在R1、R2上配置好了RR模式。在RR模式下我們選擇將所有的k8s節點都作為rr的client, 因此同意as下的k8s節點間不需要再建立ibgp對等體關系,剩下的則讓各自as的k8s節點分別和R1與R2建立ibgp關系即可
- :'
- 區域as64513的k8s節點與R2建立rr關系
- '
- vim as64513_r2_peer.yaml
- apiVersion: projectcalico.org/v3
- kind: BGPPeer
- metadata:
- name: as64513-to-r2-peer ## 給BGPPeer取一個名稱,方便識別
- spec:
- nodeSelector: rr-id == 'as64513' ## 通過節點選擇器添加有rr-id == 'as64513'標簽的節點
- peerIP: 192.168.219.10
- asNumber: 64513
- :'
- 區域as64512的k8s節點與R1建立rr關系
- '
- vim as64512_r1_peer.yaml
- apiVersion: projectcalico.org/v3
- kind: BGPPeer
- metadata:
- name: as64512-to-r1-peer ## 給BGPPeer取一個名稱,方便識別
- spec:
- nodeSelector: rr-id == 'as64512' ## 通過節點選擇器添加有rr-id == 'as64512'標簽的節點
- peerIP: 10.30.81.118
- asNumber: 64512
- calicoctl apply -f as64512_r1_peer.yaml
- calicoctl apply -f as64513_r2_peer.yaml
驗證bgp路由宣告和pod間通信
使用標簽在各個節點行創建pod, 然后找跨網端的兩臺主機的pod進行ping通信并抓包。創建pod
- mkdir test_pod
- cd test_pod
- vim master.yaml
- apiVersion: v1
- kind: Pod
- metadata:
- name: master
- spec:
- containers:
- - name: master
- image: larioy/nettool:latest
- imagePullPolicy: IfNotPresent
- nodeSelector:
- node: master
- sed s/master/node1/g master.yaml > node1.yaml
- sed s/master/node2/g master.yaml > node2.yaml
- sed s/master/node3/g master.yaml > node3.yaml
- sed s/master/node4/g master.yaml > node4.yaml
- ls -l | grep -v grep | grep yaml | awk '{print $9}' | xargs -I {} kubectl apply -f {}
看看創建出來的pod的分布情況
- [root@k8s-master ~]# kubectl get pod -o wide
- NAME READY STATUS RESTARTS AGE IP NODE
- master 1/1 Running 0 4h17m 10.244.235.192 k8s-master
- node1 1/1 Running 0 4h17m 10.244.36.64 k8s-node1
- node2 1/1 Running 0 4h17m 10.244.169.129 k8s-node2
- node3 1/1 Running 0 4h17m 10.244.107.192 k8s-node3
- node4 1/1 Running 0 4h17m 10.244.122.64 k8s-node4
在bird客戶端看看學習到的bgp路由, 在k8s-master節點上操作, 其自身pod子網段為:10.244.235.192/26
rr路由宣告
在ensp網絡的R1上其應該能學習到所有k8s節點的pod子網對應的子網段路由
R1學習的bgp路由
接著通過跨網段節點的pod間通信抓包驗證, as64512的k8s-master節點的pod master與as64513的k8s-node3的pod node3間通信抓包, 在R2上抓包
- [root@k8s-master ~]# kubectl get pod -o wide | grep -E "node3|master"
- master 1/1 Running 0 29m 10.244.235.192 k8s-master
- node3 1/1 Running 0 29m 10.244.107.192 k8s-node3
- [root@k8s-master ~]# kubectl exec -it master -- ping 10.244.107.192
- PING 10.244.107.192 (10.244.107.192): 56 data bytes
- 64 bytes from 10.244.107.192: seq=0 ttl=60 time=49.314 ms
- 64 bytes from 10.244.107.192: seq=1 ttl=60 time=28.744 ms
- 64 bytes from 10.244.107.192: seq=2 ttl=60 time=48.422 ms
- 64 bytes from 10.244.107.192: seq=3 ttl=60 time=39.144 ms
- 64 bytes from 10.244.107.192: seq=4 ttl=60 time=32.472 ms
R2抓包
如上跨節點k8s集群基于bgp實現了pod間的通信
手動維護bgp
實驗過程中在ENSP部分有關R1/R2的bgp配置都是手工進行維護的, 針對每機架一個AS的部署模式, 怎么監控到一個AS內的主機的上下線, 然后自動的更新RR上client的信息。
bgp架構的思考
在本篇測試中只建立了"每機架作為一個獨立as"架構的測試,該架構中最上層是采用交換機連接, 因此要求所有不同網段中的RR要建立其ebgp關系, 不一定要全互聯但是要保證每個RR都可以從某一個RR學到其他剩余的RR宣告的BGP路由。"每機架作為一個獨立AS"架構的另一種為最上層為路由器, 他們與所有RR都建立EBGP關系,這樣在RR之間就不需要再建立BGP關系了。另外就是考慮路由條目變多后, 哪種架構更合適, 暫未涉及。
問題記錄
- ensp使用云無法找到vmnet8網卡問題, 重裝winPcap,重裝ensp, 路由和同網段主機突然不通了可能是網卡找不到...
- ensp路由設備無效問題:見ensp界面右上角菜單查找幫助手冊, 刪掉頁面上的所有設備重新注冊, 還是失敗考慮重裝ensp...
- workstation在nat模式下無法連接虛機:先查主機上vmnet8網卡的ip地址,在虛擬網絡編輯器中設置nat時, 設置的nat范圍需要和vmnet8的ip地址在同一網段且網關設置為vmnet8的ip
- 新增k8s節點在安裝必備的工具時可以先切換回橋接聯網,然后再切換回nat, 然后在加入k8s集群
- ensp部分網絡配置不通可以直接在路由器R1和R2的兩端接口處抓包, 分析哪段不通, 哪段接到請求但是沒有響應
本文為原創投稿文章,文章原文:https://larioy.gst.monster/2021/09/05/k8s-ji-chong-cni-fang-an-jie-xi/calico/ensp-mo-ni-calico-kua-wang-duan-bgp-wang-luo/
參考資料
[1]The AS Per Rack model: https://docs.projectcalico.org/reference/architecture/design/l3-interconnect-fabric