上一篇【第44篇】Flannel——最简单的K8s网络方案
下一篇【第46篇】K8s DNS——CoreDNS的"黄页"服务
摘要
上一讲我们聊了Flannel——一个"能跑就行"的买菜车。它用VXLAN把Pod包打包封装,丢到物理网络上传输。简单是简单,但封装/解封装是有性能损耗的,带宽一般要打9折。
今天要讲的Calico,完全是另一种思路。它压根不走overlay封装,而是直接把Pod的IP"宣告"到物理网络的路由表里,让Pod IP成为真正可路由的三层地址。用一个词概括:BGP直连,裸奔到底。
Calico的核心魅力有三点:(1)性能几乎等于物理网络,没有隧道开销;(2)NetworkPolicy支持最完整,是零信任网络的标配;(3)可观测性、可调试性极强——因为Pod IP就在路由表里,你用ip route就能看到一切。
不过Calico也有门槛:它要求你对底层网络有一定掌控力(至少得让BGP能通)。如果你在公有云上动不了路由器,那Calico的BGP模式可能玩不转,只能退而用IPIP/VXLAN封装。
读完这篇,你就知道为什么"大型生产集群基本都选Calico"——以及它和Flannel到底差在哪。
一、Calico的架构——三个组件各司其职
1.1 全景图
Calico不像Flannel那样"一个二进制搞定一切",它的组件分得更细:
【Calico 核心组件全景】 ┌──────────────────────────────────────────────────────────┐ │ Control Plane │ │ │ │ ┌────────────────┐ ┌────────────────┐ │ │ │ Typha │ │ kube-controllers│ │ │ │ (大规模优化) │ │ (同步K8s资源) │ │ │ └────────────────┘ └────────────────┘ │ └───────────────────────────────┬────────────────────────────┘ │ 读取/下发配置 ▼ ┌──────────────────────────────────────────────────────────┐ │ 每个 Node 上的 "守护三剑客" │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Felix │ │ BIRD │ │ confd │ │ │ │ (安全执行者) │ │ (BGP路由守护) │ │ (模板渲染) │ │ │ │ │ │ │ │ │ │ │ │ • 写iptables │ │ • 跑BGP协议 │ │ • 监听etcd │ │ │ │ • 写路由表 │ │ • 宣告Pod路由 │ │ • 渲染BIRD配置│ │ │ │ • 执行Network │ │ • 学习邻居路由 │ │ │ │ │ │ Policy │ │ │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ └──────────────┘ │ │ │ │ │ └─────────┼──────────────────┼────────────────────────────────┘ ▼ ▼ ┌──────────────────┐ ┌──────────────────────────────────────┐ │ Linux 路由表 │ │ BGP 邻居 (其他Node的BIRD) │ │ (Pod CIDR路由) │ │ "我这台机器上有这些Pod,听我说!" │ └──────────────────┘ └──────────────────────────────────────┘要点:Calico的核心是Felix和BIRD。Felix负责在每个节点上"落地"——写iptables规则(实现NetworkPolicy)、写路由表;BIRD是一个标准的BGP客户端,负责把"我这台机器上有哪些Pod"这件事通过BGP协议告诉其他节点。confd负责把etcd里的配置渲染成BIRD的配置文件。三者配合,就实现了"Pod IP全网可路由"。
1.2 为什么需要三个组件?
你可能会问:Flannel一个二进制就搞定了,Calico搞这么复杂干嘛?
答案是——因为Calico要做两件Flannel做不了的事:
【Flannel vs Calico 能力对比】 Flannel: • 只管"Pod包怎么到对端" → 一个二进制够用 • 不管网络策略 → 没有iptables规则要维护 • 不做路由宣告 → 不需要BGP Calico: • 管"Pod包怎么到对端" → Felix写路由 + BIRD宣告 • 还要管"哪些Pod能通哪些不能" → Felix写一大堆iptables • 还要管"动态学习路由" → BIRD跑BGP → 事情多了,自然要分工二、BGP——Calico性能神话的源头
2.1 BGP是什么——“路由界的八卦协议”
BGP(Border Gateway Protocol)本来是互联网的核心路由协议,用来在各大运营商之间交换路由信息。你可以把它理解成**“路由界的八卦协议”**——每个路由器都在喊:“我能到这些网段!走我这儿!”
Calico把这套机制搬到了K8s集群里:
【Calico BGP 路由宣告——"Pod IP长腿了自己跑"】 Node1 (10.0.0.1) Node2 (10.0.0.2) ┌────────────────────┐ ┌────────────────────┐ │ Pod A: 10.244.1.5 │ │ Pod C: 10.244.2.5 │ │ Pod B: 10.244.1.6 │ │ Pod D: 10.244.2.6 │ └─────────┬──────────┘ └─────────┬──────────┘ │ │ BIRD 宣告: BIRD 宣告: "10.244.1.0/24 "10.244.2.0/24 经过我 10.0.0.1" 经过我 10.0.0.2" │ │ └────────── BGP 交换 ────────────────┘ │ ▼ Node1 的路由表现在多了: 10.244.2.0/24 via 10.0.0.2 Node2 的路由表现在多了: 10.244.1.0/24 via 10.0.0.1 → Pod A 访问 Pod C 时,包直接走物理路由,没有任何封装!要点:这是Calico和Flannel最本质的区别。Flannel(VXLAN模式)把Pod包塞进UDP包里再发;Calico(BGP模式)直接让Pod IP成为物理网络的可路由地址。前者多了一层封装(约50字节开销+内核处理),后者几乎没有开销。在中大规模集群、高吞吐场景下,这个差距会被放大得很明显。
2.2 BGP vs VXLAN 性能对比
| 维度 | Calico BGP (Direct) | Flannel VXLAN | Calico IPIP |
|---|---|---|---|
| 是否封装 | ❌ 无封装 | ✅ VXLAN封装 | ✅ IPIP封装 |
| 额外字节开销 | 0 | ~50字节 | ~20字节 |
| 走物理路由 | ✅ 是 | ❌ 走隧道 | ❌ 走隧道 |
| 性能 | 极高(≈裸网) | 中等(打折) | 高(略打折) |
| 对底层网络要求 | 高(需BGP可达) | 低(只要IP通) | 低 |
| 跨网段/跨云 | 受限(需支持BGP) | ✅ 任意IP可达 | ✅ 任意IP可达 |
| 调试难度 | 低(路由表可见) | 高(隧道难追) | 中 |
三、Calico的三种模式——什么时候用什么
3.1 IPIP / VXLAN / Direct 怎么选
Calico很贴心,给了你三种封装模式,按底层网络能力挑:
# 查看当前Calico的封装模式kubectl get ippool-oyaml|grep-E"encapsulation|vxlanMode|ipipMode"# 三种模式配置示例# 1. IPIP模式 (跨子网时封装,同子网直连)kubectl edit ippool default-ipv4-ippool# ipipMode: CrossSubnet ← 同二层广播域直连,跨子网才封装# ipipMode: Always ← 永远封装(最稳但最慢)# ipipMode: Never ← 完全不封装(就是纯BGP,要求网络可达)# 2. VXLAN模式 (不需要BGP,纯overlay)# vxlanMode: CrossSubnet / Always# 3. 纯BGP (Direct) —— ipipMode: Never 且 vxlanMode: Never# 性能最好,但要求所有Node之间IP层直接可达(无NAT、无防火墙挡BGP)【Calico 三种模式决策树】 你的底层网络能跑BGP吗?(Node间能直接交换路由?) │ ├─ 能 → 选 Direct (ipipMode: Never) │ ✅ 性能最佳,Pod IP全网可路由 │ ⚠️ 要求:无NAT、防火墙放行BGP(179端口)、二层可达 │ ├─ 不能,但同子网内可达 → 选 IPIP: CrossSubnet │ ✅ 同子网直连(快),跨子网才封装(兜底) │ └─ 完全不可控(公有云/跨VPC) → 选 VXLAN / IPIP: Always ✅ 任意IP可达环境都能用 ❌ 有封装开销,性能略降3.2 一张表总结
| 模式 | 封装 | 性能 | 适用场景 | 关键配置 |
|---|---|---|---|---|
| Direct (BGP) | 无 | ⭐⭐⭐⭐⭐ | 自建机房/可控网络/性能敏感 | ipipMode: Never |
| IPIP CrossSubnet | 部分 | ⭐⭐⭐⭐ | 混合网络(同子网多) | ipipMode: CrossSubnet |
| IPIP Always | 全 | ⭐⭐⭐ | 跨VPC/公有云 | ipipMode: Always |
| VXLAN | 全 | ⭐⭐⭐ | 不要BGP又要overlay | vxlanMode: Always |
四、NetworkPolicy——Calico的"杀手锏"
4.1 为什么Calico的政策最完整
这是Calico和Flannel拉开差距的地方。Flannel根本不支持NetworkPolicy——它只管连通,不管隔离。而Calico从一开始就把网络策略当成核心能力。
# Calico 实现的高性能 NetworkPolicy 示例apiVersion:networking.k8s.io/v1kind:NetworkPolicymetadata:name:deny-all-except-dnsnamespace:prodspec:podSelector:{}# 选中该namespace所有PodpolicyTypes:-Ingressingress:-ports:-port:53# 只允许DNS出站(否则Pod连名字都解析不了)protocol:UDP-port:53protocol:TCP# Calico 还支持更强大的 GlobalNetworkPolicy (集群级)kubectl apply-f-<<EOF apiVersion: crd.projectcalico.org/v1 kind: GlobalNetworkPolicy metadata: name: default-deny-all spec: selector: all() types: - Ingress - Egress EOF# ↑ 这条规则会"默认拒绝一切"——典型零信任起点要点:Calico的NetworkPolicy不是用iptables"暴力实现"的(那会像Flannel+其他插件那样规则爆炸),而是用** Felix + ipset** 高效实现的。ipset把大量IP放进一个集合,iptables只需一条规则就能匹配整个集合,性能比纯iptables链好太多。这也是为什么大规模集群的网络策略首选Calico。
4.2 Felix写规则的过程
【Felix 把 NetworkPolicy 翻译成 iptables】 你写: NetworkPolicy "只允许frontend访问backend:8080" │ ▼ Calico API (etcd/datastore) 通知 Felix │ ▼ Felix 计算: backend Pod IP集合 = {10.244.2.5, 10.244.2.6} frontend Pod IP集合 = {10.244.1.5, 10.244.1.6} │ ▼ Felix 调用 ipset 创建集合 ipset create cali-s:src frontend-ips ipset add cali-s:src 10.244.1.5 ipset add cali-s:src 10.244.1.6 │ ▼ Felix 写一条iptables规则搞定 -A FORWARD -m set --match-set cali-s:src src \ -m set --match-set cali-d:dst dst \ -p tcp --dport 8080 -j ACCEPT五、实战:装一个Calico并验证BGP
5.1 安装(kubeadm场景)
# 下载官方manifestcurlhttps://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml-O# 按需修改 CIDR(要和 kubeadm --pod-network-cidr 一致)# 然后一把梭安装kubectl apply-fcalico.yaml# 等所有 calico-node 变成 Runningkubectl get pods-nkube-system-w|grepcalico5.2 验证BGP邻居建立
# 进到某个 calico-node 容器里看BGP邻居kubectlexec-nkube-system calico-node-xxxxx --\calicoctlnodestatus# 输出示例:# Calico process is running.# IPv4 BGP status# +--------------+-------------------+-------+----------+-------------+# | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |# +--------------+-------------------+-------+----------+-------------+# | 10.0.0.2 | node-to-node mesh | up | 10:23:11 | Established |# | 10.0.0.3 | node-to-node mesh | up | 10:23:12 | Established |# +--------------+-------------------+-------+----------+-------------+# ↑ 看到 up / Established 就说明BGP邻居建立成功了!# 看路由表,确认学到了其他Node的Pod网段iproute show|grepbird# 10.244.2.0/24 via 10.0.0.2 dev eth0 proto bird# 10.244.3.0/24 via 10.0.0.3 dev eth0 proto bird要点:看到
proto bird的路由就是Calico通过BGP学到的。这说明Pod IP已经"上路由"了——从这一刻起,Pod间的通信走的是纯三层路由,没有任何overlay封装。你可以ping一下别的Node上的Pod IP验证连通性。
本篇小结
Calico的思路和Flannel完全相反:它不靠overlay封装,而是用BGP把Pod IP宣告成物理网络的可路由地址,性能几乎等于裸网。它的三大组件Felix(写规则/路由)、BIRD(跑BGP)、confd(渲染配置)配合默契,其中Felix+ipset实现的高效NetworkPolicy是它最硬的"杀手锏"。
选模式时记住决策树:网络可控就Direct(最猛),公有云受限就IPIP/VXLAN(兜底)。后面我们会看到CoreDNS——另一个"看不见但离不开"的基础设施。
上一篇【第44篇】Flannel——最简单的K8s网络方案
下一篇【第46篇】K8s DNS——CoreDNS的"黄页"服务