mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
3051 字
8 分钟
Kubernetes CNI 深度解析
2023-11-14

一、CNI 规范概述#

容器网络接口(Container Network Interface,简称 CNI)是 Cloud Native Computing Foundation(CNCF)旗下的一个项目,旨在为容器运行时提供标准化的网络配置接口。CNI 规范定义了一组标准接口,使得容器编排系统(如 Kubernetes)可以与各种网络实现解耦,从而实现网络插件的即插即用。

Kubernetes 的网络模型提出了三个核心要求:所有 Pod 之间无需 NAT 即可直接通信;所有 Node 与所有 Pod 之间无需 NAT 即可直接通信;Pod 看到的自身 IP 地址与其他 Pod 看到的该 Pod 的 IP 地址必须一致。这些要求确保了 Kubernetes 网络的扁平性和透明性,而 CNI 插件正是实现这些要求的关键组件。

CNI 规范的核心是一个简单的 JSON Schema,它定义了网络配置的标准格式。当一个 Pod 被创建时,容器运行时会调用 CNI 插件,传入网络配置信息和操作类型(如 ADD、DEL、CHECK)。CNI 插件负责完成实际的网络安全组、路由表、网桥等配置工作,并返回配置结果。

{
"cniVersion": "1.0.0",
"name": "my-network",
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipam": {
"type": "host-local",
"subnet": "10.244.0.0/16",
"routes": [{ "dst": "0.0.0.0/0" }]
}
}

CNI 插件的工作流程可以概括为以下几个步骤:kubelet 创建 Pod 时,会调用 CRI(Container Runtime Interface)创建 Pod 的网络命名空间;然后 kubelet 以命令行方式调用 CNI 插件二进制文件,传入 ADD 命令和网络配置;CNI 插件为 Pod 分配 IP 地址,并在主机上配置相应的路由规则和 iptables 规则;最后,CNI 插件返回配置结果,kubelet 将网络接口附加到 Pod 的网络命名空间中。

sequenceDiagram participant Kubelet participant CRI as Container Runtime participant CNI as CNI Plugin participant IPAM as IPAM participant NS as Network Namespace Kubelet->>CRI: 创建 Pod sandbox CRI->>NS: 创建网络命名空间 Kubelet->>CNI: 调用 ADD 命令<br/>传入配置 JSON CNI->>IPAM: 请求分配 IP 地址 IPAM-->>CNI: 返回 IP 地址 CNI->>NS: 创建 veth pair CNI->>NS: 配置路由规则 CNI-->>Kubelet: 返回配置结果 Kubelet->>CRI: 启动容器

二、Flannel:基于 VXLAN 的 Overlay 网络#

Flannel 是 Kubernetes 生态中最早的 CNI 插件之一,由 CoreOS 团队开发维护。它的设计理念是简单可靠,通过为每个节点分配一个子网,并维护一张全局的路由表来实现 Pod 跨节点通信。Flannel 支持多种网络后端,其中 VXLAN 是最常用的模式。

VXLAN(Virtual Extensible LAN)是一种网络虚拟化技术,它通过在 UDP 数据包中封装二层以太网帧,实现了在三层网络之上构建虚拟二层网络的能力。Flannel 的 VXLAN 实现创建了一个名为 flannel.1 的 VXLAN 网络设备,所有跨节点的 Pod 流量都通过该设备进行封装和解封装。

在 VXLAN 模式下,Flannel 的工作原理如下:每个节点运行一个 flanneld 进程,该进程负责从 etcd 或 Kubernetes API Server 获取网络配置信息,并为当前节点分配一个子网。当 Pod 需要与另一个节点上的 Pod 通信时,流量首先到达 flannel.1 设备,flanneld 根据目标 IP 地址查询节点间的映射关系,将数据包封装在 VXLAN 格式中发送到目标节点。目标节点的 flannel.1 设备解封装后,将数据包转发给目标 Pod。

