MoreRSS

site iconOilbeater修改

灵雀云技术合伙人, Kube-OVN Malacca 项目发起人,维护者
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Oilbeater的 RSS 预览

从 NetworkPolicy 到 ClusterNetworkPolicy

2025-11-30 17:45:00

NetworkPolicy 作为 Kubernetes 早期的 API 看似美好,实际使用过程中就会发现它功能有限,不易扩展,不易理解且不易使用。因此 Kubernetes 成立了 Network Policy API Working Group 来制订下一代的 API 规范,而 ClusterNetworkPolicy 就是目前探讨出来的最新成果,未来可能会成为新的规范。

NetworkPolicy 的局限性

NetworkPolicy 是 Namespace 级资源,本质上是“应用视角”的策略。它通过 podSelector、namespaceSelector 来选中一批 Pod,然后对这些 Pod 的 Ingress、Egress 做限制。这带来了几个实际的问题:

缺少 Cluster 级别的控制

由于策略的作用域是 Namespace,集群管理员无法定义集群级别的默认网络策略,只能在每个 Namespace 里都创建相同的网络策略。这样一方面每次更新策略需要对所有 Namespace 下的资源进行更新,另一方面,很容易和开发者创建的网络策略产生冲突。管理员设置的策略,应用侧很容易就可以通过新的策略绕过去。

本质上在于 NetworkPolicy 这种应用视角的策略和管理员集群视角的策略存在冲突,当用户的安全模型并不是应用视角的时候 NetworkPolicy 就会变得难以应用。而集群管理员管控集群整体的安全策略是个现实中很常见的场景。

语义不清晰

NetworkPolicy 的语义有几个“坑”,新手和运维人员都容易踩:

  • 隐式隔离。
    一旦有任何 NetworkPolicy 选中了某个 Pod,那么“未被允许”的流量就会被默认拒绝。这种隐式的行为需要靠心算来推导,很难一眼看懂。

  • 只有允许,没有显式拒绝。
    标准 NetworkPolicy 只能写 allow 类型的规则,想要“拒绝某个来源”,通常要通过补充其他 allow 规则间接实现,或者依赖某些 CNI 厂商特有的扩展。

  • 没有优先级。
    多个 NetworkPolicy 选择同一批 Pod 时,规则是加法而不是覆盖关系。最终行为往往需要把所有策略合在一起看,排查问题时非常困难。

这些特点叠加在一起,就会导致 NetworkPolicy 理解起来困难,调试起来更困难。

ClusterNetworkPolicy 的解决方案

为了解决 NetworkPolicy 固有的问题,Network Policy API 工作组提出了一个新的 API —— ClusterNetworkPolicy (CNP),它的目标是在不破坏现有 NetworkPolicy 用法的前提下,给集群管理员提供一个更清晰、更强大的网络控制能力。

其最核心的思路是引入策略分层,在现有的 NetworkPolicy 之前和之后分别引入独立的策略层,将集群管理员的策略和应用的策略分开,提供了更丰富的视角和更灵活的使用。

一个示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: policy.networking.k8s.io/v1alpha2
kind: ClusterNetworkPolicy
metadata:
name: sensitive-ns-deny-from-others
spec:
tier: Admin
priority: 10
subject:
namespaces:
matchLabels:
kubernetes.io/metadata.name: sensitive-ns
ingress:
- action: Deny
from:
- namespaces:
matchLabels: {}
name: deny-all-from-other-namespaces

集群管理员视角

新引入的 ClusterNetworkPolicy 是集群级别资源,管理员可以直接选中多个 Namespace 下的 Pod 进行策略控制。同时 Admin Tier 的策略可以先于 NetworkPolicy 生效,这样集群管理员只需要少量的 Admin Tier 策略就可以控制住整个集群的红线行为。

而 Baseline Tier 的策略在所有 NetworkPolicy 都不匹配后执行,相当于提供了一个兜底策略。

简单来说:

  • tier: Admin 的策略用来定义绝对不能做的事情。
  • tier: Baseline 的策略用来定义默认不建议做的事情,用户可以通过 NetworkPolicy 来放行。

明确的优先级

ClusterNetworkPolicy 中新增了 priority 字段,这样在同一个 Tier 中多个规则的范围出现重叠时,可以通过优先级清晰的界定哪个规则该生效,不会再出现 NetworkPolicy 里那种隐式覆盖,需要互相猜测的情况。

清晰的动作语义:Accept / Deny / Pass

