☰
Calico CNI 插件指南:构建、配置与网络/IPAM 插件工作原理
2026/9/29 21:37:23 网站建设 项目流程
  • 网络
  • 云原生
  • 网络安全

【免费下载链接】calico

Cloud native networking and network security

项目地址:https://gitcode.com/gh_mirrors/cal/calico
点击查看免费下载

本文围绕 Calico 开源仓库中的 cni-plugin 组件,系统讲解其两个核心产物——CNI 网络插件calico与 CNI IPAM 插件calico-ipam——的构建方法、测试方式、配置字段与底层工作流程。读完本文,你将掌握如何本地编译这两个插件、如何理解 CNI 网络配置中每个关键参数的含义,以及 ADD/DEL 调用链在源码层面的完整执行路径,可直接用于接入任何遵循 CNI 规范的容器编排系统(如 Kubernetes、Mesos)。

Calico CNI 插件解决了什么问题

CNI(Container Network Interface)是容器运行时与网络插件之间的标准接口协议。任何遵循该规范(如 0.1.0、0.2.0、0.3.0、0.3.1、0.4.0、1.0.0)的编排器,都可以通过配置一个 CNI 网络配置文件,把容器的网络接入交给第三方插件完成。

Calico 的 cni-plugin 正是这样一组插件,它包含两个部分:

  • 顶层 CNI 网络插件(networking plugin):负责在容器创建时建立 veth 网络设备对、把容器接入主机网络、将 workload endpoint 信息写入数据存储,并关联 Calico 策略;
  • CNI IPAM 插件:基于 Calico IPAM 模块为容器分配/回收 IP 地址。

仓库中把两者打包进同一个二进制:入口 cmd/calico/calico.go 通过argv[0](进程被调用时的名字)来决定分发到哪个子程序——以calico或calico.exe运行时进入网络插件 plugin.Main,以calico-ipam或calico-ipam.exe运行时进入 IPAM 插件 ipamplugin.Main:

switch filename { case "calico", "calico.exe": plugin.Main(buildinfo.Version) case "calico-ipam", "calico-ipam.exe": ipamplugin.Main(buildinfo.Version) default: panic("Unknown binary name: " + filename) }

因此部署时只需安装一份可执行文件,再以两个名字(或符号链接)放置到 CNI 的 bin 目录即可。这一点在 Makefile 中也有印证:$(BIN)/calico-ipam就是calico的符号链接(ln -sf ./calico)。

本地构建插件与运行测试

README 给出的构建入口非常简洁:克隆仓库后直接执行make,即可完成两个 CNI 插件二进制的构建并运行测试。这里的前提是本地环境装有较新版本的 Docker,因为默认构建流程是在容器内完成的。

按需拆分的三个目标如下:

命令作用产物
make构建全部插件二进制并运行单元测试bin/$ARCH/calico、bin/$ARCH/calico-ipam
make build只构建二进制,不跑测试同上
make test只运行测试,不构建无

其中$ARCH为当前目标架构(如amd64)。查看 Makefile 可以看到,测试还会额外依赖 host-local、loopback、portmap、tuning、flannel 等 CNI 辅助插件,它们由仓库中的 third_party/cni-plugins 组件构建后拷贝到bin/$ARCH下,供单元测试使用。

如果不想用容器构建,README 特别注明:需要Go 1.7+ 和 glide作为本地依赖管理工具(这是仓库编写时点的要求,当前仓库根目录的 go.mod 已采用 Go Modules 管理依赖,实际构建以仓库当时的 Makefile 与工具链为准)。

单元测试的三套矩阵

Makefile 将单元测试拆分为三个场景,均通过ut目标统一触发:

  • ut-etcd:以DATASTORE_TYPE=etcdv3运行,使用 CNI 规范版本0.3.1;
  • ut-kdd:以DATASTORE_TYPE=kubernetes(Kubernetes datastore)运行,使用 CNI 规范版本1.0.0,并排除 KubeVirt 相关用例;
  • ut-kubevirt:同样基于 Kubernetes datastore 与 CNI 1.0.0,但只运行 KubeVirt 标签的用例,测试前会先通过install-kubevirt-crds目标把 kubevirt-test-crds.yaml 安装到本地 apiserver。