graph TB subgraph "Node A" PA["Pod A<br/>10.244.1.5"] CA["cni0"] FA["flannel.1<br/>VXLAN VTEP"] FLA["flanneld"] end subgraph "Node B" PB["Pod B<br/>10.244.2.3"] CB["cni0"] FB["flannel.1<br/>VXLAN VTEP"] FLB["flanneld"] end subgraph "配置存储" ETCD["etcd / API Server"] end PA <--> CA <--> FA PB <--> CB <--> FB FA <-->|"VXLAN 隧道<br/>UDP 8472"| FB FLA <-->|"获取配置"| ETCD FLB <-->|"获取配置"| ETCD FLA -.->|"管理"| FA FLB -.->|"管理"| FB style FA fill:#ffecb3 style FB fill:#ffecb3 style ETCD fill:#f3e5f5
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-flannel-cfg
namespace: kube-flannel
data:
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}

Flannel 的 host-gw 模式是另一种常用的网络后端。在这种模式下,Flannel 不进行任何数据包封装,而是在每个节点上配置静态路由,将目标 Pod 子网的下一跳指向目标节点的 IP 地址。这种模式性能最优,因为它避免了封装开销,但要求所有节点必须在同一个二层网络中。

Flannel 的优势在于其简单性和稳定性。它不依赖复杂的分布式协议,配置简单,易于排错。然而,Flannel 的功能相对有限,不支持 Kubernetes NetworkPolicy,也无法提供网络层面的可观测性。对于只需要基本 Pod 互联互通的场景,Flannel 是一个不错的选择。

三、Calico:基于 BGP 的 Underlay 网络#

Calico 是一个功能丰富的 CNI 插件,它采用纯三层网络架构,通过 BGP(Border Gateway Protocol)协议实现路由分发。与 Flannel 不同,Calico 不使用隧道封装技术,而是直接利用底层网络基础设施进行路由,这使得它能够提供接近原生网络的性能表现。

Calico 的核心组件包括 Felix、Bird 和 confd。Felix 是运行在每个节点上的代理进程,负责配置主机路由、iptables 规则和 ACL。Bird 是 BGP 客户端,负责与其他节点的 Bird 进程交换路由信息。confd 负责监听 Calico 数据存储的变化,并动态生成 Bird 的配置文件。

graph TB subgraph "Node 1" F1["Felix"] B1["Bird<br/>BGP Client"] C1["confd"] RT1["路由表"] IP1["iptables"] end subgraph "Node 2" F2["Felix"] B2["Bird<br/>BGP Client"] C2["confd"] RT2["路由表"] IP2["iptables"] end subgraph "Calico 数据存储" DS["etcd / API Server"] end DS -->|"监听变化"| F1 DS -->|"监听变化"| F2 DS -->|"监听变化"| C1 DS -->|"监听变化"| C2 F1 -->|"配置路由"| RT1 F1 -->|"配置 ACL"| IP1 F2 -->|"配置路由"| RT2 F2 -->|"配置 ACL"| IP2 C1 -->|"生成配置"| B1 C2 -->|"生成配置"| B2 B1 <===>"BGP 路由交换"==> B2 style DS fill:#f3e5f5 style B1 fill:#bbdefb style B2 fill:#bbdefb

在 BGP 模式下,Calico 为每个节点分配一个子网,并通过 BGP 协议将每个节点的路由信息广播到集群中的其他节点。当一个 Pod 需要与另一个节点上的 Pod 通信时,流量通过主机路由表直接发送到目标节点,无需任何封装。这种方式的优点是性能高、延迟低,缺点是要求底层网络支持 BGP 协议。

apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: default-ipv4-ippool
spec:
cidr: 192.168.0.0/16
blockSize: 26
ipipMode: Never
vxlanMode: Never
natOutgoing: true
nodeSelector: all()

当底层网络不支持 BGP 时,Calico 提供了 IPIP 和 VXLAN 两种隧道模式。IPIP 模式将原始 IP 数据包封装在另一个 IP 数据包中,封装开销较小,但功能相对简单。VXLAN 模式则与 Flannel 的 VXLAN 实现类似,功能更丰富但封装开销更大。在生产环境中,推荐优先使用 BGP 模式,其次是 IPIP 模式。