和 NetworkPolicy 只有“允许”语义不同,ClusterNetworkPolicy 的每条规则都有一个显式的 action 字段,可以取值:

  • Accept:允许这条规则选中的流量,并停止后续策略评估
  • Deny:拒绝这条规则选中的流量,并停止后续策略评估
  • Pass:在当前 tier 里跳过后续 ClusterNetworkPolicy,交给下一层继续评估

同时,文档中特别强调:

  • ClusterNetworkPolicy 不再有 NetworkPolicy 那种“隐式隔离”的效果
  • 所有行为都来自你写的规则本身,读策略时看到什么就是什么

结合优先级的配置,规则的理解就不再会产生模糊的情况,理解上也变得不那么困难。

小结

ClusterNetworkPolicy 一定程度上回归了传统的分层网络策略的架构,在解决了 NetworkPolicy 问题的情况下没有带来破坏性的变化,可以说是一个很不错的设计,希望能尽快看到这个规范的成熟和落地。

OpenPERouter:把 EVPN 带入 Kubernetes

2025-11-09 12:29:02

目前社区在 Kubernetes 实现网络多租户主流选型是 Kube-OVNovn-kubernetes,这两个方案本质上都是在物理网络上通过 OVS 和 OVN 的能力构建了一层 Overlay 虚拟网络。这种方案不太关心底层物理网络架构,有着比较好的兼容性,但是双层网络架构也加大了整体架构的复杂度。

最近我在调研 EVPN 这种物理网络多租户的方案,发现了 OpenPERouter 这个开源项目,他把 EVPN 的理念引入了容器网络,提供了一种新的在 Kubernetes 上实现多租户的方案。该方案不仅能统一软硬件网络架构,还在一定程度上能兼容现有 Calico 这种通过 BGP 方式发布路由的 CNI,我甚至已经看到通过少量工作就可以让 Calico 具备多租户能力的前景。虽然这个项目还在早期,但我认为这是一个相当不错的方向,未来很可能会成为构建大规模数据中心的一个有竞争力选型。

OVN 类方案的局限性

OVN 类方案的主要局限性有两个一个是集中式控制平面的规模限制,另一个就是网络复杂度。

集中式控制平面

尽管 Kube-OVN 在社区已经存在了上千节点的大规模案例,但是由于 OVN 这种集中式控制面的架构,会导致控制面存在比较大的压力,成为整个集群的瓶颈。特别是在控制面节点断电或者故障时,可能会需要较长时间网络控制面才能恢复。

ovn-limit

这个问题主要是由 OVN 集中式控制平面的架构带来的,无法完全规避。ovn-kubernetes 中采用了每个节点一个 OVN 控制平面,多节点之间通过 OVN-IC 互联的方案来规避这个瓶颈。但是这个方案同时也会导致架构的复杂,并且相当于主动弃用了 OVN 本身的集群网络能力,使得大量的 OVN 能力无法使用。

网络复杂度

另一个问题就在于 OVS/OVN 这套体系本身的复杂度,使用者需要重新再构建一套 OVN 规范下的网络拓扑,流表的知识体系才能保证自己面对实际问题时不会手足无措。而这套体系和底层的物理网络往往又是不同的,实际中相当于存在两套网络体系,这不仅会使问题排查变得更复杂,还会导致需要物理网络团队和容器网络团队两套人马,双方往往都无法理解彼此的工作内容,无法有效协同。

以上两个局限性更多的是选型上的取舍,如果希望能够软件集中控制,希望容器网络能不关心底层物理网络,那这样的选择必然就会带来这样的局限性。

EVPN

在和 OVS 这种纯软件方案平行的另一个硬件世界,有另一套硬件版本的多租户网络方案,那就是 EVPN。

在 EVPN 的世界里,在数据平面交换机之间通过 Vxlan 对数据包做封装,通过在 Vxlan 的 Header 中设置 VNI 来区分不同租户的流量,实现了流量的隔离。

同时,交换机之间通过 BGP 在控制平面来同步 L2/L3 的路由以及 VNI 的信息,能够快速的学习整个网络拓扑中的地址,路由和租户信息。

EVPN

通过这种方式,大型数据中心可以自动化分布式的实现多租户网络。这套方案在很多大型数据中心都已经落地了,主流的交换机目前也都已经支持。那么在容器领域有没有基于这种技术架构做网络的呢?这就是我最近发现的 OpenPERouter 了。

OpenPERouter

