共计 10883 个字符,预计需要花费 28 分钟才能阅读完成。
1 前置常识
1.1 Cilium 介绍
Cilium 是一款基于 eBPF 技术的 Kubernetes CNI 插件,Cilium 在其官网上对产品的定位为 “eBPF-based Networking, Observability, Security”,致力于为容器工作负载提供基于 eBPF 的网络、可察看性和安全性的一系列解决方案。Cilium 通过应用 eBPF 技术在 Linux 外部动静插入一些管制逻辑,能够在不批改利用程序代码或容器配置的状况下进行利用和更新,从而实现网络、可察看性和安全性相干的性能。
1.2 Cilium BGP 介绍
BGP(Border Gateway Protocol,边界网关协定)是一种用于 AS(Autonomous System,自治零碎)之间的动静路由协定。BGP 协定提供了丰盛灵便的路由控制策略,晚期次要用于互联网 AS 之间的互联。随着技术的倒退,当初 BGP 协定在数据中心也失去了宽泛的利用,古代数据中心网络通常基于 Spine-Leaf 架构,其中 BGP 可用于流传端点的可达性信息。
Leaf 层由接入交换机组成,这些替换机会对来自服务器的流量进行汇聚并间接连贯到 Spine 或网络外围,Spine 交换机以一种全网格拓扑与所有 Leaf 交换机实现互连。
随着 Kubernetes 在企业中的利用越来越多,这些端点有可能是 Kubernetes Pod,为了让 Kubernetes 集群内部的网络可能通过 BGP 协定动静获取到拜访的 Pod 的路由,显然 Cilium 应该引入对 BGP 协定的反对。
在 Cilium 最后在 1.10 版本中引入了 BGP,通过为利用调配 LoadBalancer 类型的 Service 并联合 MetalLB,从而向 BGP 街坊宣告路由信息。
然而,随着 IPv6 的应用持续增长,很显著 Cilium 须要 BGP IPv6 性能 — 包含 Segment Routing v6 (SRv6)。MetalLB 目前通过 FRR 对 IPv6 的反对无限,并且仍处于试验阶段。Cilium 团队评估了各种选项,并决定转向性能更丰盛的 [GoBGP [1]](https://osrg.github.io/gobgp/)。
在最新的 Cilium 1.12 版本中,启用对 BGP 的反对只须要设置 --enable-bgp-control-plane=true
参数,并且通过一个新的 CRD CiliumBGPPeeringPolicy
实现更加细粒度和可扩大的配置。
- 应用
nodeSelector
参数通过标签抉择,能够将雷同的 BGP 配置利用于多个节点。 - 当
exportPodCIDR
参数设置为 true 时,能够动静地宣告所有 Pod CIDR,无需手动指定须要宣告哪些路由前缀。 neighbors
参数用于设置 BGP 街坊信息,通常是集群内部的网络设备。
apiVersion: "cilium.io/v2alpha1"
kind: CiliumBGPPeeringPolicy
metadata:
name: rack0
spec:
nodeSelector:
matchLabels:
rack: rack0
virtualRouters:
- localASN: 65010
exportPodCIDR: true
neighbors:
- peerAddress: "10.0.0.1/32"
peerASN: 65010
1.3 Kind 介绍
[Kind [2]](https://kind.sigs.k8s.io/)(Kubernetes in Docker)是一种应用 Docker 容器作为 Node 节点,运行本地 Kubernetes 集群的工具。咱们仅须要装置好 Docker,就能够在几分钟内疾速创立一个或多个 Kubernetes 集群。为了不便试验,本文应用 Kind 来搭建 Kubernetes 集群环境。
1.4 Containerlab 介绍
[Containerlab[3]](https://containerlab.dev/) 提供了一种简略、轻量的、基于容器的编排网络试验的计划,反对各种容器化网络操作系统,例如:Cisco,Juniper,Nokia,Arista 等等。Containerlab 能够依据用户定义的配置文件,启动容器并在它们之间创立虚构连贯以构建用户定义网络拓扑。
name: sonic01
topology:
nodes:
srl:
kind: srl
image: ghcr.io/nokia/srlinux
sonic:
kind: sonic-vs
image: docker-sonic-vs:2020-11-12
links:
- endpoints: ["srl:e1-1", "sonic:eth1"]
容器的治理接口会连贯到名为 clab 的 bridge 类型的 Docker 网络中,业务接口通过配置文件中定义的 links 规定相连。这就好比数据中心中网络管理对应的带外治理(out-of-band)和带内治理(in-band)两种管理模式。
Containerlab 还为咱们提供了丰盛的试验案例,能够在 [Lab examples[4]](https://containerlab.dev/lab-…) 中找到。咱们甚至能够通过 Containerlab 创立出一个数据中心级别的网络架构 (参见 [5-stage Clos fabric[5]](https://containerlab.dev/lab-…))
2 前提筹备
请依据相应的操作系统版本,抉择适合的装置形式:
- 装置 Docker: https://docs.docker.com/engin…
- 装置 Containerlab: https://containerlab.dev/inst…
- 装置 Kind: https://kind.sigs.k8s.io/docs…
- 装置 Helm: https://helm.sh/docs/intro/in…
本文所用到的配置文件能够在 https://github.com/cr7258/kub… 中获取。
3 通过 Kind 启动 Kubernetes 集群
筹备一个 Kind 的配置文件,创立一个 4 节点的 Kubernetes 集群。
# cluster.yaml
kind: Cluster
name: clab-bgp-cplane-demo
apiVersion: kind.x-k8s.io/v1alpha4
networking:
disableDefaultCNI: true # 禁用默认 CNI
podSubnet: "10.1.0.0/16" # Pod CIDR
nodes:
- role: control-plane # 节点角色
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-ip: 10.0.1.2 # 节点 IP
node-labels: "rack=rack0" # 节点标签
- role: worker
kubeadmConfigPatches:
- |
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
node-ip: 10.0.2.2
node-labels: "rack=rack0"
- role: worker
kubeadmConfigPatches:
- |
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
node-ip: 10.0.3.2
node-labels: "rack=rack1"
- role: worker
kubeadmConfigPatches:
- |
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
node-ip: 10.0.4.2
node-labels: "rack=rack1"
执行以下命令,通过 Kind 创立 Kubernetes 集群。
kind create cluster --config cluster.yaml
查看集群节点状态,因为以后咱们尚未装置 CNI 插件,因而节点的状态是 NotReady。
kubectl get node
4 启动 Containerlab
定义 Containerlab 的配置文件,创立网络基础设施并连贯 Kind 创立的 Kubernetes 集群:
- router0, tor0, tor1 作为 Kubernetes 集群内部的网络设备,在 exec 参数中设置网络接口信息以及 BGP 配置。router0 与 tor0, tor1 建设 BGP 街坊,tor0 与 server0, server1, router0 建设 BGP 街坊,tor1 与 server2, server3, router0 建设 BGP 街坊。
- 设置
network-mode: container:< 容器名 >
能够让 Containerlab 共享 Containerlab 之外启动的容器的网络命名空间,设置 server0, server1, server2, server3 容器别离连贯到第 3 大节中通过 Kind 创立的 Kubernetes 集群的 4 个 Node 上。
# topo.yaml
name: bgp-cplane-demo
topology:
kinds:
linux:
cmd: bash
nodes:
router0:
kind: linux
image: frrouting/frr:v8.2.2
labels:
app: frr
exec:
- iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
- ip addr add 10.0.0.0/32 dev lo
- ip route add blackhole 10.0.0.0/8
- touch /etc/frr/vtysh.conf
- sed -i -e 's/bgpd=no/bgpd=yes/g' /etc/frr/daemons
- usr/lib/frr/frrinit.sh start
- >-
vtysh -c 'conf t'
-c 'router bgp 65000'
-c 'bgp router-id 10.0.0.0'
-c 'no bgp ebgp-requires-policy'
-c 'neighbor ROUTERS peer-group'
-c 'neighbor ROUTERS remote-as external'
-c 'neighbor ROUTERS default-originate'
-c 'neighbor net0 interface peer-group ROUTERS'
-c 'neighbor net1 interface peer-group ROUTERS'
-c 'address-family ipv4 unicast'
-c 'redistribute connected'
-c 'exit-address-family'
-c '!'
tor0:
kind: linux
image: frrouting/frr:v8.2.2
labels:
app: frr
exec:
- ip link del eth0
- ip addr add 10.0.0.1/32 dev lo
- ip addr add 10.0.1.1/24 dev net1
- ip addr add 10.0.2.1/24 dev net2
- touch /etc/frr/vtysh.conf
- sed -i -e 's/bgpd=no/bgpd=yes/g' /etc/frr/daemons
- /usr/lib/frr/frrinit.sh start
- >-
vtysh -c 'conf t'
-c 'frr defaults datacenter'
-c 'router bgp 65010'
-c 'bgp router-id 10.0.0.1'
-c 'no bgp ebgp-requires-policy'
-c 'neighbor ROUTERS peer-group'
-c 'neighbor ROUTERS remote-as external'
-c 'neighbor SERVERS peer-group'
-c 'neighbor SERVERS remote-as internal'
-c 'neighbor net0 interface peer-group ROUTERS'
-c 'neighbor 10.0.1.2 peer-group SERVERS'
-c 'neighbor 10.0.2.2 peer-group SERVERS'
-c 'address-family ipv4 unicast'
-c 'redistribute connected'
-c 'exit-address-family'
-c '!'
tor1:
kind: linux
image: frrouting/frr:v8.2.2
labels:
app: frr
exec:
- ip link del eth0
- ip addr add 10.0.0.2/32 dev lo
- ip addr add 10.0.3.1/24 dev net1
- ip addr add 10.0.4.1/24 dev net2
- touch /etc/frr/vtysh.conf
- sed -i -e 's/bgpd=no/bgpd=yes/g' /etc/frr/daemons
- /usr/lib/frr/frrinit.sh start
- >-
vtysh -c 'conf t'
-c 'frr defaults datacenter'
-c 'router bgp 65011'
-c 'bgp router-id 10.0.0.2'
-c 'no bgp ebgp-requires-policy'
-c 'neighbor ROUTERS peer-group'
-c 'neighbor ROUTERS remote-as external'
-c 'neighbor SERVERS peer-group'
-c 'neighbor SERVERS remote-as internal'
-c 'neighbor net0 interface peer-group ROUTERS'
-c 'neighbor 10.0.3.2 peer-group SERVERS'
-c 'neighbor 10.0.4.2 peer-group SERVERS'
-c 'address-family ipv4 unicast'
-c 'redistribute connected'
-c 'exit-address-family'
-c '!'
server0:
kind: linux
image: nicolaka/netshoot:latest
network-mode: container:control-plane
exec:
- ip addr add 10.0.1.2/24 dev net0
- ip route replace default via 10.0.1.1
server1:
kind: linux
image: nicolaka/netshoot:latest
network-mode: container:worker
exec:
- ip addr add 10.0.2.2/24 dev net0
- ip route replace default via 10.0.2.1
server2:
kind: linux
image: nicolaka/netshoot:latest
network-mode: container:worker2
exec:
- ip addr add 10.0.3.2/24 dev net0
- ip route replace default via 10.0.3.1
server3:
kind: linux
image: nicolaka/netshoot:latest
network-mode: container:worker3
exec:
- ip addr add 10.0.4.2/24 dev net0
- ip route replace default via 10.0.4.1
links:
- endpoints: ["router0:net0", "tor0:net0"]
- endpoints: ["router0:net1", "tor1:net0"]
- endpoints: ["tor0:net1", "server0:net0"]
- endpoints: ["tor0:net2", "server1:net0"]
- endpoints: ["tor1:net1", "server2:net0"]
- endpoints: ["tor1:net2", "server3:net0"]
执行以下命令,创立 Containerlab 试验环境。
clab deploy -t topo.yaml
创立完的拓扑如下所示,以后只有 tor0, tor1 和 router0 设施之间建设了 BGP 连贯,因为咱们尚未通过 CiliumBGPPeeringPolicy 设置 Kubernetes 集群的 BGP 配置,因而 tor0, tor1 与 Kubernetes Node 的 BGP 连贯还没有建设。
别离执行以下命令,能够查看 tor0, tor1, router0 3 个网络设备以后的 BGP 街坊建设状况。
docker exec -it clab-bgp-cplane-demo-tor0 vtysh -c "show bgp ipv4 summary wide"
docker exec -it clab-bgp-cplane-demo-tor1 vtysh -c "show bgp ipv4 summary wide"
docker exec -it clab-bgp-cplane-demo-router0 vtysh -c "show bgp ipv4 summary wide"
执行以下命令,查看 router0 设施当初学到的 BGP 路由条目。
docker exec -it clab-bgp-cplane-demo-router0 vtysh -c "show bgp ipv4 wide"
以后总共有 8 条路由条目,此时还未学到 Pod 相干的路由。
为了不便用户更直观地理解试验的网络结构,Containerlab 提供 graph
命令生成网络拓扑。
clab graph -t topo.yaml
在浏览器输出 http://< 宿主机 IP>:50080 能够查看 Containerlab 生成的拓扑图。
5 装置 Cilium
本例中应用 Helm 来装置 Cilium,在 values.yaml 配置文件中设置咱们须要调整的 Cilium 配置参数。
# values.yaml
tunnel: disabled
ipam:
mode: kubernetes
ipv4NativeRoutingCIDR: 10.0.0.0/8
# 开启 BGP 性能反对,等同于命令行执行 --enable-bgp-control-plane=true
bgpControlPlane:
enabled: true
k8s:
requireIPv4PodCIDR: true
执行以下命令,装置 Cilium 1.12 版本,开启 BGP 性能反对。
helm repo add cilium https://helm.cilium.io/
helm install -n kube-system cilium cilium/cilium --version v1.12.1 -f values.yaml
期待所有 Cilium Pod 启动结束后,再次查看 Kubernetes Node 状态,能够看到所有 Node 都曾经处于 Ready 状态了。
6 Cilium 节点配置 BGP
接下来别离为 rack0 和 rack1 两个机架上 Kubernetes Node 配置 CiliumBGPPeeringPolicy。rack0 和 rack1 别离对应 Node 的 label,在第 3 大节中 Kind 的配置文件中做过设置。
rack0 的 Node 与 tor0 建设 BGP 街坊,rack1 的 Node 与 tor1 建设 BGP 街坊,并主动宣告 Pod CIDR 给 BGP 街坊。
# cilium-bgp-peering-policies.yaml
apiVersion: "cilium.io/v2alpha1"
kind: CiliumBGPPeeringPolicy
metadata:
name: rack0
spec:
nodeSelector:
matchLabels:
rack: rack0
virtualRouters:
- localASN: 65010
exportPodCIDR: true # 主动宣告 Pod CIDR
neighbors:
- peerAddress: "10.0.0.1/32" # tor0 的 IP 地址
peerASN: 65010
---
apiVersion: "cilium.io/v2alpha1"
kind: CiliumBGPPeeringPolicy
metadata:
name: rack1
spec:
nodeSelector:
matchLabels:
rack: rack1
virtualRouters:
- localASN: 65011
exportPodCIDR: true
neighbors:
- peerAddress: "10.0.0.2/32" # tor1 的 IP 地址
peerASN: 65011
执行以下命令,利用 CiliumBGPPeeringPolicy。
kubectl apply -f cilium-bgp-peering-policies.yaml
创立完的拓扑如下所示,当初 tor0 和 tor1 也曾经和 Kubernetes Node 建设了 BGP 街坊。
别离执行以下命令,能够查看 tor0, tor1, router0 3 个网络设备以后的 BGP 街坊建设状况。
docker exec -it clab-bgp-cplane-demo-tor0 vtysh -c "show bgp ipv4 summary wide"
docker exec -it clab-bgp-cplane-demo-tor1 vtysh -c "show bgp ipv4 summary wide"
docker exec -it clab-bgp-cplane-demo-router0 vtysh -c "show bgp ipv4 summary wide"
执行以下命令,查看 router0 设施当初学到的 BGP 路由条目。
docker exec -it clab-bgp-cplane-demo-router0 vtysh -c "show bgp ipv4 wide"
以后总共有 12 条路由条目,其中多进去的 4 条路由是从 Kubernetes 4 个 Node 学到的 10.1.x.0/24 网段的路由。
7 验证测试
别离在 rack0 和 rack1 所在的节点上创立 1 个 Pod 用于测试网络的连通性。
# nettool.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: nettool-1
name: nettool-1
spec:
containers:
- image: cr7258/nettool:v1
name: nettool-1
nodeSelector:
rack: rack0
---
apiVersion: v1
kind: Pod
metadata:
labels:
run: nettool-2
name: nettool-2
spec:
containers:
- image: cr7258/nettool:v1
name: nettool-2
nodeSelector:
rack: rack1
执行以下命令,创立 2 个测试 Pod。
kubectl apply -f nettool.yaml
查看 Pod 的 IP 地址。
kubectl get pod -o wide
nettool-1 Pod 位于 clab-bgp-cplane-demo-worker(server1, rack0)上,IP 地址是 10.1.2.185;nettool-2 Pod 位于 clab-bgp-cplane-demo-worker3(server3, rack1)上,IP 地址是 10.1.3.56。
执行以下命令,在 nettool-1 Pod 中尝试 ping nettool-2 Pod。
kubectl exec -it nettool-1 -- ping 10.1.3.56
能够看到 nettool-1 Pod 可能失常拜访 nettool-2 Pod。
接下来应用 traceroute 命令察看网络数据包的走向。
kubectl exec -it nettool-1 -- traceroute -n 10.1.3.56
数据包从 nettool-1 Pod 收回,顺次通过了:
- 1.server1 的 cilium_host 接口 :Cilium 网络中 Pod 的默认路由指向了本机的 cilium_host。cilium_host 和 cilium_net 是一对 veth pair 设施。Cilium 通过 hardcode ARP 表,强制将 Pod 流量的下一跳劫持到 veth pair 的主机端。
- 2.tor0 的 net2 接口 。
- 3.router0 的 lo0 接口 :tor0, tor1 和 router0 3 个网络设备间通过本地环回口 lo0 建设 BGP 街坊,这样做能够在有多条物理链路备份的状况下晋升 BGP 街坊的稳健性,不会因为某个物理接口故障时而影响到街坊关系。
- 4.tor1 的 lo0 接口 。
-
5.server3 的 net0 接口 。
8 清理环境
执行以下命令,清理 Containerlab 和 Kind 创立的试验环境。
clab destroy -t topo.yaml
kind delete clusters clab-bgp-cplane-demo
9 参考资料
- [1] GoBGP: https://osrg.github.io/gobgp/
- [2] Kind: https://kind.sigs.k8s.io/
- [3] containerlab: https://containerlab.dev/
- [4] Lab examples: https://containerlab.dev/lab-…
- [5] 5-stage Clos fabric: https://containerlab.dev/lab-…
- [6] BGP WITH CILIUM: https://nicovibert.com/2022/0…
- [7] CONTINAERlab + KinD 秒速部署跨网络 K8s 集群: https://www.bilibili.com/vide…
- [8] Cilium 网络概述: https://www.koenli.com/fcdddb…
- [9] Cilium BGP Control Plane: https://docs.cilium.io/en/sta…
- [10] Cilium 1.12 – Ingress, Multi-Cluster, Service Mesh, External Workloads, and much more: https://isovalent.com/blog/po…
- [11] Cilium 1.10: WireGuard, BGP Support, Egress IP Gateway, New Cilium CLI, XDP Load Balancer, Alibaba Cloud Integration and more: https://cilium.io/blog/2021/0…
- [12] Life of a Packet in Cilium:实地摸索 Pod-to-Service 转发门路及 BPF 解决逻辑: https://arthurchiao.art/blog/…