
Cilium Azure IPAM 详解基于 CRD 与 Azure 私有 IP 的集群级地址分配【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/ciliumAzure IPAM 是 Cilium 面向非 AKS 自管理集群运行在 Azure 虚拟机 VM 或虚拟机规模集 VMSS 上提供的 IP 分配方案它基于 Azure 私有 IP 地址进行 Pod 地址管理。本文将从整体架构、配置方式、分配/释放算法、Azure 权限模型、故障排查与指标观测六个维度完整讲解 Cilium 如何在 Azure 云环境中落地 IPAM并结合仓库源码给出底层实现依据帮助读者在自建 Azure 集群中正确启用并运维 Azure IPAM。适用场景与部署形态Azure IPAM 分配器面向在 Azure 云中运行的 Cilium 部署基于 Azure 私有 IP 地址。在 AKS 上运行 Cilium 时官方推荐以下两种方式而非本文所述的 Azure IPAMAzure CNI Powered by CiliumAKS 完全托管 Cilium 的部署与配置集群以--network-dataplane cilium创建IP 分配由 AKS 自身的控制器通过 delegated IPAM 处理。Bring Your Own CNIBYOCNI集群以--network-pluginnone创建由管理员通过 Helm 或 cilium-cli 自行管理 Cilium可使用任意 Cilium IPAM 后端。架构上Azure IPAM 的关键设计是保证只有单个 operator 与 Azure API 通信从而避免大规模集群中的 API 限流问题同时通过预分配水位pre-allocation watermark在节点上维持一定数量的空闲 IP使得新 Pod 调度时无需即时请求 Azure API。架构CRD-backed 分配器Azure IPAM 构建在 CRD-backed 分配器之上其核心交互如下图所示。整体工作流程分为两侧Cilium Agent节点侧每个节点上的 Cilium 首次启动时会创建与节点同名的ciliumnodes.cilium.io自定义资源。Agent 获取 Kubernetesv1.Node资源并提取.Spec.ProviderID字段以此推导出 Azure 实例 ID。Azure 分配参数作为 Agent 配置选项提供并同步写入该自定义资源。Agent 从 CiliumNode 的spec.ipam.available中取用 IP 分配给 Pod并将已用 IP 上报到status.ipam.used。Cilium Operator集群侧Operator 监听新的ciliumnodes.cilium.io自定义资源并自动接管 IPAM 管理。它扫描 Azure 实例上已存在的网卡及其关联 IP通过spec.ipam.available字段将其发布为可用地址随后持续监控status.ipam.used中的已用地址按 IP 预分配水位watermark追加分配更多 IP保证节点上始终有可用地址。ProviderID 前缀与地址上限等常量定义在 pkg/azure/types/types.go 中ProviderPrefix azure://用于识别 k8s ProviderID 代表 Azure 资源InterfaceAddressLimit 256是单张网卡可关联的最大地址数。Azure 规范字段AzureSpec含interface-name会被嵌入v2.CiliumNode自定义资源而AzureStatus.Interfaces则承载节点网卡状态。启用 Azure IPAM启用 Azure IPAM 需要同时在 Agent 与 Operator 上开启以--ipamazure运行 Cilium Agent 和 Operator或在 ConfigMap 中设置ipam: azure。该选项会在节点 Agent 与 Operator 中同时启用 Azure IPAM 分配。大多数场景下建议在 Agent 首次于节点启动时自动创建ciliumnodes.cilium.io自定义资源指定--auto-create-cilium-node-resource选项或在 ConfigMap 中设置auto-create-cilium-node-resource: true。通常也建议在 Operator 上通过--enable-metrics开启指标。Prometheus 与 Grafana 面板的安装方式参见 observability/grafana.rst。在 Helm 部署场景下上述选项由 install/kubernetes/cilium/templates/cilium-configmap.yaml 自动生成当azure.enabled为 true 时模板会设置enable-endpoint-routes: true、auto-create-cilium-node-resource: true、azure-use-primary-address并在配置了azure.nodeSpec.azureInterfaceName时写入azure-interface-name若设置azure.userAssignedIdentityID则会写入azure-user-assigned-identity-id。Operator 的作用域订阅、资源组、身份Operator 通过三段上下文与 Azure 交互每段都可以从 Azure Instance Metadata ServiceIMDS自动探测或通过--azure-*系列 operator 参数 显式指定订阅--azure-subscription-id所有 Azure SDK 客户端都绑定到单一订阅。未设置时Operator 通过 IMDS 探测其所在节点的订阅。对应的 IMDS 路径为instance/compute/subscriptionId见 pkg/azure/metadata/metadata.go。资源组--azure-resource-group用于限定按资源组维度的 API 调用如列出网卡、VMSS 与 Public IP Prefix。该值必须是集群节点所在的资源组。未设置时通过 IMDS 探测节点自身的资源组路径instance/compute/resourceGroupName但仅当 Operator Pod 与集群其余节点处于同一资源组时结果才正确。当 worker VM/VMSS 位于不同资源组时例如自管理集群将控制面与工作节点池拆分到多个资源组必须显式设置该参数。VNet / 子网资源组Operator 在运行时从每张网卡的子网 ID 推导 VNet 与子网所属资源组无对应参数。当 VNet 位于共享网络资源组时Operator 的身份需要在该资源组拥有读权限。这些选项的定义位于 operator/option/config.goazure-subscription-id、azure-resource-group、azure-user-assigned-identity-id、azure-use-primary-address。其中azure-use-primary-address决定是否将网卡的 primary IP 暴露进可分配池在 pkg/azure/ipam/instances.go 中该值被镜像为InstancesManager.usePrimary字段用于在计算网卡可用地址时预留 primary IP 占用的槽位。认证方式Operator 使用 Azure Identity SDK 认证支持两种模式默认凭据链不设置任何参数当--azure-user-assigned-identity-id为空时Operator 调用DefaultAzureCredential依次尝试环境变量、工作负载身份projected token、系统分配托管身份、Azure CLI。这是 AKS 集群配合 Azure AD Workload Identity 的推荐路径。用户分配托管身份--azure-user-assigned-identity-id设置后 Operator 以指定的用户分配托管身份认证。该值必须是身份的client IDUUID而非完整的 Azure 资源 ID/subscriptions/.../userAssignedIdentities/...。client ID 可在 Azure 门户的身份概览页查看或通过az identity show -g resource-group -n name --query clientId -o tsv获取。自定义 Azure IPAM 配置Helm 与 CNI ConfigMap自定义 Azure IPAM 配置可以通过 Helm 或自定义 CNI 配置 ConfigMap 定义。若同一字段同时配置了 Helm 与自定义 CNI自定义 CNI 优先于 Helm 配置。通过 Helm 配置可使用--set或 Helm value 文件指定。下面的示例将 Cilium 配置为使用eth0网卡进行 Pod IP 分配最小分配 IP 数设为 10helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \ --set azure.enabledtrue \ --set azure.nodeSpec.azureInterfaceNameeth0 \ --set ipam.nodeSpec.ipamMinAllocate10完整的可用选项见 install/kubernetes/cilium/values.yaml 中的azure与ipam配置节azure.enabled、azure.nodeSpec.azureInterfaceName、azure.usePrimaryAddress、azure.resourceGroup、azure.subscriptionID、azure.userAssignedIdentityID等以及 Helm 参考文档的azure.nodeSpec与ipam.nodeSpec章节。通过 CNI 配置 ConfigMap创建cni-config.yaml基于以下模板并填写interface-name字段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, azure: { interface-name:eth0 } } ] }部署该 ConfigMapkubectl apply -f cni-config.yaml然后按前述方式部署 Cilium并附加以下 Helm 参数使其使用自定义 CNI 配置--set cni.customConftrue \ --set cni.configMapcni-configurationazure段在 CNI 配置中的承载结构见 plugins/cilium-cni/types/types.goCNI 配置中azureJSON 字段直接映射到azureTypes.AzureSpec其测试用例 types_test.go 验证了azure.interface-name从 CNI 配置读取并解析为AzureSpec{InterfaceName: eth1}的行为。Azure 分配参数以下参数用于控制 IP 分配它们对应 pkg/ipam/types/types.go 中IPAMSpec的字段min-allocate、pre-allocate、max-above-watermark与AzureSpec的interface-name参数说明spec.ipam.min-allocate节点首次启动时必须分配的最少 IP 数定义必须可用的最小地址基数。达到该水位后由 PreAllocate 与 MaxAboveWatermark 逻辑继续分配。未指定时不要求最小 IP 数kubebuilder:validation:Minimum0。spec.ipam.pre-allocate任何时刻必须保持可用的 IP 地址数量即无需 Operator 介入即可立即分配的地址缓冲。未指定时默认值为8。spec.azure.interface-name用于 IP 分配的网卡名称。pre-allocate默认值 8 定义在 pkg/defaults/defaults.goIPAMPreAllocation 8并在 operator/pkg/ipam/nodemanager/node.go 的getPreAllocate()中应用当Spec.IPAM.PreAllocate为 0 时回退到该默认值。同样地pkg/azure/ipam/node.go 的GetMinimumAllocatableIPv4()也返回defaults.IPAMPreAllocation。运维细节缓存、水位与分配算法网卡、子网与虚拟网络缓存Operator 在缓存中维护与 Azure 订阅关联的所有 ScaleSets、实例、网卡、虚拟网络与子网。缓存每分钟更新一次或在完成一次 IP 分配后更新由分配触发的更新最多每秒执行一次。全量同步与单实例增量同步的实现见 pkg/azure/ipam/instances.goResync()执行全量同步先一次性拉取所有网卡再只针对实际使用的子网 ID 做定向查询避免无谓的 Azure API 调用InstanceSync()则对单个实例做增量同步并将 Azure API 的 404 响应视为实例已不存在与临时同步失败区分开。发布可用 IP缓存更新后Operator 会更新所有代表节点的 CiliumNode 自定义资源发布新变为可用的 IP。该过程中会扫描所有网卡上的全部可用 IP所有发现的 IP 加入spec.ipam.available每张网卡也加入status.azure.interfaces。若此次更新导致自定义资源发生变化则通过 Kubernetes API 的Update()和/或UpdateStatus()方法更新资源。状态填充逻辑位于 pkg/azure/ipam/node.go 的PopulateStatusFields()为保证未变化节点的比较结果稳定、跳过重复的状态写入它对网卡与地址按 ID、IP 排序后再写入Status.Azure.Interfaces。IP 赤字与过剩的判定Operator 持续监控所有节点在两种时机检测可用 IP 赤字CiliumNode 自定义资源被更新时以及常规间隔每分钟一次全量扫描所有节点时。赤字计算spec.ipam.pre-allocate - (len(spec.ipam.available) - len(status.ipam.used))过剩计算(len(spec.ipam.available) - len(status.ipam.used)) - (spec.ipam.pre-allocate spec.ipam.max-above-watermark)检测到赤字后节点被加入需要分配 IP 的队列。通过间隔扫描发现赤字时节点的分配顺序按其赤字严重程度排列赤字最大的节点排在分配队列最前需要释放 IP 的节点排在需要分配的节点之后。分配队列按需处理但最多每秒处理一次。IP 分配为存在地址赤字的节点执行分配时Operator 首先查看该节点由 CiliumNode 资源代表已挂载的网卡然后选择满足以下条件的第一张网卡网卡已关联的地址中存在未使用的或网卡关联地址数小于 Azure 允许的单卡最大地址数256网卡关联的子网仍有可分配的 IP。单次分配多少 IP 由以下公式决定min(AvailableOnSubnet, min(AvailableOnInterface, NeededAddresses spec.ipam.max-above-watermark))这意味着单次分配周期分配的 IP 数可能小于满足spec.ipam.pre-allocate所需的量。在 pkg/azure/ipam/node.go 的PrepareIPAllocation()中候选网卡还需要匹配spec.azure.interface-name若指定并通过isAvailableInterface()检查availableOnInterface max(256 - len(iface.Addresses), 0)未启用 primary 地址时上限减一同时通过FirstSubnetWithAvailableAddresses()确认子网有空闲地址。随后AllocateIPs()依据网卡所属是独立 VM 还是 VMSS分别调用AssignPrivateIpAddressesVM或AssignPrivateIpAddressesVMSS完成实际分配。静态公网 IP 分配节点可以从打有标签的 Azure Public IP Prefix 获得静态公网 IP在与节点相同的资源组中创建并标记 Public IP Prefix$ az network public-ip prefix create \ --resource-group $RESOURCE_GROUP \ --name $PREFIX_NAME \ --length 28 \ --tags prefix-tag-keyprefix-tag-value在 CNI 配置中设置ipam.static-ip-tags{ ipam: { static-ip-tags: { prefix-tag-key: prefix-tag-value } } }Operator 会从第一个具有剩余容量且匹配标签的 Prefix 分配公网 IP并将 Prefix ID 存储在 CiliumNode 的status.ipam.assigned-static-ip中。源码层面的实现为 pkg/azure/ipam/node.go 的AllocateStaticIP()同样按 VM 与 VMSS 分支调用AssignPublicIPAddressesVM/AssignPublicIPAddressesVMSS。IP 释放为存在 IP 过剩的节点执行释放时Operator 扫描节点挂载的网卡单卡可释放的 IP 数由以下公式决定min(FreeOnInterface, (TotalFreeIPs - spec.ipam.pre-allocate - spec.ipam.max-above-watermark))从源码结构看Azure 网卡不支持 prefix delegationIsPrefixDelegated()返回 false、ReleaseIPPrefixes()为空操作因此释放逻辑围绕单个 IP 展开。节点终止当节点或实例终止时Kubernetes apiserver 发送节点删除事件Operator 捕获该事件后删除对应的ciliumnodes.cilium.io自定义资源。对应地实例增量同步中 Azure API 返回 404 时会被转换为nodemanager.ErrInstanceNotFound供上层据此清理本地实例缓存pkg/azure/ipam/instances.go。MasqueradingMasquerading 可通过 eBPF ip-masq-agent 或设置--ipv4-native-routing-cidr支持。所需权限Azure RBACOperator 使用的身份托管身份、服务主体或工作负载身份联合需要按拓扑在两个或三个作用域上拥有 Azure RBAC 权限节点资源组授予 VMSS 的读权限以及向节点 NIC 附加 IP 配置所需的写权限。在 VMSS 上是对 VMSS 实例的 VM model 的写操作在独立 VM 上是对网络接口本身的写操作具体见下方Actions拆分。即通过--azure-resource-group传入的资源组Operator 与节点同置时也可从 IMDS 自动探测。VNet / 子网资源组授予 VNet 与子网的读权限以及附加新私有 IP 时使用的subnets/join/action。通常与节点资源组相同也可能是独立的网络资源组。订阅可选仅当希望通过单一角色分配让 VNet 发现跨多个资源组工作时才需要。List调用按 RBAC 过滤因此订阅级 Reader 并非必需将相同 Actions 限定到各相关资源组即可。自定义角色的最小Actions所有部署共用的权限Microsoft.Network/networkInterfaces/read Microsoft.Network/virtualNetworks/read Microsoft.Network/virtualNetworks/subnets/read Microsoft.Network/virtualNetworks/subnets/join/action Microsoft.Compute/virtualMachineScaleSets/readVMSS 集群额外添加Microsoft.Compute/virtualMachineScaleSets/virtualMachines/read Microsoft.Compute/virtualMachineScaleSets/virtualMachines/write独立 VM 集群额外添加Microsoft.Network/networkInterfaces/write使用 Public IP Prefix 的静态公网 IP 分配时额外添加Microsoft.Network/publicIPPrefixes/read Microsoft.Network/publicIPPrefixes/join/action Microsoft.Compute/virtualMachines/read两点重要说明Microsoft.Compute/virtualMachineScaleSets/virtualMachines/write是较宽泛的权限它授权对实例 VM model 的任何 PATCH而不仅是 NIC 变更但对 VMSS 拓扑是必需的在 VMSS 上每实例的 NIC 配置属于实例模型本身Properties.NetworkProfileConfiguration不存在只允许编辑 NIC 块的更窄 RBAC 动作。Operator 仅使用该权限增删已有 NIC 上的 IP 配置不会发起 VMSS 实例生命周期操作。独立 VM 部署没有此问题因为 NIC 是一等资源通过Microsoft.Network/networkInterfaces/write编辑。节点资源组不是AKS 集群的资源组。单个资源组可容纳多个 AKS 集群但每个 AKS 集群会把所有资源归入一个自动托管的次级资源组。故障排查AuthorizationFailedonMicrosoft.Network/virtualNetworks/readOperator 的身份对拥有 VNet 的资源组没有读权限。需要添加限定到 VNet 资源组可能与节点资源组不同的角色分配。spec.ipam.available一直为空且不发生任何分配--azure-resource-group指向了错误的资源组。请核对该值匹配实际包含 VM 或 VMSS 的资源组而不是 Operator 自身所在的资源组也不是 AKS 集群资源组。ManagedIdentityCredential authentication failed--azure-user-assigned-identity-id被设置为完整的资源 ID/subscriptions/.../userAssignedIdentities/name。请改为传入身份的 client IDUUID。指标观测开启 Operator 的--enable-metrics后可通过 IPAM 相关指标观测分配行为。完整指标表见 observability/metrics.rst 的 IPAM 一节这些指标仅在启用 AWS、AlibabaCloud 或 Azure IPAM 插件时全部启用核心指标包括指标标签说明ipam_ip_allocation_opssubnet_idIP 分配操作次数。ipam_ip_release_opssubnet_idIP 释放操作次数。ipam_allocation_duration_secondstype,status,subnet_idIP 或网卡分配延迟。ipam_release_duration_secondstype,status,subnet_idIP 或网卡释放延迟。ipam_nodescategory按类别total、in-deficit、at-capacity统计的节点数。ipam_resync_total—与外部 IPAM API 的同步操作次数。ipam_api_duration_secondsoperation,response_code与外部 IPAM API 交互的耗时。ipam_api_rate_limit_duration_secondsoperation访问外部 IPAM API 时被限流的耗时。ipam_available_ipstarget_node节点上可用 IP 数已考虑插件特定的 NIC/地址上限。ipam_used_ipstarget_node节点当前已用 IP 数。ipam_needed_ipstarget_node满足节点分配所需的 IP 数。其中ipam_nodes的in-deficit与at-capacity类别由 operator/pkg/ipam/nodemanager/node_manager.go 在每次节点统计后通过metricsAPI.SetNodes(...)更新可用于快速判断集群中是否存在 IP 分配赤字节点。结合 Grafana 面板参见 observability/grafana.rst可以直观监控各节点的可用/已用 IP 水位、分配与释放延迟以及 Azure API 的限流情况为大规模集群的 IP 容量规划提供依据。【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考