OpenPERouter 的核心理念是将 EVPN 交换机的逻辑下沉到节点,在每台机器上运行一个 FRR 通过直接和物理交换机建立 BGP 和 VXLAN 隧道,将容器网络直接打通到已有的 EVPN 架构的物理网络。

现有的容器网络想接入 OpenPERouter 也并不算复杂,基于 BGP 的 CNI 需要和 OpenPERouter 建立 BGP Peer;对于基于 veth 和网桥的 CNI,需要把原来在宿主机一侧的 veth 改为接入到 OpenPERouter 所在的 net ns 即可。

这个方案带来了一些独特的优点:

  1. 统一了底层网络和容器网络,两者采用了相同的 EVPN 架构,虽然在具体操作,软件使用上还有区别,但整体的思路已经基本一致了。
  2. 极其轻量的方式就实现了 Underlay 和多租户这两个在容器网络里比较困难的功能,由于主要的控制面和数据面都在硬件层,容器网络只是做接入,理论上 CNI 层可以做的十分轻量化。
  3. 可以将已有的 CNI 转换为多租户的 CNI,尽管项目的开发者没有具体提这个事情,但是我已经看到了给 Calico 的 IPPool 增加一个 VNI 的配置就能快速把 Calico 改造成一个多租户网络的可能性。

当然这个方案当前也有它的局限性:

  1. 统一的网络也就意味着容器网络完全侵入了底层物理网络,这需要有统一的团队管理,这在当前的环境可能会产生很多办公室政治问题
  2. OpenPERouter 目前自己并没有做 CNI 相关的事情,而是尝试接入其他网络项目。这可能是考虑到当前已有多种主流方案可供选择,但从我来看接入其他 CNI 反而会让这个简洁的 EVPN 方案变的比原来更复杂,未来发生不兼容和冲突也是大概率事件。基于这个思路从头做一个轻量化的专门面向 EVPN 设计的 CNI 会是个更优雅的选择。

小结

在我看来,EVPN 会是未来容器网络里的一个极其有竞争力的技术方案,但是当下并没有很成熟的开源项目,OpenPERouter 做了很好的尝试,我也很希望看到未来有一款专门为 EVPN 架构设计的 CNI 能够大幅简化全局的网络设计。

LoxiLB -- More than MetalLB

2025-08-15 22:48:00

MetalLB 目前几乎成了私有云场景下 Kubernetes 提供 LoadBalancer 类型 Service 的事实标准。他的实现逻辑简单清晰,并且功能单一,基于 Gossip 的分布式选主也保证了 VIP 的漂移可以做到迅速且不依赖 Kubernetes 的状态。但是它在专注的情况下也缺少了一些在生产环境极为重要的功能,这也是为什么我最近在调研其他的开源项目,并发现了 LoxiLB 这个很不错的 MetalLB 替代项目。

MetalLB 的缺陷

MetalLB 虽有 LB 之名,但实际上并不处理任何转发平面的工作。严格来说它只提供了 VIP 的对外通告能力,所有转发平面的事情都是依赖 kube-proxy 或者各类的 kube-proxy 的替代 来实现。这样的好处是它可以专注在提供各种类型的 VIP 宣告方式,并且能和 Kubernetes 本身的行为保持最大的兼容性,但同时由于 kube-proxy 本身孱弱的能力,也限制了 MetalLB 本身的功能。

缺乏主动健康检查

这是 Kubernetes 由来已久的一个问题,Service 后端的 Endpoint 健康状态依赖 Pod 本身的 ReadinessProbe/LivenessProbe,Probe 的执行依赖当前节点的 kubelet。造成的结果就是断电或类似的直接宕机情况下 kubelet 无法更新 Pod 的健康状态,需要等到触发 node not ready 的超时才会修改 Pod 监控状态,通常在大集群这个超时可能会有数分钟,导致这段时间内访问 Service 会出现失败。

严格来说这并不是 MetalLB 的问题,但是由于 MetalLB 本身对数据转发平面没有任何控制能力,无法主动探测 Pod 真实健康情况也无法修改 Pod 健康状态,只能被动接受这种机制。

虽然通过 Pod ReadinessGates 可以使用额外的 controller 主动探测来控制 Pod 健康状态,间接解决这个问题,但对于 MetalLB 来说这个也和它没有什么关系,并没有能开箱即用的方案,这对生产环境还是个很大的隐患。

缺乏有效的监控

