再谈自研开源 Kube-OVN, 设计思路及实现原理
关于 OVN 和 OVS 的介绍可以参考之前的分享《灵雀云开源Kube-OVN网络组件,增强Kubernetes网络功能》。目前 Kube-OVN 已经在 GitHub 开源 https://github.com/alauda/kube-ovn,欢迎大家 star 做贡献。
为什么又要做一个网络插件
我们之所以要自己动手来做,有很多现实原因的考虑:
1、最主要的是现有开源方案很难满足我们客户的需求,例如子网划分,IP 固定,QoS,VLAN 隔离,流量镜像等等这种在传统网络里很常见的功能在绝大部分的开源网络方案里都是缺失的。造成的结果是,真正落地的时候会发现没有一个开源网络方案能用,只能不断的和网络部、系统部、应用部各个部门扯皮,割舍掉原有的一些网络功能来上容器。我们希望能通过技术的手段丰富现有的容器网络能力,来帮助客户更顺利的落地容器。
2、从我们自身维护容器云的角度来看,容器平台网络相关的问题是最难排查的。一个网络不通的问题可能会涉及 Pod 网络、CNI、Service、Iptables、IPVS、Ingress、DNS、NetworkPolicy、Loadbalancer 等等多个组件,流量的分散导致故障十分难以排查,并且需要运维人员掌握很多组件的原理。我们希望能够把网络流量的数据面进行统一,不要再分散到各个组件上,降低维护方面的复杂度。
3、经过调研我们认为 OVN/OVS 这套网络组件功能上比较齐全,能够实现 OpenStack 的所有网络功能,那么对 Kubernetes 的网络来说能力其实是大幅溢出的,可以实现很多高级功能。此外 OVS 已经是经久考验的虚拟交换机,稳定性是很有保证的,性能方面也有各种 DPDK 和硬件加速方案来托底,真正到要性能的时候我们有应对的方案。此外我们了解到的一些公有容器云厂商内部其实也是用的 OVN 来做容器网络,我们也不算第一个烈士。
综合这些因素我们决定自己开发一个基于 OVN 的网络方案,也就是 Kube-OVN 。一方面能够很好满足客户和我们自己的需求,另一方面开源出来也能帮助社区一同进步。
Kube-OVN 的设计原则和思路
1、平移 OpenStack 网络的概念和功能到 Kubernetes。OpenStack 的网络已经发展了很多年,很多设计和概念也基本成了 SDN 的标准。我们希望能通过 OVN 不仅仅是引入一些高级功能,还能引入一些比较成熟的网络概念,像 VPC、Subnet、多租户、FIP、SecurityGroup 等等,从整体上增强 Kubernetes 网络的能力。
2、统一网络的数据平面,我们希望把 Kubernetes 作为网络的控制平面,所有数据平面的功能都能通过 OVN 来实现,包括 Service、DNS、NetworkPolicy 都通过 OVN 来实现,简化之后的维护工作。
3、尽可能覆盖其他开源网络方案的功能。对我们来说也不希望同时支持多个网络插件,每个客户都不一样,这样对我们成本也很高。我们自己希望有这么一个跟水桶机一样的网络方案要的功能都覆盖了,还能有些特色,这样是最好的。
4、尽可能的易于安装使用。OVN、OVS 这套东西本身的安装和使用都还是比较复杂,门槛比较高我们希望能进行简化,降低用户使用的门槛。方便交付,也方便更好的推广。
Kube-OVN 的整体架构和功能实现
先看一下组件的架构,Kube-OVN 自身的安装 yaml 里包含了 OVN 和 OVS 的安装和配置,Kube-OVN 自身的逻辑主要集中在图中蓝色的部分 kube-ovn-controller,kube-ovn-cni 和 kube-ovn-cniserver。其中最主要的逻辑在 kube-ovn-controller 可以看成是一个 Kubernetes 资源的控制器,它会 watch Kubernetes 内所有和网络相关的资源变化,例如 Pod、Node、Namespace、Service、Endpoint 和 NetworkPolicy。每当资源发生变化 kube-ovn-controller 会计算预期的状态,并将网络对应的变化翻译成 OVN 北向数据库的资源对象。同时 kube-ovn-controller 会将配置具体网络的信息,例如分配的 IP、Mac、网关等信息再以 Annotation 的方式回写到 Kubernetes 的资源里,方便后续的处理。
kube-ovn-cni 本身是很薄的一层,主要工作是适配 CNI 的协议和 Kubelet 对接,将标准的 cni add/del 命令发送到每台机器上的 kube-ovn-cniserver 进行后续处理。而 kube-ovn-cniserver 会根据传入的参数反查 Kubernetes 中资源对应的 Annotation,操作每台机器上的 OVS 以及容器网络。
举一个创建 Pod 的例子,Pod 下发到 apiserver 后 kube-ovn-controller 会 watch 的新生成了一个 Pod,然后调用 ovn-nb 的接口去创建一个虚拟交换机接口,成功后将 OVN 分配的 IP、Mac、GW 等信息反写到这个 Pod 的 Annotation 中。接下来 kubelet 创建 Pod 时会调用 kube-ovn-cni,kube-ovn-cni 将信息传递给 kube-ovn-cniserver。CNIServer 会反查 Pod 的 Annotation 获得具体的 IP 和 Mac 信息来配置本地的 OVS 和容器网卡,完成整个工作流。其他的 Service、NetworkPolicy 的流程也是和这个类似的。
Kube-OVN 实现的网络模型
Flannel 和很多网络的实现上都是一个 Node 一个子网,我们发现这种子网模型很不灵活,而且也很难扩展。因此在 Kube-OVN 里我们采用了一个 Namespace 一个子网的模型,子网是可以跨节点的这样比较符合用户的预期和管理。每个子网对应着 OVN 里的一个虚拟交换机,LB、DNS 和 ACL 等流量规则现在也是应用在虚拟交换机上,这样方便我们之后做更细粒度的权限控制,例如实现 VPC,多租户这样的功能。
所有的虚拟交换机目前会接在一个全局的虚拟路由器上,这样可以保证默认的容器网络互通,未来要做隔离也可以很方便的在路由层面进行控制。此外还有一个特殊的 Node 子网,会在每个宿主机上添加一块 OVS 的网卡,这个网络主要是把 Node 接入容器网络,使得主机和容器之间网络可以互通。需要注意的是这里的虚拟交换机和虚拟路由器都是逻辑上的,实现中是通过流表分布在所有的节点上的,因此并不存在单点的问题。
网关负责访问集群外部的网络,目前有两种实现,一种是分布式的,每台主机都可以作为运行在自己上面的 Ood 的出网节点。另一种是集中式的,可以一个 Namespace 配置一个网关节点,作为当前 Namespace 里的 Pod 出网所使用的网关,这种方式所有出网流量用的都是特定的 IP nat 出去的,方便外部的审计和防火墙控制。当然网关节点也可以不做 nat 这样就可以把容器 IP 直接暴露给外网,达到内外网络的直连。
Kube-OVN 功能实现
首先是子网,子网是 Kube-OVN 中最为重要的一个概念,涉及到之后的 IP 分配,ACL 以及未来的 VPC 等功能。实现上每个子网对应 OVN 中的一个虚拟交换机,对应 Kubernetes 中的一个 Namespace,我们可以通过给 Namespace 加 Annotation 的方式来配置一个虚拟交换机。子网里可以配置基础的 CIDR,Gateway,保留 IP 段,以及一些基本的 ACL,这些都可以用 OVN 自身提供的能力。
然后是 IP 分配。Kube-OVN 现在支持随机分配和固定 IP 分配。随机分配比较简单,可以使用 OVN 提供的 dynamic addresses 能力,自动分配一个当前子网内不冲突的 IP/Mac。固定 IP 我们采用了一个额外的 annoation ip_pool,Pod 在启动时 controller 会跳过 OVN 的自动分配根据 ip_pool 内的 IP 选择一个未被占用的地址分配给 Pod。对于 Deployment Pod 启停会产生 IP 的释放和再分配的过程。表面上看 Deployment 下面的几个 Pod 一直用固定的 IP,但实际上是一个动态变化,最中表现出来使用固定 IP 的过程。
之后是 QoS,通过 QoS 可以控制容器的 Ingress 和 Egress 带宽,我们可以通过 Pod 的 Annotation 来动态控制容器带宽。实现上我们最早计划使用 OVN 的 QoS 能力,但是实际使用时发现 OVN 的 QoS 这块存在问题,无法控制同主机内的流量,因此最终使用的是 OVS 自身的 ingress_policing_rate 和 Port QoS 来实现带宽控制。
网关这里 OVN 本身提供了网关的能力,但是对网络有额外的需求需要用到一块单独的网卡做 Overlay 网络的 offload,使用上有些限制因此我们并没有采用。我们最终的实现是使用了 OVN 中的策略路由,将访问外网的流量路由到特定节点,再通过 Iptable 做 Masq 自己实现了一套从网关出网的逻辑。这种方案的好处是对网络没有额外的需求,我们在公有云上都可以使用这种网关模式。当然在具体落地时也可以根据场景替换成性能较好的 OVN Gateway 方式。
流量镜像。对容器流量进行抓包是件很繁琐的事情,好在 OVS 本身有流量镜像的功能,Kube-OVN 会在每台主机上创建一块 mirror0 的网卡,并设置镜像规则,将该主机上所有的容器流量复制一份到 mirror0 网卡。这样我们只需要 tcpdump -i mirror0 就可以捕获到这台主机上所有的容器网络流量了。方便之后的应用层面的监控和审计。
还有一些其他的功能。例如用 OVN 的 LB 代替 kube-proxy,用 ACL 来实现 NetworkPolicy 还有 OVN 的高可用等等,感兴趣的可以爬一下 Kube-OVN 的 release note 看看还有什么隐藏功能。
这些看上去功能都比较复杂,但实际使用还是比较简单的在对应的资源上打 Annotation 就可以了。此外即使不做任何配置,Kube-OVN 会带一个默认的子网,默认的分布式网关,以及内置的 Service 和 NetworkPolicy 实现,完全可以当一个增强版本的 Flannel 来用。
近期工作和未来发展
1、IPv6 的支持,这是我们客户方面比较急迫的一个需求,由于工信部的 IPv6 推广计划,对 IPv6 的需求也越来越多,同时借这个机会我们会对 Kube-OVN 现有的子网进行重新的设计,可能会抽象出一个 CRD 来做更复杂的控制。
2、监控 /tracing 工具的集成。传统网络工程有很多不错的网络检测工具例如 IPFIX、sFlow 和 NetFlow,我们未来会将这些工具加进来丰富网络的功能。此外借助流量镜像的能力我们也可以做一些应用层的流量分析和监控。
3、性能优化和 DPDK 的支持,主要是为了消除客户对 OVS 性能的担心。我们和社区内的一些人进行过交流,在使用 DPDK 后即使是小包也可以打满万兆网卡,因此性能方面还是很有前途的。
现在项目已经开源在 https://github.com/alauda/kube-ovn ,欢迎大家来 star 给作者打打气,也欢迎感兴趣的个人和公司都能参与进来,大家一块来完善这个项目。
Q&A
Q:能说说组件 kube-ovn-cni 具体是做什么的?OVN 本身不是已经是 OVS 的控制面了么?
A:其实做的是容器网卡和 OVS 的对接,OVN 那边生成了 port 的信息,需要 kube-ovn-cni 把这个信息同步到 OVS 和容器网卡。
Q:能讲讲 Kube-OVN 负载均衡和会话保持是怎么做的吗?已经支持哪些策略?
A:目前的负载均衡用的是 OVN 的 L2 Loadbalancer,这一块的负载均衡还比较简单只支持 IP Hash。
Q:多租户 /VPC 模式下是否可以互相之间网段冲突,如何实现 livenessProbe?
A:这块暂时还不支持,主要是 kubelet 是在主机的 network namespace 进行 probe,其实可以改 kubelete 代码进入到对应容器的 ns 再 probe 就可以了,但是这块需要 upstream 来进行支持,自己魔改现在倒也是个方案。
Q:Kubernetes 的业务使用本身就是有局限的,这种无限制扩大虚拟网络的做法,基于业务风险和成本来讲,真的很勇敢,如果原有的 Kubernetes 生态被改掉了,怎么保证开源的东西可以业务延续?
A:这个问题有点大,我们现在看到的趋势还是 Kubernetes 不断的发展,各个业务都在往 Kubernetes 走,我们做这个其实也希望能尽量和 Upstream 同步,并且之后可以去影响 Upstream。还有很多复杂的功能,比如 IPv4/IPv6 的双栈,多租户我们暂时也还没开始,也是因为 Upstream 现在对这块的支持还不好。
Q:和 https://github.com/ovn-org/ovn-kubernetes 的区别是什么?
A:ovn-kubernetes 我们之前调研主要问题在于他们是和 Flannel 类似的一个节点一个子网的模型,再就是看他们的代码过程中发现控制平面存在着丢消息的隐患。最后看到网络模型和控制平面都要改,工作量太大了我们就自己从头来了。
Q:使用 Flow 负载均衡器的性能怎么样,是否适合上生产环境?
A:大部分的 Flow 性能问题都可以用 DPDK 来解决,我们之前问过一些公有云的厂商性能方面是可以的,但是可能功能方面有些简单。
Q:使用 OVS 对 Host 机器的性能压迫有多大?
A:我们目前看来还好,OVS 本身带 cache 的机制,主要还是业务对性能用的比较多一些。
Q:kube-ovn-controller 如果来不及写入 podIP 这些信息,CNI 插件获取不到分配的 IP 信息,会不会导致 Pod 创建失败,还有 ovn-cni 是能过什么协议和 ovn-cni-server 进行协作的?
A:来不及写入的情况下 CNIServer 会重试等待 annotation ready,如果超时的话会失败等 kubelet 下次调用 CNI 的时候重新获取信息。CNI 和 CNIServer 现在是通过一个本机的 socket 走 http 协议进行通信。
Q:DPDK 怎么满足需求?使用容器,可以用 DPDK 加速么?
A:DPDK 主要做 OVS 的流表加速,社区由 ovs-dpdk 的 binding,容器相当于用的是 OVS 的网卡,这样 DPDK 就可以加速容器的网络。
Q:在没有硬件交换机的情况,这个网络插件怎么利用虚拟机模拟交换机呢?
A:还是要有硬件交换机做物理上的网络连通的,虚拟交换机是在机器中用软件的方式来模拟交换机的行为,这样一台机器上的多个容器或者虚拟机就好像接在了一个物理交换机上。
版权声明: 本文为 InfoQ 作者【York】的原创文章。
原文链接:【http://xie.infoq.cn/article/499b53360c4ab02a7b747472f】。文章转载请联系作者。
评论