news 2026/9/14 17:31:11

Cilium 基于磁盘文件的 Network Policy:static-cnp-path 实现策略即文件与实时热更新

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cilium 基于磁盘文件的 Network Policy:static-cnp-path 实现策略即文件与实时热更新

Cilium 基于磁盘文件的 Network Policy:static-cnp-path 实现策略即文件与实时热更新

【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium

Cilium 的 Network Policy 通常通过 Kubernetes CRD(CiliumNetworkPolicy、CiliumClusterwideNetworkPolicy)下发到集群。而磁盘文件驱动的策略(Disk based Cilium Network Policies)提供了一条不依赖 K8s API Server 的路径:把策略 YAML 文件直接放到节点的文件系统目录中,Cilium agent 会自动读取、解析并加载进策略引擎,同时持续监听该目录,对新增、修改、删除的文件做出实时响应。本文以当前仓库 Documentation/security/policy/disk-based.rst 为核心骨架,结合pkg/policy/directory的源码实现,完整讲解该特性的原理、配置、验证与已知限制。

功能定位:策略 YAML 即文件,绕过 CRD 下发

该特性允许用户将网络策略 YAML 文件直接放置在节点文件系统中,无需通过 Kubernetes CRD 进行定义。通过设置配置字段static-cnp-path,用户可以指定策略加载目录;Cilium agent 会处理该目录下的所有策略 YAML 文件,将其转换为规则并纳入策略引擎。除此之外,Cilium agent 还会持续监控该目录:新出现的策略 YAML 文件会被加载,已存在文件的更新与删除也会同步反映到策略引擎的规则中。

需要明确该特性的边界——它只支持CiliumNetworkPolicyCiliumClusterwideNetworkPolicy两种类型,普通 Kubernetes NetworkPolicy 不在其处理范围内。从源码实现看,目录监视器(Directory policy watcher)读取文件后统一反序列化为cilium_v2.CiliumNetworkPolicy对象(watcher.go),再调用cnp.Parse()转换为规则,因此文件内的kind决定了其作用域:命名空间级(CiliumNetworkPolicy)或集群级(CiliumClusterwideNetworkPolicy)。

配置方式:static-cnp-path 与 Helm 挂载

static-cnp-path是 Cilium agent 的启动参数,定义在 pkg/policy/directory/cell.go 中:

type Config struct { StaticCNPPath string } const ( // StaticCNPPath defines the directory path for static cilium network policy yaml files. staticCNPPath = "static-cnp-path" ) var defaultConfig = Config{ StaticCNPPath: "", // Disabled } func (cfg Config) Flags(flags *pflag.FlagSet) { flags.String(staticCNPPath, defaultConfig.StaticCNPPath, "Directory path to watch and load static cilium network policy yaml files.") }

默认值为空字符串,即默认关闭该功能;一旦设置了非空路径,agent 启动后即开始监视该目录。该参数同样会出现在cilium-agent --help的完整输出中,对应--static-cnp-path选项(参见 Documentation/cmdref/cilium-agent.md):

--static-cnp-path string Directory path to watch and load static cilium network policy yaml files.

Helm values 配置示例

Cilium agent 需要监视的目录必须通过卷挂载(volume mount)从宿主机挂载进来。对于使用 Helm 部署的用户,可以通过extraArgsextraHostPathMounts开启,完整示例如下:

extraArgs: - --static-cnp-path=/policies extraHostPathMounts: - name: static-policies mountPath: /policies hostPath: /policies hostPathType: Directory

参数说明:

字段取值示例含义
extraArgs--static-cnp-path=/policies以 agent 命令行参数形式启用目录监视,/policies为容器内策略目录
extraHostPathMounts[].namestatic-policies挂载项名称,便于在 Pod 中标识
extraHostPathMounts[].mountPath/policies容器内挂载路径,须与--static-cnp-path一致
extraHostPathMounts[].hostPath/policies宿主机上的策略目录路径
extraHostPathMounts[].hostPathTypeDirectory宿主机路径类型,明确声明为目录

extraHostPathMounts是 Cilium Helm Chart 为 agent DaemonSet 提供的标准扩展入口(在 Documentation/helm-values.rst 中亦有收录),因此无需修改 Chart 本身,即可将宿主机目录以 HostPath 形式挂载进 agent 容器。部署完成后,向宿主机/policies目录放置或修改策略 YAML,agent 即会自动感知。

策略文件的要求与目录监视机制

从源码 watcher.go 可以看出,目录监视器对文件名的校验非常明确:

func (p *policyWatcher) isValidCNPFileName(filePath string) bool { if filepath.Ext(filePath) != ".yaml" { return false } if reasons := validation.IsDNS1123Subdomain(filepath.Base(filePath)); len(reasons) > 0 { p.log.Error( "CNP name parse validation failed", logfields.Name, filepath.Base(filePath), logfields.Reasons, reasons, ) return false } return true }

即文件必须满足:

  • 扩展名为.yaml.yml、无扩展名等均会被忽略);
  • 文件名必须符合 DNS-1123 子域名规范(仅含小写字母、数字、-.,且以字母数字开头/结尾),命名不合法会直接打印错误日志并跳过。