Calico 的一个重要特性是对 Kubernetes NetworkPolicy 的完整支持。NetworkPolicy 允许用户定义 Pod 之间的网络访问策略,实现网络层面的安全隔离。Calico 会将 NetworkPolicy 规则转换为 iptables 规则,在流量进入或离开 Pod 时进行过滤。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432

四、Cilium:基于 eBPF 的高性能网络方案#

Cilium 是新一代 CNI 插件的代表,它利用 Linux 内核的 eBPF(extended Berkeley Packet Filter)技术,实现了高性能的网络、安全和可观测性功能。eBPF 允许用户在内核空间安全地运行沙盒程序,而无需修改内核源码或加载内核模块。

Cilium 的核心设计理念是将网络策略和安全策略下放到数据包处理层面。传统 CNI 插件通常使用 iptables 实现网络策略,而 iptables 的规则匹配是线性的,随着规则数量增加,性能会显著下降。Cilium 使用 eBPF 程序直接在网卡驱动层面处理数据包,通过哈希表实现 O(1) 复杂度的规则查找,即使在大规模集群中也能保持稳定的性能。

graph TB subgraph "数据包处理流程" NIC["网卡"] EBPF["eBPF 程序"] CT["连接跟踪表"] POL["策略映射表"] APP["应用程序"] end subgraph "Cilium 组件" AGENT["Cilium Agent"] CLI["Cilium CLI"] HUBBLE["Hubble<br/>可观测性"] end subgraph "控制平面" API["API Server"] KV["Key-Value Store"] end NIC -->|"接收数据包"| EBPF EBPF -->|"查表 O(1)"| CT EBPF -->|"查表 O(1)"| POL EBPF -->|"转发"| APP API -->|"监听资源"| AGENT KV -->|"存储状态"| AGENT AGENT -->|"加载 eBPF"| EBPF AGENT -->|"收集指标"| HUBBLE style EBPF fill:#ff9800,color:#fff style CT fill:#4caf50,color:#fff style POL fill:#4caf50,color:#fff

Cilium 提供了两种网络模式:Overlay 模式和 Native Routing 模式。在 Overlay 模式下,Cilium 支持 VXLAN 和 Geneve 两种封装协议。Native Routing 模式则要求底层网络支持路由,Cilium 直接使用主机路由表进行转发。在高性能场景中,推荐使用 Native Routing 模式。

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: secure-api-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
egress:
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: production
app: database
toPorts:
- ports:
- port: "5432"
protocol: TCP

Cilium 的可观测性能力是其另一大亮点。通过 eBPF 程序,Cilium 可以在内核层面捕获网络流量信息,生成详细的网络监控数据。Hubble 是 Cilium 的网络可观测性组件,它提供了网络流量的可视化界面,支持 DNS 级别的监控、HTTP 请求追踪和服务依赖关系图谱。这些功能对于故障排查和性能分析非常有价值。

Cilium 还可以完全替代 kube-proxy,实现更高效的 Service 负载均衡。传统 kube-proxy 使用 iptables 或 ipvs 实现 Service,而 Cilium 使用 eBPF 程序直接处理 Service 流量,减少了数据包在内核协议栈中的转发次数,显著提升了性能。

graph LR subgraph "传统 kube-proxy" TRAF1["流量"] --> IPT["iptables"] IPT --> NAT["DNAT"] NAT --> POD1["Pod"] NAT --> POD2["Pod"] end subgraph "Cilium (eBPF)" TRAF2["流量"] --> EBPF["eBPF<br/>O(1) 查找"] EBPF --> POD3["Pod"] EBPF --> POD4["Pod"] end style IPT fill:#ffcdd2 style EBPF fill:#c8e6c9

五、CNI 插件对比#

特性FlannelCalicoCilium
网络模式Overlay (VXLAN/UDP)Underlay (BGP) / Overlay (IPIP/VXLAN)Overlay (VXLAN/Geneve) / Native Routing
NetworkPolicy不支持完整支持完整支持 + 增强策略
性能中等最高
可观测性基础指标Hubble 全面的可观测性
替代 kube-proxy
资源消耗中高
学习曲线简单中等较陡
内核版本要求较高 (≥4.19)
企业支持社区TigeraIsovalent (Cisco)