这同样是依赖 kube-proxy 实现导致的一个问题,kube-proxy 的多种实现方式都没有流量层面的监控,导致的后果就是如果你看 MetalLB 提供的监控指标就会发现里面没有任何流量的指标。这种几乎没有任何数据平面监控的 LB 要上生产,就有点过于松弛了。

LoxiLB 的改进

LoxiLB 本身是一个为电信场景的特殊需求,使用 eBPF 打造的专用 LB,它完全实现了控制平面和数据平面是一个完整的 LB 实现。LoxiLB 本身的功能十分多,尤其在 SCTP 领域有十分多专属能力,这里不赘述只是重点看一下针对 MetalLB 缺陷的补足。

主动健康检查

LoxiLB 可以给每个 Service 配置主动健康检查,支持 ping, tcp, udp, sctp, http, https 也支持超时,重试之类的细粒度配置,虽然称不上多优秀,但 MetalLB 就是没有这个功能,这就显得很尴尬。

监控指标

这一点就是 eBPF 的强项了,LoxiLB 内置了不少 Metrics 和 Grafana 面板,此外由于数据平面是自己实现的,添加各类监控指标也相对容易一些。

潜在的风险

整体来看 LoxiLB 是一个我很喜欢的项目,甚至很多关于 SCTP 协议的理解我都是看了它的一些配置才能理解是怎么回事。但是他还是有着一些不足的地方:

  • 选主的逻辑目前还是 Kubernetes 那套 Leader Election 逻辑,但我更喜欢 MetalLB 那种与 Kubernetes 解耦的选主逻辑。
  • 文档整体比较凌乱,虽然文档内容很多但是组织的不是很好,好多配置得靠搜索才能找到,一些文档格式也存在问题。
  • 虽然该项目是 CNCF 沙箱项目,但是整体的活跃度和参与度还是偏低,能感觉出来该项目应该还是个比较成熟的内部项目拿了出来,但是如果社区采用度比较低的话未来还是有些隐患。

小结

MetalLB 依然是一个我很喜欢的项目,它极其精准地解决了 VIP 宣告及高可用的问题,但是如果达到生产上完备的状态还需要配合其他组件。LoxiLB 则是一套完整的 LB 解决方案,但是社区的发展还处于早期,还有待更多人的参与。

GoBGP 快速上手

2025-07-09 06:48:00

在做 MetalLB 和 Calico 的一些测试时需要验证 BGP 相关的功能,然而每次测试要去联系运维团队配合网络变更是不太现实的,并且大多数情况我们只要验证 BGP 信息正常交换就可以了,不需要真的去改变物理网络。于是就找到了 GoBGP 这个软件路由器进行模拟。

GoBGP 本身有着很复杂的配置,但是如果你只是像我一样只是想有个虚拟的路由器,让客户端把 BGP 信息发送过来,检查路由表信息是否正确更新,那看这篇文章就可以了。

下载 GoBGP 二进制文件

Release 制品列表里找到对应系统的制品解压即可,重要的只有两个二进制文件: gobgpd 虚拟路由器进程,gobgp命令行工具,用来查看路由对不对。

启动虚拟路由器

创建一个 gobgp.toml 文件,最简单的配置就照着我下面这个就好了,大部分基础的云原生领域 BGP 相关的软件测试用这个就够了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[global.config]
as = 65000 # 测试环境随便写一个就好
router-id = "10.0.0.1" # 测试环境随便写一个就好,写 GoBGP 所在节点 IP 日志清晰一些

[[dynamic-neighbors]] # 被动连接模式,省去了配固定客户端
[dynamic-neighbors.config]
prefix = "192.168.0.0/24" # 允许哪个 IP 范围内的客户端来连接
peer-group = "ext-ebgp"

[[peer-groups]] # 复制粘贴就好了
[peer-groups.config]
peer-group-name = "ext-ebgp"
peer-as = 65000
[[peer-groups.afi-safis]]
[peer-groups.afi-safis.config]
afi-safi-name = "ipv4-unicast"

启动 gobgpd

1
./gobgpd -f gobgp.toml

在另一个终端观察当前的路由表

1
./gobgp global rib

这样基本上 MetalLB,Calico 的基础 BGP 能力就可以测试了。如果想更配更复杂的模式,比如 Router ReflectorEVPN 那就再去翻 GoBGP 的文档吧。

怎样的开源文档规范最合适?

2025-07-06 21:00:10

最近打算把 Kube-OVN 的文档整理一遍,同时思考怎样的文档规范能尽可能做到:

  1. 降低 Maintainer 的维护成本(用户看完文档后不会再去找 Maintainer )。
  2. 能够充分复用(不看文档的人找过来可以直接甩文档)。
  3. 同时对社区的用户也尽可能有帮助(少走弯路)。