文件的解析流程为:os.ReadFile读取 →yaml.YAMLToJSON转 JSON →json.Unmarshalcilium_v2.CiliumNetworkPolicy对象(watcher.go)。这意味着文件必须是合法的 Cilium Network Policy YAML,任何语法错误或字段不合法都会导致翻译失败,agent 会记录Failed to translate policy yaml file to cnp object之类的错误日志。

目录监视本身基于 fsnotify),完整生命周期如下:

  1. agent 启动时通过fsnotify.NewWatcher()创建监视器,并watcher.Add(dir)注册目录;
  2. 扫描目录中已存在的文件,逐个合法文件加载进策略引擎(保证 agent 重启后策略不丢失);
  3. 随后进入事件监听循环:
    • Create/Write事件 → 读取并解析文件,新增或更新策略;
    • Remove/Rename事件 → 从策略引擎删除对应策略。

cell.go中通过 Hive 生命周期将监视器注册为 agent 启动钩子(cell.go):OnStart时启动watchDirectoryOnStop时通过context.WithCancel取消监听;而StaticCNPPath为空时,直接返回一个空的sync.WaitGroup,即完全禁用该能力。

文件 → 策略引擎的数据流

加载与删除的核心实现如下(watcher.go):

// addToPolicyEngine:读取 yaml 文件并转换为策略对象,然后加入策略引擎。 func (p *policyWatcher) addToPolicyEngine(cnp *cilium_v2.CiliumNetworkPolicy, cnpFilePath string) error { fileName := filepath.Base(cnpFilePath) resourceID := ipcacheTypes.NewResourceID( ipcacheTypes.ResourceKindFile, p.config.StaticCNPPath, fileName, ) // convert to rules rules, err := cnp.Parse(p.log, p.clusterName) if err != nil { return err } // update labels lbls := getLabels(fileName, cnp) for _, r := range rules { r.Labels = lbls } dc := make(chan uint64, 1) // add to policy engine p.policyImporter.UpdatePolicy(&policytypes.PolicyUpdate{ Rules: policyutils.RulesToPolicyEntries(rules), Source: source.Directory, Resource: resourceID, ProcessingStartTime: time.Now(), DoneChan: dc, }) <-dc // wait for policy to be applied p.fileNameToCnpCache[fileName] = cnp return err }

关键点:

  • 每个策略文件会携带由filename、命名空间(若有)与policy-derived-from(值为CiliumNetworkPolicyCiliumClusterwideNetworkPolicy)组成的标签集,来源统一标记为source.Directory(watcher.go);
  • 通过PolicyImporter.UpdatePolicy()提交策略更新(policy_importer.go),提交至异步队列后由 importer 批量处理,DoneChan用于等待策略真正应用到策略引擎;
  • fileNameToCnpCache缓存「文件名 → CNP 对象」映射,用于删除操作时反查对应的策略内容(watcher.go);
  • 删除时提交Rules: nil的更新,即删除该文件对应的全部规则。

源码级测试对这条链路有完整覆盖(watcher_test.go):

  • TestTranslateToCNPObject:验证合法 YAML 能成功转为 CNP 对象、非法 YAML 返回错误;
  • TestAddToPolicyEngine:验证策略加载后写入缓存,且同名文件重复加载即为更新(覆盖同一缓存条目);
  • TestDeleteFromPolicyEngine:验证删除后缓存清空,且删除不存在的条目会返回fileNameToCnp map entry doesn't exist错误。

