bgplb 管理由外部邊緣路由器承載的 Kubernetes 公網 EIP。上游路由維持聚合前綴;叢集透過 WireGuard 與私有 BGP 接入較細的地址池。MetalLB 分配 Service VIP,bgplb 管理隧道、路由、回程策略與故障切換。
本文中的位址均來自 RFC 5737 文件網段。主機名稱、ASN、Registry 與實際部署位置已匿名化。
1. 需求與驗收條件
| 項目 | 約束 | 驗收條件 |
|---|---|---|
| 地址池粒度 | 邊緣路由器持有聚合前綴,叢集使用 /26、/28 等子網 | 整個子網可由同一叢集分配 |
| 節點耦合 | Gateway 節點可能更換,也可能位於 NAT 後方 | 節點主動建立隧道;無需固定節點公網位址 |
| EIP 分配 | 公網位址交付給 LoadBalancer Service | 支援自動選址與指定地址 |
| 路由收斂 | 同一地址池在任一時間只有一個 Active Gateway | Active 失效後,完整前綴切換至 Standby |
| 封包尺寸 | 底層網路不保證 1500-byte MTU | TCP MSS、PMTUD 與 IPv4 fragmentation 可工作 |
| 回程一致性 | Service 可能把流量轉發至其他節點上的 Pod | 回應封包仍以 EIP 為來源,經原邊緣出口返回 |
| 既有路由 | 外部 Transit BGP 已由邊緣路由器管理 | Controller 不修改外部 BGP Session |
| 安全 | 節點 Agent 需要操作核心網路狀態 | 權限限制於指定節點;私鑰不進入 CRD 與日誌 |
2. 部署環境
| 元件 | 配置 |
|---|---|
| Edge Router | 宣告聚合公網前綴;提供可達的 UDP Endpoint;安裝叢集子網路由 |
| Kubernetes | 多個可替換 Gateway Candidate;允許節點位於 NAT 後方 |
| Service Dataplane | kube-proxy / IPVS,externalTrafficPolicy: Cluster |
| Address Allocator | MetalLB IPAddressPool,停用對該池的 L2/BGP Advertisement |
| Tunnel | WireGuard over UDP,節點主動連線,Persistent Keepalive 維持 NAT Mapping |
| Internal Routing | WireGuard 內執行私有 BGP;預設 Hold Time 15 秒 |
| MTU | WireGuard 預設 1280,允許範圍 1280–1420 |
公網聚合前綴只在 Edge Router 對 Transit 宣告。叢集子網由 Active Gateway 經私有 BGP送至 Edge Router。這兩個 BGP 執行個體具有獨立的鄰居、Port 與路由責任。
3. 系統架構
flowchart LR
C["External Client"] --> T["Transit"]
T --> E["Edge Router<br/>Aggregate Route"]
E -->|"WireGuard + Private BGP"| A["Gateway A<br/>Active"]
E -.->|"Established Standby Tunnel"| B["Gateway B<br/>Standby"]
A --> K["kube-proxy / IPVS"]
K --> S["LoadBalancer Service"]
S --> P["Pod Endpoint"]| 元件 | 責任 |
|---|---|
bgplb-controller | Reconcile CRD、選擇 Active Peer、建立 MetalLB Pool、綁定 Service |
| Node Agent | 建立 WireGuard、宣告 Active Pool、配置 Source Policy Routing 與 MSS Clamp |
| Edge Agent | 接受 WireGuard Peer 與私有 BGP Session、安裝或撤回子網路由 |
| MetalLB | 從指定 EIPPool 分配 Service VIP |
| Edge Router | 維持 Transit BGP 聚合宣告,轉送子網流量 |
控制面由四個 Cluster-scoped CRD 組成:
flowchart TB
EG["EdgeGateway"] --> TP["TunnelPeer"]
EP["EIPPool"] --> MP["MetalLB IPAddressPool"]
EP --> RA["RouteAdvertisement"]
TP --> RA
RA --> NA["Node Agent"]
RA --> EA["Edge Agent"]
SV["LoadBalancer Service"] -->|"Pool Annotation"| EP
MP -->|"Allocated VIP"| SVEdgeGateway:隧道、私有 BGP、Node Selector 與 Standby 數量。TunnelPeer:節點公鑰、Tunnel Address、Handshake、BGP 與 Ready 狀態。EIPPool:聚合前綴、可分配子網、Gateway Reference 與 Namespace Policy。RouteAdvertisement:Active Peer、前綴、Next Hop、MTU 與收斂狀態。
4. 封包處理
4.1 入站與回程
sequenceDiagram
participant C as External Client
participant E as Edge Router
participant G as Active Gateway
participant K as kube-proxy / IPVS
participant P as Pod
C->>E: dst = Service EIP
E->>G: WireGuard Packet
G->>K: EIP Packet
K->>P: DNAT to Endpoint
P-->>K: Response
K-->>G: Reverse NAT, src = EIP
G-->>E: Source Policy, table 10077
E-->>C: Transit Response入站封包保持未標記狀態,交由 IPVS 完成 Service DNAT。回應經 Reverse NAT 恢復 EIP 來源位址後,來源前綴規則選擇 bgplb 專用路由表 10077,再送入 WireGuard。
早期版本使用 Connection Mark 決定回程。IPVS 在 DNAT 後可能保留該標記,導致入站封包提前返回隧道。現行實作會清除舊規則,回程判斷只使用 EIP Source Prefix。一般 Pod 與節點流量繼續使用原有 Default Route。
4.2 MTU 與 Fragmentation
資料面同時配置四項措施:
- WireGuard Interface MTU 預設為
1280。 - Edge 與 Node 的 Pool Route 使用
mtu lock 1280。 - 跨隧道的 TCP SYN 套用 MSS Clamp。
- ICMP Fragmentation Needed / Packet Too Big 保持可達。
IPv4 Fragment 在進入 WireGuard 前的單片尺寸只要小於 Tunnel MTU,即可完整傳輸並由 Active Gateway 重組。帶 DF 的大型 UDP 依賴 PMTUD 與應用層重試。IPv6 資料面將在端到端 ICMPv6 Packet Too Big 驗證完成後加入。
4.3 NAT 狀態保存
Node 主動連接 Edge,預設每 25 秒送出 Persistent Keepalive。Agent Reconcile WireGuard 設定時保留核心已學到的 Endpoint 與 Listen Port,避免一次控制面更新清除 NAT Runtime。
5. 地址池與 Service
以下配置建立一個 Cluster-wide /26 EIP Pool。autoAssign: false 要求 Service 明確引用該池;Namespace Policy 限制可使用地址的工作負載範圍。
apiVersion: networking.example.net/v1alpha1
kind: EIPPool
metadata:
name: external-ip-pool-1
spec:
aggregate: 192.0.2.0/24
addresses:
- 192.0.2.0/26
gatewayRef: edge-gateway
autoAssign: false
advertiseWhenEmpty: true
serviceAllocation:
namespaces:
- ingress-system
priority: 10Service 可要求池內的固定 EIP:
apiVersion: v1
kind: Service
metadata:
name: public-ingress
namespace: ingress-system
annotations:
networking.example.net/eip-pool: external-ip-pool-1
metallb.io/loadBalancerIPs: 192.0.2.10
spec:
type: LoadBalancer
loadBalancerClass: metallb.io/metallb
externalTrafficPolicy: Cluster
selector:
app: public-ingress
ports:
- name: https
protocol: TCP
port: 443
targetPort: 8443Controller 檢查地址是否位於指定 Pool、是否已被佔用,以及 Namespace Policy。通過後,MetalLB 寫入 status.loadBalancer.ingress,bgplb 維持整個 Pool Prefix 的路由。
6. 故障切換
stateDiagram-v2
[*] --> ActiveHealthy
ActiveHealthy --> FailureDetected: Heartbeat stale / BGP down
FailureDetected --> OldRouteWithdrawn: Withdraw prefix
OldRouteWithdrawn --> PeerUpdated: Remove old AllowedIPs
PeerUpdated --> StandbyAdvertising: Select ready standby
StandbyAdvertising --> ActiveHealthy: Install new route切換單位是完整的 EIPPool。Service VIP 不重新分配。Standby 已建立 WireGuard Session 並維持 NAT Mapping,接管時只更新 Prefix Ownership 與 BGP Advertisement。
目前版本沒有同步 Conntrack。切換期間既有 TCP Connection 可能 Reset;新連線在路由收斂後恢復。實測故障切換的封包中斷約為 3 秒。
7. 驗證結果
| 測試 | 條件 | 結果 |
|---|---|---|
| TCP 基本連線 | 外部 Client 經 EIP 存取 Service | 150 / 150 |
| UDP 基本連線 | 外部 Client 經 EIP 往返 | 150 / 150 |
| IPv4 Fragment | 4,000-byte UDP,外部 MTU 600 | 10 / 10;觀察 70 個 Fragment;ReasmFails=0 |
| TCP 大型回應 | 8,000-byte Response | 20 / 20 |
| Active / Standby | 移除 Active Gateway Candidate | 約 3 秒恢復 |
| 回程路由 | Pod 位於非 Gateway 節點 | EIP Source 保持,經 Edge 返回 |
| CI | Unit Test + Race、Vet、SAST、gosec、Trivy | 通過 |
上線前檢查項目
EdgeGateway、EIPPool與RouteAdvertisement顯示Ready=True。- Active
TunnelPeer顯示最新 Handshake 與BGP=ESTABLISHED。 - MetalLB 生成的
IPAddressPool與 CRD Prefix 完全一致。 - bgplb Pool 未被任何 MetalLB
L2Advertisement或BGPAdvertisement選中。 - Edge Kernel Route 的 Next Hop 指向 Active WireGuard Peer。
- 從叢集外部執行 TCP、UDP、Fragment、PMTUD 與 Failover 測試。
8. 安全邊界
- Controller 以非 Root、Read-only Root Filesystem、Default Seccomp 執行。
- Node Agent 使用 Host Network 並操作 WireGuard、
iproute2、iptables與sysctl;只排程至帶有專用 Label 的 Gateway Candidate。 - Command Runner 僅允許
ip、iptables、sysctl、wg,不啟動 Shell。 - Node Private Key 存在專用 Namespace 的 Kubernetes Secret;Edge Private Key 保存在 Root-only File。
- CRD、Status、Event 與 Log 只包含 Public Key 或 Secret Reference。
- Controller 只處理明確帶有 Pool Annotation 的 Service。
9. 版本邊界
| 項目 | v0.1 狀態 |
|---|---|
| 公網地址族 | IPv4 |
| Pool Ownership | Single Active / Standby |
| ECMP | 未實作 |
| Conntrack Replication | 未實作 |
| Transit BGP 管理 | 不在 bgplb 範圍內 |
| Service Traffic Policy | Cluster |
| Linux Dataplane | WireGuard、Policy Routing、iptables、IPVS |
這個版本已完成 EIP 分配、NAT-friendly Tunnel、私有 BGP、Source Policy Return、MTU 保護與 Pool-level Failover。後續工作集中在 IPv6 PMTUD、Conntrack Replication、ECMP 與更細的 Dataplane Telemetry。