六、CNI 选型建议#

选择 CNI 插件时,需要综合考虑多种因素,包括网络性能需求、安全策略要求、可观测性需求、运维复杂度和团队技术栈等。

对于小型集群或测试环境,Flannel 是一个稳妥的选择。它的配置简单,资源消耗低,稳定性好。如果你的应用对网络性能没有特殊要求,且不需要网络策略功能,Flannel 能够满足基本需求。在所有节点位于同一个二层网络的场景下,使用 Flannel 的 host-gw 模式可以获得接近原生的网络性能。

对于需要网络策略的生产环境,Calico 是一个成熟可靠的选择。它的 BGP 架构适合大规模集群,支持多种网络后端,可以根据实际网络环境灵活选择。如果你的数据中心已经运行了 BGP 协议,Calico 可以无缝集成。对于需要严格网络隔离的多租户环境,Calico 的 NetworkPolicy 支持和全局网络策略功能非常有用。

对于追求极致性能和可观测性的场景,Cilium 是最佳选择。它的 eBPF 架构能够提供最高的网络性能和最低的延迟。如果你的应用需要详细的网络监控、服务依赖分析和 HTTP 级别的流量追踪,Cilium 的 Hubble 组件能够提供强大的支持。需要注意的是,Cilium 的学习曲线相对较陡,需要团队有一定的技术积累。

在实际生产环境中,还需要考虑 CNI 插件与其他 Kubernetes 组件的兼容性。例如,某些网络插件可能与特定的 Ingress Controller 或 Service Mesh 不兼容。在选型时,建议参考社区的最佳实践,并在测试环境中进行充分的验证。

从运维角度来看,选择一个有活跃社区支持、文档完善的 CNI 插件非常重要。Flannel、Calico 和 Cilium 都是 CNCF 项目,拥有活跃的社区和丰富的文档资源。在企业级生产环境中,还应该考虑厂商支持和商业服务的可用性。

七、CNI 选型决策流程#

以下决策流程图可帮助您根据实际需求选择合适的 CNI 插件:

flowchart TD START([开始选型]) --> Q1{需要网络策略?} Q1 -->|否| Q2{节点在同一二层?} Q2 -->|是| F1[Flannel host-gw] Q2 -->|否| F2[Flannel VXLAN] Q1 -->|是| Q3{需要极致性能<br/>或可观测性?} Q3 -->|是| Q4{内核版本 ≥4.19?} Q4 -->|是| C1[Cilium<br/>推荐用于生产] Q4 -->|否| CA1[Calico BGP/IPIP] Q3 -->|否| Q5{底层网络支持 BGP?} Q5 -->|是| CA2[Calico BGP] Q5 -->|否| CA3[Calico VXLAN/IPIP] F1 --> FINAL([选型完成]) F2 --> FINAL C1 --> FINAL CA1 --> FINAL CA2 --> FINAL CA3 --> FINAL style START fill:#e1f5fe style FINAL fill:#c8e6c9 style C1 fill:#fff9c4 style CA1 fill:#fff9c4 style CA2 fill:#fff9c4 style CA3 fill:#fff9c4 style F1 fill:#f8bbd0 style F2 fill:#f8bbd0

7.1 场景化选型建议#

场景推荐方案理由
开发/测试环境Flannel VXLAN简单易用,资源消耗低
小型生产集群Calico IPIP支持网络策略,运维成熟
大规模集群Calico BGP / Cilium性能好,可扩展性强
多租户环境Calico + NetworkPolicy完善的网络隔离能力
金融/高安全要求CiliumeBPF 级安全 + 审计能力
Service Mesh 场景Cilium原生集成,性能最优
边缘计算/混合云Calico BGP灵活的路由策略

八、参考资料#


参考#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

Kubernetes CNI 深度解析
https://blog.souloss.com/posts/kubernetes/k8s-cni/
作者
Souloss
发布于
2023-11-14
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时