AIGC标识 [AI生成] 通过bird模拟calico打通容器网络

本文基于 Docker + Bird 2 模拟 Calico 的 BGP 网络原理,使用 3 个容器作为节点,通过 Bird 建立 BGP 全互联(node-to-node mesh),模拟 Calico 的 Pod 网络路由宣告与学习过程。

一、架构概述

拓扑结构:3 个节点(node1 / node2 / node3)组成一个 BGP 全互联 mesh,模拟 Calico 的 node-to-node BGP 模式。每个节点运行 bird2 作为 BGP 路由守护进程,有一个 dummy 接口模拟本节点的 Pod CIDR,通过 bird 将本机 Pod 网段宣告给其他节点,学到的路由直接写入内核路由表,实现 Pod 跨节点互通。

节点网络(共享同一 docker 网络,模拟物理交换机):

节点 节点 IP AS 号 Pod CIDR
node1 10.0.0.11 64512 10.244.1.0/24
node2 10.0.0.12 64512 10.244.2.0/24
node3 10.0.0.13 64512 10.244.3.0/24

二、与 Calico 的对应关系

组件 Calico 真实环境 本模拟
节点 物理机 / 虚拟机 Docker 容器
BGP 守护进程 BIRD / GoBGP Bird 2
Pod 接口 veth pair dummy 接口 pod0
Pod CIDR IPAM 分配 手动分配 /24
本地路由生成 felix 写内核路由 static 协议 + pod0
路由宣告 bird 从内核学路由 → BGP 宣告 bird 直接宣告 static 路由
路由学习 bird 学 BGP 路由 → 写内核表 kernel protocol 同步
BGP 模式 node-to-node mesh iBGP 全互联(AS 64512)

三、跨节点 Pod 通信数据流

Pod A (node1, 10.244.1.10)
    |
    v
node1 内核路由表
    10.244.2.0/24 via 10.0.0.12 dev eth0  ← bird 从 BGP 学到写入内核
    |
    v
node2 (10.0.0.12)
    |
    v
node2 内核路由表
    10.244.2.0/24 dev pod0  ← 本机 Pod CIDR
    |
    v
Pod B (node2, 10.244.2.10)

四、环境搭建

4.1 目录结构

calico-bird-test/
├── Dockerfile             # bird2 + iproute2 + ping 镜像
├── docker-compose.yml     # 3 节点编排
├── init-node.sh           # 节点初始化脚本
├── verify.sh              # 一键验证脚本
├── node1/bird.conf        # node1 BGP 配置
├── node2/bird.conf        # node2 BGP 配置
└── node3/bird.conf        # node3 BGP 配置

4.2 Dockerfile

基于本地已有 redis 镜像(Debian 12),安装 bird2、iproute2 和 iputils-ping:

FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/redis:8.4.0

