使用 BGP 通告 Service IP
没有云负载均衡器?Cilium 可以通过 BGP 将 Service IP 直接通告到你的物理网络。
云服务商的 LoadBalancer Service 类型之所以可用,是因为云平台有 API 可以按需创建外部负载均衡器。在裸金属或任何没有这类 API 的环境中,LoadBalancer Service 会一直停留在 Pending 状态,除非有别的组件来承担这个角色。Cilium 的 BGP 控制平面就是一种方案:通过集群节点直接与上游路由器建立 BGP 会话,把 Service 的 IP 路由进你的物理网络。本指南介绍配置它所需的四种资源,以及如何从两端验证 BGP 会话确实已建立。
BGP 何时是合适的工具
从集群节点向上游路由器建立 BGP 对等关系,是一次真正的网络集成。它需要与管理物理(或虚拟)网络的人协调,需要对方路由器上的配置与你在 Kubernetes 一侧的对等配置相匹配,也需要真正熟悉 BGP 的概念,例如自治系统和路由通告。对于需要让 Service IP 能被网络其他部分真正路由到的本地或裸金属集群,这是合适的工具,效果与云上的 LoadBalancer 相同。对于较简单的需求,Cilium 的 L2 announcements 功能(通过本地网段上的 ARP/NDP 通告 Service 的 IP,不涉及路由协议)是更轻量的替代方案,如果你的集群位于单一网段,且不需要在网段或数据中心之间进行三层路由,值得优先考虑。
四种资源
四个 CiliumBGP* 自定义资源协同工作:
CiliumLoadBalancerIPPool定义 Cilium 可以分配给LoadBalancerService 的 IP 地址范围。CiliumBGPAdvertisement定义通过 BGP 通告什么内容,这里是取自该地址池的 Service IP。CiliumBGPPeerConfig定义如何使用 BGP:定时器、graceful restart 行为、地址族。CiliumBGPClusterConfig将它们串联起来:哪些节点参与(通过标签选择器)、它们的本地 AS 号,以及它们连接到哪些上游对等体(通过 IP 和 AS 号)。
定义 IP 池
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
name: apps-pool
spec:
allowFirstLastIPs: "No"
blocks:
- cidr: "10.10.211.0/24"
allowFirstLastIPs: "No" 会把网络地址和广播地址(.0 和 .255)排除在可分配范围之外,这是沿用传统子网分配的常见约定。请把 CIDR 调整为网络团队实际分配给你的范围;从他们的角度看,它必须是真实、可路由的地址空间,而不是你未经协调随意挑选的私有范围。
定义要通告的内容
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPAdvertisement
metadata:
name: bgp-advertisements
labels:
advertise: bgp
spec:
advertisements:
- advertisementType: Service
service:
addresses:
- LoadBalancerIP
selector:
matchExpressions:
- key: io.kubernetes.service.namespace
operator: Exists
这会通告匹配 Service 的 LoadBalancerIP。这里的 labels 字段(advertise: bgp)是下面的 peer config 用来关联两者的依据,而不是 Service 本身上的标签。
定义对等体行为
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPPeerConfig
metadata:
name: bgp-peer-config
spec:
timers:
holdTimeSeconds: 9
keepAliveTimeSeconds: 3
gracefulRestart:
enabled: true
restartTimeSeconds: 15
families:
- afi: ipv4
safi: unicast
advertisements:
matchLabels:
advertise: bgp
这里的 families.advertisements.matchLabels 通过匹配上面定义的通告资源的标签,把这个对等配置与通告资源连接起来。
串联起来:集群配置与节点选择
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPClusterConfig
metadata:
name: bgp-cluster-config
spec:
nodeSelector:
matchLabels:
role: bgp-node
bgpInstances:
- name: instance-1
localASN: 65011
peers:
- name: leaf-switch-1a
peerASN: 65002
peerAddress: "10.10.210.2"
peerConfigRef:
name: bgp-peer-config
- name: leaf-switch-1b
peerASN: 65002
peerAddress: "10.10.210.3"
peerConfigRef:
name: bgp-peer-config
nodeSelector 把 BGP 对等关系限制在有意选定的节点子集上,即带有 role: bgp-node 标签的节点,而不是让集群中每个节点都去和上游路由器建立对等:
kubectl label node worker-4 worker-5 worker-6 role=bgp-node
合理的范围是两到八个对等节点:既足以避免单点故障,又不会要求网络团队为一个可能有几十甚至上百个节点的集群,针对每个节点都配置和维护 BGP 会话。具体多少合适取决于集群的物理布局;如果分布在多个机架或机排,通常应当让每个位置的节点都参与对等,而不是把所有 BGP 会话集中在一处。
应用这四个资源,然后从 Kubernetes 一侧检查:
kubectl apply -f bgp-pool.yaml -f bgp-advertisement.yaml -f bgp-peer-config.yaml -f bgp-cluster-config.yaml
验证会话确实建立
从节点的角度,在带有 BGP 标签的节点上运行的 Cilium Pod 内,使用 Cilium 自带的调试 CLI:
kubectl -n kube-system exec <cilium-pod-on-bgp-node> -- cilium-dbg bgp peers
查找会话状态为 established。其他任何状态(idle、connect、active)都意味着会话尚未真正建立,最常见的原因是两端 AS 号不匹配、对等地址不可达,或者上游路由器根本还没有配置为接受这个对等体;在断定 Kubernetes 一侧的配置有误之前,请先确认网络一侧的对等配置与你这里声明的完全一致。
确认地址确实被通告
创建一个从该池中取地址的 LoadBalancer Service:
kubectl get svc -o wide
它的 EXTERNAL-IP 应该是该池 CIDR 内的地址。在上游路由器上(或其后的任何设备,如防火墙、核心路由器),检查这个地址是否作为通过 BGP 学到的 /32 路由出现,并由对等节点的地址通告。看到这条具体的 /32 出现,并且能够通过它成功访问 Service,才是对 IP 池分配、BGP 通告以及物理网络自身路由三者都正确连接的真正端到端确认,而不仅仅是 Kubernetes 一侧的资源应用时没有报错。
热门指南
-
Cilium 如何使用 eBPF:身份、策略与套接字 当一个 Pod 启动、与另一个 Pod 通信,或某个数据包需要策略判定时,内核中究竟发生了什么 —— 以及它为什么快。 -
为 Cilium 准备集群:先禁用默认 CNI Cilium 会完全取代集群的网络,这意味着操作顺序比大多数插件更重要。 -
使用 Cilium 的 Gateway API 支持暴露服务 GatewayClass、Gateway 和 HTTPRoute —— 基于主机名的路由、路径匹配、URL 重写和 TLS,无需单独的 gateway Pod。 -
编写网络策略:从 L3/L4 到 L7 规则 Kubernetes 起初让每个 Pod 都能访问其他所有 Pod —— CiliumNetworkPolicy 就是用来收窄这一点的,必要时甚至可以细到 HTTP 方法。