Cilium IPAM 技术深潜:容器网络控制流与多模式地址管理全景解析
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
导读
本文围绕 Cilium 官方文档 Technical Deep Dive 中的核心控制流图展开,系统梳理 Cilium IP 地址管理(IPAM)从容器创建到 IP 分配完成的完整链路:CNI 插件如何触发分配、agent 如何根据--ipam配置选择后端、各后端(Kubernetes Host Scope、ClusterPool/Multi-Pool、CRD、AWS ENI、Azure、GKE)如何协同 Operator 与自定义资源完成地址分配。读者阅读后既能看懂控制流图中每条分支的走向与依据,也能掌握各 IPAM 模式的启停配置、参数语义与排障手段,形成从"容器要 IP"到"IP 落网卡"的全链路认知。
一、总览:Cilium 的 IP 地址管理(IPAM)是什么
IP 地址管理(IP Address Management,IPAM)负责为 Cilium 所管理的网络端点(容器及其他)分配和管理 IP 地址。根据官方 IPAM 索引文档,Cilium 支持多种 IPAM 模式以适配不同用户场景,其能力差异可用下表概括:
| 特性 | Kubernetes Host Scope | Cluster Scope(默认) | Multi-Pool | CRD-backed | AWS ENI | Azure IPAM | GKE |
|---|---|---|---|---|---|---|---|
| Tunnel 路由 | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Direct 路由 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| CIDR 配置方 | Kubernetes | Cilium | Cilium | 外部 | 外部(AWS) | 外部(Azure) | 外部(GCP) |
| 每集群多 CIDR | ❌ | ✅ | ✅ | N/A | N/A | N/A | N/A |
| 每节点多 CIDR | ❌ | ❌ | ✅ | N/A | N/A | N/A | N/A |
| 动态 CIDR/IP 分配 | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ |
重要约束:除遵循文档化迁移流程外,不要变更现有集群的 IPAM 模式。在运行环境中切换 IPAM 模式可能对存量工作负载造成持续连接中断;最安全的路径是使用新 IPAM 配置安装全新的 Kubernetes 集群。当前唯一可用的在线迁移路径是 cluster-pool → multi-pool,详见 cluster-pool-to-multi-pool.rst。
所有 IPAM 模式的公共底座是一致的:当 Kubernetes 调度器把 Pod 放到某个节点后,kubelet 通过 CRI 调用 CNI 插件,CNI 插件再触发 Cilium agent 的 IPAM 模块从对应后端"取 IP"。模式之间的差异,本质上只在于"节点级地址池(PodCIDR)从哪来、由谁管理、如何增长"。这正是 deep_dive.rst 中控制流图想要表达的核心思想。
二、容器网络控制流:一次完整的 IP 分配之旅
上图(cilium_container_networking_control_flow.png)是理解 Cilium IPAM 的钥匙。它把整个控制流拆解为四个阶段:
2.1 阶段一:容器创建与 CNI 触发
- Kubelet → CRI:kubelet 通过容器运行时接口(CRI,如 containerd)发出
Create container请求; - CRI → Cilium CNI Plugin:CRI 在创建容器命名空间并识别网络后,调用 Cilium CNI 插件;
- CNI Plugin → CNI Agent:CNI 插件执行
cmdAdd()(添加网络)/cmdDel()(删除网络),将控制权交给 Cilium agent 侧的网络配置逻辑; - CNI Agent → IPAM:agent 首先检查 Cilium 配置中的
ipam选项,根据其取值决定走哪条分配分支。
这一步在源码中同样可循:agent 的 IPAM 初始化入口 pkg/ipam/ipam.go 首先在cloudProviders中查找ipam.config.IPAMMode()对应的云厂商后端(ENI/Azure 等),找不到再落入switch分支,依次处理kubernetes、cluster-pool、multi-pool等模式,最终对未知模式返回unknown IPAM backend错误。而模式字符串常量定义在 pkg/ipam/option/option.go:kubernetes、crd、eni、azure、cluster-pool、multi-pool、alibabacloud。
2.2 阶段二:IPAM 模式分支(控制流核心)
控制流图以ipam配置为分水岭,分出三类典型分支:
- 分支 1:ClusterPool / Node CIDR(默认):配置
-ipam=clusterpool(源码中实际取值为cluster-pool,参见 option.go)。默认基于 Kubernetes 节点子网(Host-Subnet),配合-allocate-node-cidrs让 Kubernetes 为节点分配 CIDR;也可以由 Cloud-IPAM Service 拉取 IP 段,再从集群节点 CIDR 中分配容器 IP。 - 分支 2:CRD 模式:配置
-ipam=crd,使用用户(或外部 operator)在 CRD 中定义的 CIDR,agent 从已分配的 IP 池中取 IP 返回给容器。 - 分支 3:ENI 等云模式:配置
-ipam=eni(或azure等),IP 段由云平台定义,Operator 负责把该 IP 段写入CiliumNode的 CRD 字段,agent 再据此分配。
无论走哪条分支,最终都由Cilium CNI Plugin → Container返回Container IP,完成"取 IP"这一步。
2.3 阶段三:网络设备挂接
拿到 IP 后,CNI 插件继续完成数据面的最后一步:
- Attach veth pair / ipvlan:为容器绑定 veth 对或 ipvlan 网卡;
- link up:激活网络设备,使容器网络可用。
2.4 阶段四:IP 状态回写
IPAM 向 Cloud-IPAM Service(或 Kubernetes/CRD 后端)回写Used IP Status Update,把已分配的 IP 标记为使用中,供分配器后续做水印管理(watermark)与回收决策。这一"分配—回写"闭环正是各云模式维持节点级可用 IP 缓冲的关键。
2.5 辅助机制:自动创建 CiliumNode 资源
图中还标注了auto-create-cilium-node-resource = true这一关键开关:当 agent 首次在某节点启动时,自动创建与该节点同名的ciliumnodes.cilium.io自定义资源,作为节点级 IPAM 信息的载体。CRD 模式、ENI 模式、Azure 模式都依赖这一机制,详见下文各模式章节。
三、Kubernetes Host Scope:把分配权交给 Kubernetes
Kubernetes Host Scope 文档 描述的是最贴近 K8s 原生的模式:启用ipam: kubernetes,把地址分配委托给集群内每个节点,IP 从 Kubernetes 关联给节点的PodCIDR范围中分配。
agent 启动时会等待 IPv4/IPv6 的 PodCIDR 通过以下任一路径就绪:
- 通过
v1.Node资源字段:spec.podCIDRs(IPv4 和/或 IPv6)或spec.podCIDR(单栈)。 - 通过
v1.Nodeannotation:
| Annotation | 描述 |
|---|---|
network.cilium.io/ipv4-pod-cidr | IPv4 PodCIDR 范围 |
network.cilium.io/ipv6-pod-cidr | IPv6 PodCIDR 范围 |
network.cilium.io/ipv4-cilium-host | cilium host 接口的 IPv4 地址 |
network.cilium.io/ipv6-cilium-host | cilium host 接口的 IPv6 地址 |
network.cilium.io/ipv4-health-ip | cilium-health 端点的 IPv4 地址 |
network.cilium.io/ipv6-health-ip | cilium-health 端点的 IPv6 地址 |
network.cilium.io/ipv4-Ingress-ip | cilium-ingress 端点的 IPv4 地址 |
network.cilium.io/ipv6-Ingress-ip | cilium-ingress 端点的 IPv6 地址 |
注:annotation 机制主要适用于尚不支持
spec.podCIDRs、但已启用双栈的较老 Kubernetes 版本。
关键前提:必须让kube-controller-manager携带--allocate-node-cidrs标志,Kubernetes 才会分配 PodCIDR 范围。
配置方式
| ConfigMap 选项 | 说明 |
|---|---|
ipam: kubernetes | 启用 Kubernetes IPAM;自动联动:enable-ipv4=true时自动开启k8s-require-ipv4-pod-cidr,enable-ipv6=true时自动开启k8s-require-ipv6-pod-cidr |
k8s-require-ipv4-pod-cidr: true | 让 agent 等待 Kubernetes node 资源暴露 IPv4 PodCIDR |
k8s-require-ipv6-pod-cidr: true | 让 agent 等待 Kubernetes node 资源暴露 IPv6 PodCIDR |
Helm 等价写法:--set ipam.mode=kubernetes、--set k8s.requireIPv4PodCIDR=true、--set k8s.requireIPv6PodCIDR=true(后两者仅与ipam.mode=kubernetes配合生效)。
四、Cluster Scope(默认):由 Operator 管理节点 PodCIDR
Cluster Scope 文档 说明:默认的 cluster-pool 模式为每个节点分配 per-node PodCIDR,并在各节点用 host-scope 分配器分配 IP。它与 Kubernetes Host Scope 的差别在于:不是由 Kubernetes 通过v1.Node分配 per-node PodCIDR,而是由 Cilium operator 通过v2.CiliumNode资源管理。优势是不依赖 Kubernetes 配置下发 per-node PodCIDR,当 Kubernetes 无法下发 PodCIDR 或需要更多控制权时非常有用。
该模式下,agent 启动时会等待v2.CiliumNode对象中按地址族启用的podCIDRs就绪:
| 字段 | 描述 |
|---|---|
spec.ipam.podCIDRs | IPv4 和/或 IPv6 PodCIDR 范围 |
扩容集群池的纪律
- 不要修改
clusterPoolIPv4PodCIDRList中已存在的元素,否则会产生意外行为; - 池耗尽时应追加新元素;最小掩码长度为
/30,建议至少/29。原因:分配器为每个 CIDR 块保留 2 个 IP(网络地址与广播地址); clusterPoolIPv4MaskSize同样不可更改。
排障命令
查看节点级 IPAM 分配错误(Error字段位于status.ipam.operator-status):
kubectl get ciliumnodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.ipam.operator-status}{"\n"}{end}'节点 CIDR 冲突检查:默认 Pod CIDR 为10.0.0.0/8。若节点网络处于同一范围,会丢失到其他节点的连通性——所有出口流量都会被误判为发往本节点上的 Pod。两种解法:显式把clusterPoolIPv4PodCIDRList设置为不冲突的 CIDR;或为节点使用不同的 CIDR。
五、Multi-Pool:按标签与注解从多个池取地址
Multi-Pool 文档 展示了一个更灵活的模型:根据工作负载注解和节点标签,从多个不同 IPAM 池分配 PodCIDR。它是对 cluster-pool 能力的扩展,支持每集群/每节点多 CIDR 与动态 CIDR 分配。
池选择的优先级顺序
- 显式注解指定:在 Pod 或其命名空间上使用
ipam.cilium.io/ip-pool=<pool-name>注解;IPv4/IPv6 可分别用ipam.cilium.io/ipv4-pool=<pool-name>和ipam.cilium.io/ipv6-pool=<pool-name>指定不同池。 - 标签选择器:通过
spec.podSelector和/或spec.namespaceSelector定义哪些 Pod 可从该池取 IP;两者都定义时需同时匹配。此外还可匹配 Cilium 附加的两个合成标签:io.kubernetes.pod.namespace(Pod 命名空间)、io.kubernetes.pod.name(Pod 名称)。- 若分配时池尚不可知(竞态或配置错误),Pod 会回退到 default 池;若希望阻止此行为,可设置
ipam.cilium.io/require-pool-match="true"注解,直到 Pod 匹配上非默认池才放行分配。 - 一个 Pod 在给定 IP 族上必须恰好匹配一个池;匹配多个池会导致分配失败并记录错误,因此务必避免池之间选择器重叠。
- 若分配时池尚不可知(竞态或配置错误),Pod 会回退到 default 池;若希望阻止此行为,可设置
- 兜底 default 池:无显式注解、也不匹配任何选择器时,从名为
default的池分配。
注意:注解只在 Pod 创建时生效,修改运行中 Pod 的ip-pool注解无效。
CiliumNode 扩展与 CiliumPodIPPool CRD
Multi-Pool 模式下CiliumNode资源新增spec.ipam.pools段:
spec.ipam.pools.requested:本节点发起的池请求列表,每项含池名与请求的 IP 数;由节点上的 Cilium agent 写入、Cilium operator 读取并履行。spec.ipam.pools.allocated:分配给本节点的 CIDR 及其来源池;operator 追加新 PodCIDR,agent 移除已释放不再使用的 PodCIDR。
IP 池用集群级CiliumPodIPPool自定义资源管理,每个池包含供各节点分配 PodCIDR 的集群级 CIDR:
apiVersion: cilium.io/v2 kind: CiliumPodIPPool metadata: name: green-pool spec: ipv4: cidrs: - 10.20.0.0/16 - 10.30.0.0/16 maskSize: 24 ipv6: cidrs: - fd00::/104 maskSize: 120运行期约束:池可运行时新增、CIDR 列表可扩展;使用中的 CIDR 不可删除,被 Cilium 节点使用的池不可删除。掩码大小不可变,spec.allowFirstIP、spec.allowLastIP同样不可变。默认情况下每个 CIDR 的首尾地址被保留(不可分配);建池时把allowFirstIP/allowLastIP设为true可放开其中之一;少于 3 个地址的池(/31、/32、/127、/128)不受此限制。
启用与预分配
ipam: mode: multi-pool operator: autoCreateCiliumPodIPPools: default: ipv4: cidrs: - 10.10.0.0/16 maskSize: 24 other: ipv4: cidrs: - 10.20.0.0/16 maskSize: 24ipam.mode=multi-pool启用该模式;ipam.operator.autoCreateCiliumPodIPPools让 operator 启动时自动创建CiliumPodIPPools资源。
预分配参数:ipam-multi-pool-pre-allocation标志携带<pool-name>=<preAllocIPs>映射,控制每个池为本地节点预分配多少 IP(每个地址族相同数量)。默认default=8;未在映射中的池视为 0。agent 计算每池绝对 IP 需求量的公式:
neededIPs = roundUp(inUseIPs + pendingIPs + preAllocIPs, preAllocIPs)其中inUseIPs为在用 IP 数,pendingIPs为已调度未取 IP 的 Pod 数,preAllocIPs为期望缓冲量。
路由通告与 Masquerade 行为
- 从池中分配的 PodCIDR 可经 BGP 控制面通告到网络,也可用
autoDirectNodeRoutesHelm 选项在 L2 网络节点间启用自动路由。 - 当 multi-pool 与 BGP 控制面结合时,可能不希望对这些池的流量做 masquerade(Pod IP 已通过 BGP 通告,回程流量可直达)。若仅靠
--ipvX-native-routing-cidr或ip-masq-agent规则无法区分,可启用--only-masquerade-default-pool关闭所有非默认池的 masquerade,或给CiliumPodIPPool打注解ipam.cilium.io/skip-masquerade="true"。改动只对重新调度后的 Pod 生效。
更新使用中的池(重要运维流程)
更新CiliumPodIPPools的约束:可以追加新 IPv4/IPv6 CIDR,但不能删除或更新使用中的 CIDR。若确需更换使用中 CIDR,官方流程是把集群拆成两个节点组分批迁移(以 kind 双节点集群为例):
- 把池更新为新 CIDR(
10.20.0.0/16替代10.10.0.0/16)。operator 会对仍被节点占用的旧 CIDR 打印警告CIDR from pool still in use by node:
$ kubectl -n kube-system logs deploy/cilium-operator | grep "CIDR from pool still in use by node" ... time=2025-11-01T11:24:13.076246842Z level=warn msg="CIDR from pool still in use by node" module=operator... cidr=10.10.0.0/24 poolName=default node=kind-control-plane- 重启 Cilium operator(
kubectl -n kube-system rollout restart deploy/cilium-operator;也可改 Helm 值后删除旧 CR 并让 operator 重建)。 - cordon 并 drain 节点组 1,其 Pod 会以新池 IP 重调度到节点组 2。
- 删除节点组 1 的
CiliumNodes、重启其上的 agent 并 uncordon。 - 对节点组 2 重复 cordon/drain、删除
CiliumNodes、重启 agent、uncordon。 - (可选)重调度 Pod 使负载均衡。
reservedRanges 平滑迁移:也可把旧 CIDR 保留在cidrs里并用reservedRanges保留整段,Cilium 会保留旧 CIDR 的既有分配、但不再从中分配新 PodCIDR:
apiVersion: cilium.io/v2 kind: CiliumPodIPPool metadata: name: default spec: ipv4: cidrs: - 10.10.0.0/16 - 10.20.0.0/16 maskSize: 24 pool: - cidr: 10.10.0.0/16 reservedRanges: - start: 10.10.0.0 end: 10.10.255.255待节点全部迁走后,再把旧 CIDR 与对应pool条目移除。
按节点的默认池
多数据中心场景下可按节点标签分配特定池(如 DC1 用10.1.0.0/16、DC2 用10.2.0.0/16)。通过CiliumNodeConfig在匹配节点标签的节点上设置ipam-default-ip-pool:
apiVersion: cilium.io/v2 kind: CiliumNodeConfig metadata: name: ip-pool-dc1 namespace: kube-system spec: defaults: ipam-default-ip-pool: dc1-pool nodeSelector: matchLabels: topology.kubernetes.io/zone: dc1限制
- 重叠 CIDR 的池不受支持:Cilium 依靠 IPCache 判定端点安全身份,集群内每个 Pod IP 必须唯一;
- iptables 型 masquerade 必须设置
egressMasqueradeInterfaces(建议直接使用完全受支持的 eBPF masquerade;池不属于同一 native-routing CIDR 时可考虑ip-masq-agent定义多个互斥的非 masquerade CIDR)。
六、CRD-Backed:把 IPAM 交给外部 operator
CRD-backed 文档 说明该模式通过 Kubernetes 自定义资源提供可扩展的 IPAM 接口,允许把 IPAM 委托给外部 operator 或让用户按节点配置。启用后每个 agent 会监听与其所在节点同名的ciliumnodes.cilium.io自定义资源:
- 资源每次更新时,节点分配池会以
spec.ipam.available中列出的所有地址刷新; - 已分配 IP 被移除时,该 IP 可继续使用,但释放后不再参与再分配;
- 池中分配出 IP 后,该 IP 被加入
status.ipam.inuse。
状态更新节流:节点状态更新限制为最多每 15 秒一次,因此多个 Pod 同时调度时 status 段更新可能滞后。
启用与等待行为
ipam: crd(ConfigMap)或--ipam=crd启用。启用后 agent 会等待与节点同名的CiliumNode资源出现且至少含一个可用 IP;开启连通性健康检查时需至少两个可用 IP。等待期间打印:
Waiting for initial IP to become available in '<node-name>' custom resource所需权限(ClusterRole)
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: cilium rules: - apiGroups: - cilium.io resources: - ciliumnodes - ciliumnodes/status verbs: - '*'标准 Cilium 部署工件会自动授予这些权限。
CRD 定义(源码级)
CiliumNode遵循标准 K8s 资源结构,分为spec与status:
type CiliumNode struct { [...] Spec NodeSpec `json:"spec"` Status NodeStatus `json:"status"` }spec侧(可由用户或 IPAM operator 填充):
type NodeSpec struct { [...] IPAM IPAMSpec `json:"ipam,omitempty"` } type IPAMSpec struct { // Pool 是本节点可用于分配的 IP 列表;IP 被使用后仍保留在列表中, // 但会加入 Status.IPAM.InUse Pool AllocationMap `json:"pool,omitempty"` } type AllocationIP struct { // Owner 在 IP 被分配时填写(Pod 名或其它标识);未分配时留空 Owner string `json:"owner,omitempty"` // Resource 同时用于可用与已分配 IP,表示关联的资源,如 AWS ENI 场景下的 ENI ID Resource string `json:"resource,omitempty"` }status侧:
type NodeStatus struct { [...] IPAM IPAMStatus `json:"ipam,omitempty"` } type IPAMStatus struct { // InUse 列出 Spec.IPAM.Pool 中已被分配且正在使用的所有 IP InUse AllocationMap `json:"used,omitempty"` }注意:上述 Go 类型定义与 crd.rst 文档一致,读者可在仓库 api 包中查得对应 CRD 结构。CRD 模式正是控制流图中"分支 2"的实体化:User-defined_cidrs写入spec.ipam.pool,分配后进入status.ipam.used。
七、云厂商模式:AWS ENI 与 Azure
云模式共有的设计哲学(ENI 文档、Azure 文档):只有单个 operator 与云 API 通信以避免大型集群的限流问题,同时用预分配水印(pre-allocation watermark)保证节点随时有可用 IP,Pod 调度时无需即时访问云 API。
7.1 AWS ENI:构建于 multi-pool 之上的分配器
AWS ENI 分配器面向 AWS 云环境,基于Elastic Network Interfaces(ENI)的 IP通过 EC2 API 分配。架构要点:
- 节点首次启动时创建同名
ciliumnodes.cilium.io资源,并通过 EC2 metadata API 获取实例 ID、实例类型与 VPC 信息写入资源; - operator 监听新资源:扫描实例已有 ENI 及关联 IP,逐 ENI 发布到
status.eni.enis;随后持续监控各 agent 在spec.ipam.pools.requested中上报的聚合 IP 需求,按需创建 ENI、分配 IP,以满足预分配水印。
agent 与 operator 分工(这是理解 ENI 模式的关键):
- operator 是唯一与 EC2 API 通信的组件,拥有 ENI 生命周期(创建、挂接、删除)与 IP/前缀分配,并把结果记录到各
CiliumNode的status.eni.enis; - agent 消费
status.eni.enis并转换为 multi-pool 分配器的视角:每个次要 IP 变成 host-prefix CIDR(IPv4 为/32),委派前缀保留原生 CIDR(IPv4/28、IPv6/80),全部发布在default池的spec.ipam.pools.allocated下;agent 在本地从这些 CIDR 分配 Pod IP,不像 CRD 分配器那样逐 IP 写status.ipam.used;agent 在spec.ipam.pools.requested的default池下按ipv4-addrs/ipv6-addrs上报聚合需求,供 operator 决定分配多少 IP/前缀/ENI。
与标准 multi-pool 的差异:标准模式下 operator 依据集群级CiliumPodIPPool写spec.ipam.pools.allocated;而 ENI 模式下agent 是spec.ipam.pools.allocated的唯一写入者,且不涉及CiliumPodIPPool,也不支持ipam.cilium.io/ip-pool注解——所有分配都来自default池。
启用与关键配置
- agent 与 operator 均以
--ipam=eni(或 ConfigMapipam: eni)运行;Helm 安装时还需eni.enabled=true(该标志会配置 ENI 环境所需的全部要求:operator 镜像选择、端点路由、CiliumNode 管理、IPv4 masquerade 默认值)。 - 建议启用
--auto-create-cilium-node-resource(ConfigMapauto-create-cilium-node-resource: "true")以自动创建节点 CR。 - IPv4 受限时可让 operator 携带
--aws-release-excess-ips=true定期检查并尝试释放 ENI 上多余的 IPv4。 - ENI 默认打上集群名标签以便 operator 垃圾回收游离 ENI;集群名取自
cluster-name标志或 EC2 实例上的aws:eks:cluster-name标签,可用--eni-gc-tags覆盖。
ENI 分配参数速查(可经 Helm 或自定义 CNI ConfigMap 配置,CNI 优先于 Helm):
| 参数 | 说明与默认值 |
|---|---|
spec.ipam.min-allocate | 节点首次引导时的最小 IP 数;未指定则无下限 |
spec.ipam.pre-allocate | 始终保持可分配的缓冲 IP 数,默认 8 |
spec.eni.first-interface-index | 用于 Pod IP 分配的首个 ENI 索引,默认 0(用 eth0) |
spec.eni.subnet-ids/spec.eni.subnet-tags | 选择子网的 ID 列表/标签,与availability-zone、vpc-id叠加;subnet-ids与subnet-tags互斥且优先 |
spec.eni.security-groups/spec.eni.security-group-tags | 新 ENI 挂接的安全组 ID 列表/标签过滤;未设置时继承 eth0 的安全组 |
spec.eni.exclude-interface-tags | 排除特定标签接口不参与分配 |
spec.eni.use-primary-address | 是否允许分配 ENI 主地址,默认禁用 |
spec.eni.disable-prefix-delegation | 是否禁用 IPv4 前缀委派 |
spec.eni.delete-on-termination | 实例终止时删除 ENI,默认启用 |
Helm 示例(选择标签为foo=bar的子网、从索引 1 的接口开始、最少分配 10 个 IP):
--set eni.enabled=true \ --set eni.nodeSpec.subnetTags={foo=bar} \ --set eni.nodeSpec.firstInterfaceIndex=1 \ --set ipam.nodeSpec.ipamMinAllocate=10自定义 CNI ConfigMap 示例(子网标签过滤):
apiVersion: v1 kind: ConfigMap metadata: name: cni-configuration namespace: kube-system data: cni-config: |- { "cniVersion":"0.3.1", "name":"cilium", "plugins": [ { "cniVersion":"0.3.1", "type":"cilium-cni", "eni": { "subnet-tags":{ "foo":"true" } } } ] }部署后通过--set cni.customConf=true --set cni.configMap=cni-configuration让 Cilium 使用该配置。
运营细节(源码文档佐证)
- 缓存:operator 缓存账号下所有 ENI/VPC/子网,通过
DescribeNetworkInterfaces、DescribeSubnets、DescribeVpcs、DescribeRouteTables维护;每分钟或每次分配/创建后刷新,基于事件触发时每秒至多一次。 - 可用 IP 发布:缓存刷新后更新所有 CiliumNode,扫描接口索引大于
first-interface-index的 ENI 的可分配 IP 与委派前缀,写入status.eni.enis;变更时通过Update()/UpdateStatus()回写。 - 赤字/富余判定:在
CiliumNode更新时与每分钟全量扫描时检查;--aws-release-excess-ips启用时按间隔扫描识别 IPv4 富余。赤字计算公式:
neededIPs = max(spec.ipam.pre-allocate - (availableIPs - usedIPs), spec.ipam.min-allocate - availableIPs) if spec.ipam.max-allocate > 0 { neededIPs = min(max(spec.ipam.max-allocate - availableIPs, 0), neededIPs) }- 分配:优先复用满足条件(ENI 有未用地址且未超实例类型上限、子网有可用 IP)的 ENI,通过
AssignPrivateIpAddresses分配;无可用 ENI 时创建新 ENI。单次分配量公式:
min(AvailableOnSubnet, min(AvailableOnENI, NeededAddresses + spec.ipam.max-above-watermark + surgeAllocate))- 释放(IPv4):agent 从
spec.ipam.pools.allocated移除已完全空闲的 CIDR,operator 跟踪消失的 CIDR,经--excess-ip-release-delay(默认 180 秒)延迟后用UnassignPrivateIpAddresses(单次要 IP)或UnassignENIPrefixes(委派 /28 前缀)释放。 - ENI 创建:按 VPC ID + 可用区匹配子网,
subnet-ids/subnet-tags进一步收窄,多子网时选可用地址最多者;无显式配置时回退到node-subnet-id→ 同路由表子网 → 匹配 VPC/AZ 的最大子网。创建描述格式为"Cilium-CNI (<EC2 instance ID>)"。 - 节点终止:apiserver 的节点删除事件触发 operator 删除对应
ciliumnodes.cilium.io资源。
operator 需要的一组 EC2 权限(DeleteNetworkInterface、CreateNetworkInterface、AttachNetworkInterface、AssignPrivateIpAddresses、ModifyNetworkInterfaceAttribute等;启用 ENI GC 需DescribeTags;释放富余 IP 需UnassignPrivateIpAddresses;启用 IPv6 需AssignIpv6Addresses),完整清单见 eni.rst。
ENI IPv6(beta)
ENI IPAM 支持 IPv6(beta):无论 Cilium 配置如何,ENI 都创建在双栈子网;启用 IPv6 后 operator 按需为 ENI 委派一个/80前缀,agent 从该前缀分配 Pod IPv6。要点:每节点只分配一个前缀且节点删除前不释放;pre-allocate/min-allocate/max-allocate/max-above-watermark及富余计算仅作用于 IPv4,IPv6 是"需要一个前缀就申请一个"的布尔式需求。Helm 启用方式:
--set ipam.mode=eni --set eni.enabled=true --set ipv6.enabled=true节点侧注意事项
ENI 上 IP 与路由由 agent 管理,需禁用NetworkManager/systemd-networkd等系统服务对新挂接接口的自动 DHCP 管理,否则会干扰 Cilium 配置。示例(NetworkManager 排除 eth0 外的 eth* 接口;systemd-networkd 对eth[1-9]*设置Unmanaged=yes)参见 eni.rst。
7.2 Azure IPAM:构建于 CRD-backed 之上的分配器
Azure 文档 说明该分配器面向在 Azure VM/VMSS 上自建(非 AKS 托管)的集群,基于Azure 私有 IP 地址分配。同样遵循"单 operator 访问云 API + 预分配水印"的架构:
- 节点首次启动创建同名
ciliumnodes.cilium.io资源;agent 从 Kubernetesv1.Node的.Spec.ProviderID推导 Azure 实例 ID; - operator 监听新资源,扫描实例现有接口及关联 IP,通过
spec.ipam.available发布,随后持续监控status.ipam.used并按水印补足 IP。
启用与关键配置
--ipam=azure或 ConfigMapipam: azure同时启用 agent 与 operator 的 Azure 分配;建议同样开启--auto-create-cilium-node-resource;operator 建议开启--enable-metrics。- operator 作用域:
--azure-subscription-id(未设置时经 IMDS 探测自身订阅)、--azure-resource-group(必须为集群节点所在资源组,未设置时经 IMDS 探测;worker VM/VMSS 与其他节点不同资源组时必须显式设置)、VNet/子网资源组在运行时由各接口的子网 ID 推导。 - 认证:基于 Azure Identity SDK。
--azure-user-assigned-identity-id为空时走DefaultAzureCredential链(环境变量 → workload identity → 系统托管身份 → Azure CLI);设置时认证为指定用户托管身份,必须传 client ID(UUID)而非完整资源 ID。
Azure 分配参数:spec.ipam.min-allocate(节点引导最小 IP 数,未指定无下限)、spec.ipam.pre-allocate(常驻缓冲 IP 数,默认 8)、spec.azure.interface-name(用于分配的接口名,如 eth0)。
Helm 示例(使用 eth0、最少分配 10 个 IP):
--set azure.enabled=true \ --set azure.nodeSpec.azureInterfaceName=eth0 \ --set ipam.nodeSpec.ipamMinAllocate=10自定义 CNI ConfigMap(azure.interface-name字段)与 ENI 模式同构,部署后同样用cni.customConf=true/cni.configMap=cni-configuration接入。
运营细节与排障
- 缓存:operator 缓存 ScaleSets、Instances、Interfaces、VirtualNetworks、Subnets;每分钟或分配后刷新,事件触发时每秒至多一次。
- 发布:接口扫描出的 IP 全部加入
spec.ipam.available,每个接口记入status.azure.interfaces。 - 赤字/富余:
// deficit spec.ipam.pre-allocate - (len(spec.ipam.available) - len(status.ipam.used)) // excess (len(spec.ipam.available) - len(status.ipam.used)) - (spec.ipam.pre-allocate + spec.ipam.max-above-watermark)- 分配:复用满足条件的接口(有未用地址且未超上限、子网有可用 IP),单次分配量
min(AvailableOnSubnet, min(AvailableOnInterface, NeededAddresses + spec.ipam.max-above-watermark))。 - 静态公网 IP:创建带标签的 Public IP Prefix 后,在 CNI 配置的
ipam.static-ip-tags中指定标签,operator 从首个有容量的匹配 Prefix 分配公网 IP,Prefix ID 存于status.ipam.assigned-static-ip。 - RBAC:所需 Azure 权限按拓扑分三档(公共部分含
Microsoft.Network/networkInterfaces/read、virtualNetworks/read、virtualNetworks/subnets/read、virtualNetworks/subnets/join/action、Microsoft.Compute/virtualMachineScaleSets/read;VMSS 集群追加virtualMachineScaleSets/virtualMachines/read与write;独立 VM 追加networkInterfaces/write;静态公网 IP 追加publicIPPrefixes/read、publicIPPrefixes/join/action、virtualMachines/read),详见 azure.rst。 - 常见排障:
AuthorizationFailed on Microsoft.Network/virtualNetworks/read说明身份对 VNet 资源组无读权限;spec.ipam.available为空且无分配说明--azure-resource-group指错资源组;ManagedIdentityCredential authentication failed说明传了完整资源 ID 而非 client ID。
八、GKE:复用 Kubernetes Host Scope
GKE 文档 说明 Cilium 在 Google GKE 上运行时,直接利用 GCP 原生网络层做地址管理与 IP 转发:GKE 模式本质是 Kubernetes hostscope IPAM 模式,agent 等待 Kubernetes node 资源按启用的地址族填充spec.podCIDR/spec.podCIDRs。启用方式:Helmipam.mode=kubernetes或 ConfigMapipam: kubernetes。
排障两步走:
- 验证节点
podCIDR字段是否有值:
$ kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}' gke-cluster4-default-pool-b195a3f3-k431 10.4.0.0/24 gke-cluster4-default-pool-b195a3f3-zv3p 10.4.1.0/24- 在目标节点上执行
cilium-dbg status,核对 IPAM 所用 CIDR 与节点公告的 PodCIDR 一致,例如:
IPAM: IPv4: 7/255 allocated from 10.4.0.0/24,九、模式选择对照与总结
回到控制流图与各模式文档,可提炼出选择 IPAM 模式的核心判据:
- Kubernetes Host Scope / GKE:希望完全依赖 Kubernetes 或 GCP 下发 PodCIDR,最贴近云原生原生语义,但缺乏 Cilium 侧的多 CIDR 与动态扩展能力;
- ClusterPool(默认):不依赖 Kubernetes 下发 PodCIDR,由 operator 经
CiliumNode管理,是多数场景的稳妥起点;注意扩容纪律(只追加不修改、掩码不可变); - Multi-Pool:需要按工作负载注解/节点标签区分地址域(多数据中心、多租户隔离地址),支持运行时建池与按池预分配;迁移时遵循分组滚动流程或
reservedRanges平滑方案; - CRD-Backed:需要把 IPAM 委托给外部系统或自定义 operator,接口完全通过
CiliumNode的spec.ipam.pool/status.ipam.used暴露; - AWS ENI / Azure:云原生直连模式,单 operator 访问云 API + 预分配水印保证低延迟取 IP,ENI 模式还构建在 multi-pool 分配器之上并仅使用 default 池。
无论哪种模式,控制流都遵循同一条主线:kubelet → CRI → CNI 插件 → agent IPAM → 对应后端取 IP → veth/ipvlan 挂接与 link up → 状态回写。理解这条主线与 deep_dive.rst 中的控制流图,即可在面对任何 IPAM 故障时迅速定位是"取 IP 阶段"还是"挂网卡阶段"出了问题,再依据对应模式文档的排障命令精准处置。
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考