- 网络
- 云原生
- 网络安全
【免费下载链接】calico
Cloud native networking and network security
本文围绕 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结构体中,下表梳理了主要字段及含义:
| 字段 | 说明 | 默认/取值 |
|---|---|---|
cniVersion | CNI 规范版本 | 缺省时回退为0.2.0;高于1.0.0会被拒绝 |
name | 网络名,同时用作 Calico profile 名 | 必填 |
type | 插件类型 | calico |
mode/vxlan_mac_prefix/vxlan_vni | VXLAN 相关配置 | 可选 |
ipam.type | IPAM 插件类型 | calico-ipam或host-local等 |
ipam.assign_ipv4/ipam.assign_ipv6 | 是否分配 IPv4/IPv6 | 默认分配 1 个 IPv4、0 个 IPv6 |
ipam.ipv4_pools/ipam.ipv6_pools | 指定从哪些 IPPool 分配 | 不指定则按默认池 |
mtu | 容器网卡 MTU | 0 时读取 MTU 文件(见require_mtu_file) |
num_queues | veth 队列数 | 默认 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_name | Kubernetes 客户端配置 | 可选 |
feature_control.ip_addrs_no_ipam | 是否启用免 IPAM 的固定 IP | 非 k8s 运行时启用会报错 |
device_type | Linux 端虚拟设备类型 | 空/veth为 veth 对;netkit使用内核 6.7+ 的 netkit L2 |
readiness_gates | 等待就绪的 HTTP endpoint 列表 | 可选,ADD 前轮询 30 秒 |
windows_use_single_network | Windows 单 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是创建网络的核心,其主干步骤如下:
- 解析与校验:反序列化 netconf,检查
cniVersion(缺省0.2.0,高于 1.0.0 报错),校验device_type,设置num_queues默认 1,若配置了mtu=0则尝试从 MTU 文件读取; - 就绪检查:确认
/var/lib/calico/nodename(或nodename_file指定路径)存在,否则提示检查 calico/node 容器是否挂载了该目录;随后创建客户端并再次确认DatastoreReady;若配置了readiness_gates,则对每个 endpoint 以 5 秒间隔轮询、最长 30 秒; - 工作负载标识解析:通过
utils.GetIdentifiers从 CNI_ARGS 中提取节点名、编排器、容器 ID、Pod 名/命名空间(Kubernetes 场景),据此计算 workload endpoint(WEP)名称前缀; - WEP 复用匹配:按前缀列出已有 WorkloadEndpoint,并用
NameMatches按节点、编排器、容器 ID、Pod 名匹配(不比较接口名,因为当前每 Pod 仅支持一个接口)。匹配到则复用现有 endpoint 并只追加 profile;未匹配则新建; - 分支处理:
- 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 与接口名;
- Kubernetes 场景(
- 落库与 Profile:
CreateOrUpdate写入 endpoint;若policy.type为空,则检查网络名对应的 Profile 是否存在,不存在则创建——Kubernetes 场景下入站规则为Allow全部,非 K8s 场景则只允许来自带同名 tag 的 profile 的流量; - 输出结果:清空网关字段(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 group | crd.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
相关推荐
Kubespray网络插件全解析:Calico、Cilium等CNI对比
Kubespray网络插件全解析:Calico、Cilium等CNI对比 本文全面解析Kubespray支持的多种CNI网络插件,包括Calico、Cilium
云原生容器编排DevOps运维HashiCorp Nomad 中的 CNI 插件与桥接网络配置指南
HashiCorp Nomad 中的 CNI 插件与桥接网络配置指南 前言 在现代容器编排系统中,网络配置是一个关键组件。HashiCorp Nomad 通过集
任务调度云原生运维后端kubespray网络隔离:多CNI插件与网络策略配置
kubespray网络隔离:多CNI插件与网络策略配置 概述 在现代Kubernetes集群中,网络隔离是确保应用安全性和稳定性的关键要素。kubespray作
云原生容器编排DevOps运维
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考