RUN apt-get update && apt-get install -y bird2 iproute2 iputils-ping \
    && rm -rf /var/lib/apt/lists/*

RUN mkdir -p /etc/bird

EXPOSE 179

CMD ["bird", "-d", "-c", "/etc/bird/bird.conf"]

4.3 docker-compose.yml

3 个节点共享一个 bridge 网络,每个节点挂载自己的 bird.conf 和 init-node.sh:

services:
  node1:
    build: .
    container_name: bird-node1
    hostname: node1
    privileged: true
    volumes:
      - ./node1/bird.conf:/etc/bird/bird.conf
      - ./init-node.sh:/init-node.sh
    networks:
      calico-net:
        ipv4_address: 10.0.0.11
    cap_add:
      - NET_ADMIN
      - SYS_ADMIN
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        sh /init-node.sh 10.244.1.1/24 &&
        bird -d -c /etc/bird/bird.conf
  # node2 / node3 类似,IP 和 Pod CIDR 不同

4.4 init-node.sh 节点初始化

容器启动时执行,做三件事:创建 /run/bird 目录、创建 dummy 接口 pod0 并配置 IP、启用 IP 转发。

#!/bin/sh

POD_CIDR=$1

# 创建 bird 运行时目录(控制 socket 路径)
mkdir -p /run/bird

# 启用 IP 转发
echo 1 > /proc/sys/net/ipv4/ip_forward

# 创建 dummy 接口(模拟 Calico 的 veth + 路由模式)
ip link add pod0 type dummy 2>/dev/null || true
ip link set pod0 up

# 配置 IP
ip addr add $POD_CIDR dev pod0 2>/dev/null || true

4.5 bird.conf 配置说明

以 node1 为例,每个节点的 bird.conf 包含 6 个协议:

协议 作用
kernel Bird 与内核路由表同步。import none 不导入内核路由,export all 把 bird 的路由写入内核
device 扫描网络接口状态(UP/DOWN)
direct 从接口 IP 生成直连路由,用于 BGP 下一跳递归查找
static 静态宣告本机 Pod CIDR(模拟 Calico felix 生成的路由)
bgp node2 与 node2 建立 iBGP 邻居,交换 Pod CIDR 路由
bgp node3 与 node3 建立 iBGP 邻居,交换 Pod CIDR 路由

完整配置(node1/bird.conf):

router id 10.0.0.11;

log syslog all;
log stderr all;

filter accept_pod_cidr {
    if net.len = 24 then accept;
    reject;
}

protocol kernel {
    kernel table 0;
    ipv4 {
        import none;
        export all;
    };
    scan time 2;
}

protocol device {
    scan time 2;
}

protocol direct {
    ipv4;
    interface "eth0", "pod0";
}

protocol static {
    ipv4;
    route 10.244.1.0/24 via "pod0";
}

protocol bgp node2 {
    local as 64512;
    neighbor 10.0.0.12 as 64512;
    ipv4 {
        import filter accept_pod_cidr;
        export filter accept_pod_cidr;
        next hop self;
    };
}

protocol bgp node3 {
    local as 64512;
    neighbor 10.0.0.13 as 64512;
    ipv4 {
        import filter accept_pod_cidr;
        export filter accept_pod_cidr;
        next hop self;
    };
}

五、关键配置踩坑记录

5.1 为什么需要 protocol direct?

BGP 路由的下一跳需要是可达的,bird 才会把路由标记为 unicast(可用)。如果没有 direct 协议,bird 不知道 10.0.0.0/24 是直连网段,无法递归下一跳,BGP 学到的路由会变成 unreachable。

protocol direct 自动从接口配置的 IP 生成直连路由,解决下一跳递归问题。这是踩的第一个坑——配置完 BGP 邻居后路由都是 unreachable,排查了很久才发现是 bird 自己的路由表里没有直连网段。

5.2 为什么用 next hop self?

本机的 Pod CIDR 路由的下一跳是 pod0(接口名),对端收到后无法解析这个接口名。next hop self 让 bird 在宣告路由时把下一跳改成自己的 BGP 源 IP(即节点 IP),对端收到后就能正确转发。

5.3 为什么是 iBGP(同一个 AS)?

Calico 的 node-to-node mesh 默认使用同一个 AS(通常是 64512),所有节点之间建立 iBGP 对等关系,是最简单的全互联模式。生产环境中节点数量多时,通常会引入 Route Reflector(路由反射器)来减少 BGP 连接数。

5.4 Bird 1.x 与 Bird 2.x 语法差异

Bird 1.x Bird 2.x
protocol kernel { import none; export all; } protocol kernel { ipv4 { import none; export all; }; }
protocol static { route ... } protocol static { ipv4; route ... }
protocol bgp { import ...; export ...; } protocol bgp { ipv4 { import ...; export ...; }; }
show protocols bgp show protocols(直接看)
直接指定下一跳接口名 需要 next hop self + direct 协议配合

六、验证结果

6.1 BGP 邻居状态

Name       Proto      Table      State  Since         Info
direct1    Direct     ---        up     00:19:44.376
node2      BGP        ---        up     00:19:48.364  Established
node3      BGP        ---        up     00:19:48.613  Established

两个 BGP 邻居都是 Established 状态,说明 BGP 会话建立成功。

6.2 BGP 路由表

Table master4:
10.244.1.0/24        unicast [direct1] ! (240)  dev pod0
                     unicast [static1] (200)    dev pod0
10.244.2.0/24        unicast [node2] ! (100) [i]
                     via 10.0.0.12 on eth0
10.244.3.0/24        unicast [node3] ! (100) [i]
                     via 10.0.0.13 on eth0
10.0.0.0/24          unicast [direct1] ! (240)  dev eth0

node1 学到了 node2 的 10.244.2.0/24(via 10.0.0.12)和 node3 的 10.244.3.0/24(via 10.0.0.13),路由状态是 unicast(可用)。

6.3 内核路由表

10.0.0.0/24 dev eth0 scope link metric 32
10.244.1.0/24 dev pod0 scope link metric 32
10.244.2.0/24 via 10.0.0.12 dev eth0 metric 32
10.244.3.0/24 via 10.0.0.13 dev eth0 metric 32

4 条 bird 路由全部写入内核路由表(proto bird),包括直连路由和学到的 BGP 路由。

6.4 跨节点 ping 测试

目标 结果
node1 10.244.2.1 (node2 Pod 网关) 2/2 包,0% 丢包
node1 10.244.3.1 (node3 Pod 网关) 2/2 包,0% 丢包
node2 10.244.1.1 (node1 Pod 网关) 2/2 包,0% 丢包

所有跨节点 ping 全部通过,说明 BGP 学习到的路由在内核中生效,流量可以正确转发。

image

image

七、常用操作命令

# 启动环境
cd calico-bird-test
docker compose up -d --build

# 查看 BGP 邻居状态
docker exec bird-node1 birdc show protocols

# 查看 BGP 路由表
docker exec bird-node1 birdc show route

# 查看某条路由的详细属性
docker exec bird-node1 birdc show route 10.244.2.0/24 all

# 查看从某个邻居学到的路由
docker exec bird-node1 birdc show route protocol node2

# 查看内核路由表(bird 学到的)
docker exec bird-node1 ip route show proto bird

# 软重载配置
docker exec bird-node1 birdc configure soft

# 查看节点接口
docker exec bird-node1 ip addr

# 停止环境
docker compose down

八、总结

通过 Docker + Bird 2 模拟了 Calico 的 BGP 网络核心原理:

  1. 每个节点运行 BGP 守护进程(bird),与其他节点建立 iBGP 邻居
  2. 每个节点将本机 Pod CIDR 通过 BGP 宣告给其他节点
  3. 学到的 BGP 路由写入内核路由表,实现跨节点 Pod 通信
  4. 整个过程不需要 overlay 网络(如 VXLAN),性能更好,但依赖底层网络支持 BGP

这个实验清晰地展示了 Calico BGP 模式的工作原理——本质就是在节点之间通过 BGP 交换路由,让每个节点都知道所有 Pod 网段的下一跳,从而实现纯三层的容器网络。

posted on 2026-07-11 09:11  王景迁  阅读(32)  评论(0)    收藏  举报

导航