测试以特权容器方式执行(--privileged --net=host),需要访问 etcd(默认http://127.0.0.1:2379)与本地 Kubernetes apiserver,相关用例见 tests/calico_cni_test.go、tests/calico_cni_ipam_test.go 等文件。Windows 侧的测试则在 win_tests 目录。

关于 Windows 构建

Makefile 中 Linux 版插件被打包进calico/calico镜像,因此该组件只单独产出 Windows 镜像(cni-windows)。Windows 的calico.exe由仓库根目录的 cmd/calico-windows/main.go 构建,它同时携带component cni install子命令树,由 operator 驱动完成插件安装;安装器再将其以calico与calico-ipam两个名字 stage 到宿主机上。

一份真实的 CNI 网络配置示例

CNI 插件通过标准输入接收 JSON 格式的网络配置(netconf)。仓库测试脚本中保留了完整可用的示例 calico-go-with-host-local.json:

{ "cniVersion": "0.3.1", "name": "net1", "type": "calico", "log_level": "INFO", "etcd_authority": "1.2.3.4:2379", "etcd_endpoints": "http://127.0.0.1:2379", "ipam": { "type": "host-local", "subnet": "10.0.0.0/8" } }
  • type必须为calico,运行时按此名在CNI_PATH下查找插件二进制;
  • ipam.type指明 IPAM 插件,生产环境通常为calico-ipam,也可混用官方host-local(此时 Calico 网络插件会在cmdAdd中调用ipam.ExecAdd(conf.IPAM.Type, args.StdinData)执行它,见 pkg/plugin/plugin.go)。

完整的配置字段定义集中在 pkg/types/types.go 的NetConf结构体中,下表梳理了主要字段及含义:

字段说明默认/取值
cniVersionCNI 规范版本缺省时回退为0.2.0;高于1.0.0会被拒绝
name网络名,同时用作 Calico profile 名必填
type插件类型calico
mode/vxlan_mac_prefix/vxlan_vniVXLAN 相关配置可选
ipam.typeIPAM 插件类型calico-ipam或host-local等
ipam.assign_ipv4/ipam.assign_ipv6是否分配 IPv4/IPv6默认分配 1 个 IPv4、0 个 IPv6
ipam.ipv4_pools/ipam.ipv6_pools指定从哪些 IPPool 分配不指定则按默认池
mtu容器网卡 MTU0 时读取 MTU 文件(见require_mtu_file)
num_queuesveth 队列数默认 1
nodename/nodename_file节点名来源默认读取/var/lib/calico/nodename
nodename_file_optional节点名文件缺失时是否继续默认 false(缺失即报错)
ipam_lock_file主机级 IPAM 文件锁路径用于串行化并发分配
datastore_type/etcd_endpoints/etcd_discovery_srv数据存储连接配置(etcdv3)也支持kubernetes
log_level/log_file_path等日志级别与轮转配置默认 INFO
policy.type策略处理器k8s时走 Kubernetes 策略分支
kubernetes.kubeconfig/kubernetes.node_nameKubernetes 客户端配置可选
feature_control.ip_addrs_no_ipam是否启用免 IPAM 的固定 IP非 k8s 运行时启用会报错
device_typeLinux 端虚拟设备类型空/veth为 veth 对;netkit使用内核 6.7+ 的 netkit L2
readiness_gates等待就绪的 HTTP endpoint 列表可选,ADD 前轮询 30 秒
windows_use_single_networkWindows 单 HNS 网络模式限 1 个 IPAM block

其中device_type会在cmdAdd入口处被严格校验,未知值直接返回错误(“unknown device_type in CNI config”),而不是静默回退;netkit则仅在支持的内核上使用,否则回退到 veth。

网络插件 ADD/DEL 的源码级流程

入口 plugin.Main 支持两个辅助命令行参数:

  • -v:打印插件版本后退出;
  • -t:测试数据存储连接——它读取 stdin 中的 netconf、创建 Calico 客户端、查询ClusterInformation的DatastoreReady标志,并在配置了kubernetes.kubeconfig时进一步探测 K8s apiserver 的ServerVersion。该参数被安装器用于“等数据存储就绪后再写入 CNI 配置文件”,避免编排器过早开始调度 Pod 造成启动竞态。

随后通过skel.PluginMainFuncs注册Add/Del/Check回调,声明支持 CNI 规范0.1.0~1.0.0。

ADD 流程

cmdAdd是创建网络的核心,其主干步骤如下:

  1. 解析与校验:反序列化 netconf,检查cniVersion(缺省0.2.0,高于 1.0.0 报错),校验device_type,设置num_queues默认 1,若配置了mtu=0则尝试从 MTU 文件读取;
  2. 就绪检查:确认/var/lib/calico/nodename(或nodename_file指定路径)存在,否则提示检查 calico/node 容器是否挂载了该目录;随后创建客户端并再次确认DatastoreReady;若配置了readiness_gates,则对每个 endpoint 以 5 秒间隔轮询、最长 30 秒;
  3. 工作负载标识解析:通过utils.GetIdentifiers从 CNI_ARGS 中提取节点名、编排器、容器 ID、Pod 名/命名空间(Kubernetes 场景),据此计算 workload endpoint(WEP)名称前缀;
  4. WEP 复用匹配:按前缀列出已有 WorkloadEndpoint,并用NameMatches按节点、编排器、容器 ID、Pod 名匹配(不比较接口名,因为当前每 Pod 仅支持一个接口)。匹配到则复用现有 endpoint 并只追加 profile;未匹配则新建;
  5. 分支处理:
    • Kubernetes 场景(Orchestrator == "k8s")委托给 pkg/k8s/k8s.go 的CmdAddK8s;
    • 其他编排器(如 Mesos)走默认分支:调用 IPAM 插件取地址 → 构造 WorkloadEndpoint 对象并填充Spec.IPNetworks→ 通过dataplane.GetDataplane选择数据面实现(Linux 原生 / Windows HNS / gRPC 后端,见 pkg/dataplane/dataplane.go)→DoNetworking创建 veth(主机侧命名为cali+ 容器 ID 前 11 字符)→ 回填 MAC 与接口名;
  6. 落库与 Profile:CreateOrUpdate写入 endpoint;若policy.type为空,则检查网络名对应的 Profile 是否存在,不存在则创建——Kubernetes 场景下入站规则为Allow全部,非 K8s 场景则只允许来自带同名 tag 的 profile 的流量;
  7. 输出结果:清空网关字段(Calico IPAM 不设置网关),按请求的cniVersion格式把接口、IP 打印到 stdout 返回给运行时。

整个函数对 panic 做了 recover 包装,确保任何异常都会以标准 CNI 错误结构返回而非崩溃。

DEL 流程

cmdDel是对称的清理过程:解析配置 → 确认 nodename 文件与数据存储就绪 → 计算 WEP 名 → Kubernetes 场景委托CmdDelK8s;非 K8s 场景依次执行:调用 IPAM 插件释放地址(DeleteIPAM)→ 删除 WorkloadEndpoint(若不存在则记录日志继续)→CleanUpNamespace清理命名空间内的网络设备。若 IPAM 释放失败,该错误会在最后作为整体操作失败返回,确保调用方感知清理不完整。

IPAM 插件:地址分配与回收

calico-ipam 插件 除了常规的Add/Del外,还提供两个特有参数:

  • -v:打印版本;
  • -upgrade:从 host-local 迁移到 calico-ipam。该模式要求环境变量KUBERNETES_NODE_NAME指定节点名,通过upgrade.Migrate把该节点上 host-local 分配的地址迁入 Calico IPAM 数据存储,失败会每秒重试直到成功。迁移逻辑见 pkg/upgrade/migrate.go,设计背景可参考 pkg/ipamplugin/DESIGN.md。

ADD:自动分配与指定分配

cmdAdd的分配逻辑分两条路径:

  • 指定 IP(ipAddrs注解):解析 CNI_ARGS 中的ip参数,构造AssignIPArgs(含IntendedUse: Workload,交由 IPAM 强制执行 IPPool 的AllowedUses),加锁后调用AssignIP;若地址已被本 Pod 的旧 sandbox 持有,则通过transferFromPriorSandbox执行MoveIPToHandle完成转移;若地址仍在 cooldown 期则拒绝复用。
  • 自动分配:默认num4=1, num6=0,由ipam.assign_ipv4=false/ipam.assign_ipv6=true调整;解析ipv4_pools/ipv6_pools(缺省按节点默认池解析),构造AutoAssignArgs后调用AutoAssign。若 IPv4 分配不足而 IPv6 已分配成功(或反之),会先把成功一侧的地址释放掉再返回错误,避免地址泄漏。

两条路径都通过acquireIPAMLockBestEffort获取主机级文件锁(默认路径常量ipamLockPath,可用ipam_lock_file覆盖)。该锁把同一主机上并发 CNI 调用串行化,虽然AutoAssign本身并发安全,但串行化能显著降低对 apiserver 的瞬时压力(并发请求数被摊平)。

分配成功后,插件按 IP 版本生成 /32 或 /128 掩码的IPConfig,并为每个地址追加一条目标为该地址的路由(Routes),以cniVersion要求的格式输出。

DEL:按 handle 释放

cmdDel依据容器 ID 计算 handle ID(Kubernetes 场景额外兼容 v2.x 时代的namespace.podworkloadID),加锁后调用ReleaseByHandle依次释放两个 handle 下的地址;地址不存在时仅告警并继续,保证幂等。

KubeVirt 虚拟机地址持久化

IPAM 插件还内置了 KubeVirt 支持:对virt-launcher-前缀的 Pod,通过 owner reference 与 VMI 资源校验其身份,并在IPAMConfig.Spec.KubeVirtVMAddressPersistence开启(默认开启)时,改用基于 VM 命名空间/名称的 handle ID(vmipam.CreateVMHandleID),使 VM 重建、热迁移期间 IP 保持不变;迁移目标 Pod 复用源 Pod 分配的地址并写入 AlternateOwner 属性,宿主侧不再重复编程路由。相关逻辑分布在handleVirtLauncherPod与getVMIInfoForPod中,测试见 tests/kubevirt_ipam_test.go。

部署安装器与配置注入

生产环境通常由 calico/node 或 operator 调用安装器把插件和配置部署到宿主机。安装逻辑位于 pkg/install/install.go,通过环境变量控制行为,常用变量如下:

环境变量作用默认值
CNI_NET_DIR主机 CNI 配置目录/etc/cni/net.d
CNI_CONF_NAME要写入的配置文件名自动选择
CNI_NETWORK_CONFIG/CNI_NETWORK_CONFIG_FILE待写入的 netconf 内容或其文件路径空
SKIP_CNI_BINARIES逗号分隔、跳过安装的二进制名空
UPDATE_CNI_BINARIES是否覆盖同名旧二进制true
SLEEP安装完成后是否驻留true
CALICO_API_GROUP使用的 CRD API groupcrd.projectcalico.org/v1

安装器会先把 TLS 资产(/calico-secrets)与二进制 stage 到宿主机,再以-t参数探测数据存储就绪,最后写入网络配置文件并(在SLEEP=true时)保持运行以便监听后续更新。Windows 侧由calico.exe component cni install子命令驱动同一套安装流程。与 K8s 集成的客户端配置可参考 kubeconfig.sample。

许可证说明

Calico 的二进制遵循 Apache v2.0 许可,唯一例外是 Felix 仓库下bpf-gpl目录中的部分 eBPF 程序采用 GPL 许可。此外,插件导入的第三方 Go 包均为 Apache 兼容许可,完整清单见 licenses 目录;基础容器镜像中还包含多种许可的预打包软件,部署前如需合规审计,应从上述两处入手核对。

  • 网络
  • 云原生
  • 网络安全

【免费下载链接】calico

Cloud native networking and network security

项目地址:https://gitcode.com/gh_mirrors/cal/calico
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询