测试中使用的策略 YAML 可以作为放置到目录中的真实样例(以 CiliumClusterwideNetworkPolicy 为例):

apiVersion: cilium.io/v2 kind: CiliumClusterWideNetworkPolicy metadata: name: deny-egress-to-ip spec: endpointSelector: {} egressDeny: - toCIDR: - "11.1.0.4/32" enableDefaultDeny: egress: false

策略来源验证:source 字段与 endpoint 关联

要确定某条策略是通过 Kubernetes CRD 建立,还是直接来自目录文件,可以执行cilium policy get并检查策略中的source属性。来自目录的策略其source字段为directory。此外,cilium endpoint get <endpoint_id>的输出中也包含与该 endpoint 关联策略的来源字段,可用于排查某端点究竟被哪一类来源的策略所约束。

从底层看,directory来源在 pkg/source/source.go 中定义:

// Directory is the source used for watching and reading // cilium network policy files from specific directory. Directory Source = "directory"

同时,defaultSources按优先级从高到低排列了所有来源(source.go),AllowOverwrite()依据该顺序决定新状态能否覆盖旧状态(source.go)。从源码结构看,Directory的优先级介于ClusterMeshLocalAPI之间,且 source_test.go 显示Directory来源的新状态可以覆盖KubernetesCustomResourceKVStoreLocalKubeAPIServerClusterMesh等既有来源,而LocalAPIGeneratedRestored则不可被覆盖。因此可以推断:当同一策略同时以多种来源定义时,最终生效的规则由来源优先级裁决,这也是排查「为什么目录中的策略与 CRD 中的策略行为不一致」时需要留意的点。

已知限制与版本注意点

对于Cilium 1.14 之前的版本,针对集群外部对端的 deny 策略(deny-policies for peers outside the cluster)有时无法生效,相关历史问题为 issue #15198。因此,如果依赖 deny 策略来管理发往集群的外部流量,请确保使用 1.14 或更高版本

结合源码还可补充以下使用注意点:

  • 目录中不合法(无法解析)的 YAML 文件会导致 agent 记录致命错误(logging.Fatal),需保证放置的文件始终合法;
  • 文件名的合规性直接决定策略是否被加载,命名不符合 DNS-1123 的文件会被静默跳过;
  • 该特性仅处理CiliumNetworkPolicy/CiliumClusterwideNetworkPolicy,其他类型(如标准 Kubernetes NetworkPolicy)的文件即使放入目录也不会被转换为规则;
  • 目录必须通过卷挂载从宿主机映射进 agent 容器(Helm 下使用extraHostPathMounts),且挂载路径需与--static-cnp-path保持一致,否则 agent 启动时会因无法访问目录而失败并记录Failed to watch policy directory

小结

基于磁盘文件的 Network Policy 为 Cilium 提供了一条去 CRD 化的策略下发路径:写入即加载、修改即更新、删除即卸载,配合 agent 的目录监视能力实现策略的热变更。其核心实现位于 pkg/policy/directory/,配置入口为static-cnp-path(cell.go),完整监视与导入逻辑见 watcher.go,并通过 watcher_test.go 得到行为验证。在需要绕过 Kubernetes API 进行策略管理、或希望在节点本地直接维护策略文件的场景下,该特性提供了简单而可靠的选择;使用时注意版本(1.14+)与文件名、文件格式的合规性即可。

【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 17:28:33

Less.js 备忘清单:CSS 预处理器核心语法与内置函数实战速查

Less.js 备忘清单&#xff1a;CSS 预处理器核心语法与内置函数实战速查 【免费下载链接】reference 面向开发者的技术速查清单&#xff08;Cheat Sheets&#xff09;集合&#xff0c;整理常见技术、工具与开发流程&#xff0c;帮助快速查阅关键信息&#xff0c;提高开发效率。 …

作者头像 李华
网站建设 2026/9/14 17:24:03

经销商数字化转型:Dify低代码平台实战解析

1. 经销商数字化转型的必然选择最近两年走访了上百家区域经销商&#xff0c;发现一个共性痛点&#xff1a;传统经营模式越来越难应对市场变化。上个月在山东聊城遇到一位做快消品批发的张总&#xff0c;他给我算了一笔账&#xff1a;人工统计订单的差错率高达8%&#xff0c;库存…

作者头像 李华