我决定先按照下面的结构重构一下文档,来看看效果。

  1. 概要:一两句话描述这个功能达到什么效果,解决什么问题,有什么优势。之前很多文档都是以技术细节开头,反而把真正能实现的效果给模糊掉了。明确功能是什么后,用户就可以确认自己是否还需要继续往下看了。
  2. 局限性:这个功能不是什么,什么没做到,解决不了什么问题,使用有什么限制条件。这个其实和第一部分一样重要,不然用户可能有不切实际的预期等到很靠后的时候才知道某个功能其实是不符合预期的或者限制条件不满足,也浪费了双方很多时间。有人问为什么不能用的时候也可以甩文档。
  3. 实现原理:我们用到的 OVN/OVS 的哪些能力,简要的介绍以及对应功能的参考文档。到这里我们其实期望用户有一些更深的理解,不至于出了问题毫无思路再去扒代码或者找到 Maintainer。我们也建议真在生产使用 Kube-OVN 的用户要有一些从底层开始排查的能力,Kube-OVN 虽然做了很多抽象让使用变得简单,但是在用户的环境里使用的异常还是需要用户自己有能力排查。
  4. 使用步骤:之前的常规内容,有了前面的铺垫,这一部分可以尽可能简化,只需要步骤即可。

大家有什么其他的建议也可以一块来讨论一下。

Kube-OVN 是如何自动修复 CVE 的

2025-06-28 08:02:21

这篇博客是内部分享的一个提示文稿,并没有做仔细整理,大体思路就是捕获所有 Kube-OVN 的依赖:操作系统,Golang,程序依赖,环境组件(k8s,kubevirt 等),然后激进的实时更新所有依赖做到动态清零。

Kube-OVN CVEs 问题修复的流程经历了如下几个阶段:

  • 发版/按需统一进行手动修复
  • 每次 commit 检测可修复安全漏洞,手动进行修复
  • master 依赖自动更新,发版分支部分依赖自动更新,少量手动修复
  • 未来目标:所有依赖自动更新,避免手动修复

按需修复

优势:

  • 相比每个安全漏洞单独修复,整体修复频次低
    劣势:
  • 发版集中修复,研发还要兼顾发版期间赶进度,测试,bug 修复,时间压力大
  • 依赖更新没有经过日常验证,存在未知的风险
  • 大部分安全修复工作没有实际意义还需要花费人工精力

每次 Commit 检测修复

增加工作:

优势:

  • 将 CVE 修复打散到平时,发版时时间压力较低
  • 可以快速发版
  • 大部分依赖更新已经得到了日常自动化测试的验证,风险也较低
    劣势:
  • 最后一次提交和发版扫描之间存在时间差,理论上会遗漏一部分 CVE
  • 会干扰平时正常功能提交,bug 修复,提交经常因为不相关的 CVE 问题被阻塞
  • 大量的手动修复

所有依赖自动更新

只要依赖更新版本就尝试更新,不考虑是否是安全更新。尝试解决比 CVE 修复更大的一个问题,自动就解决了 CVE 问题的修复。

我们的依赖项:

  • OS 镜像及其依赖:ubuntu:24.04, apt-get install ....
  • Go 语言版本,以及代码依赖库
  • 上游依赖:OVS, OVN
  • 其他协作组件依赖: kubernetes, kubevirt,multus, metallb, cilium, talos
  • 采用比较激进的更新策略,依赖大版本更新我们也会尝试更新

要做的事情:

优点:

  • 大部分 CVE 会在不知道情况下被修复,少量可在一天内自动修复,特殊情况再手动修复
  • 大量上游的 bugfix,性能提升和新功能被自动合入,软件整体稳定性提升
  • 大量的版本适配验证工作,如 k8s 版本更新,KubeVirt 版本更新的适配验证也都自动进行,风险提前知晓
  • 人工干预量较少

劣势:

  • 依赖更新多比较吵,需要设置聚合策略
  • 更新量太大无法人工测试,需要有自动化测试保证
  • 需要积极适配上游版本变化
  • 存在上游新版本不稳定风险,目前两年内遇到过两次

renovate 相比 dependabot 优势

  • 可以自定义依赖捕获,Dockerfile、Makefile 里的非标准依赖可以捕获
  • 可以在非 master 分支运行
  • 有 auto merge 能力

还未解决的问题