[关闭]
@Rays 2022-02-17T13:32:07.000000Z 字数 6368 阅读 573

Kubernetes IPv4/IPv6双协议栈:微软谷歌专家访谈

摘要: 本文是InfoQ对Kubernetes双协议栈的设计实现者的访谈,其中涉及双协议栈项目的动机、技术细节、漫长的历程和路线图,以及双协议栈对Kubernetes各组件的影响,在Kubernetes云服务提供商中引发的连锁反应。

作者: Rags Srinivas

正文:

双协议栈(Dual Stack),即同时提供对IPv4/IPv6地址的支持。随着2021年12月Kubernetes 1.23的发布,双协议栈已在转为GA版本中提供。

该项目历时多年,涉及几乎全部Kubernetes组件,详见“Kubernetes增强提案(KEP,Kubernetes Enhancement Proposal)KEP-563”。

为此,InfoQ择机访谈了微软的Khaled (Kal) Henidak和谷歌的Tim Hockin。正是Kal和Tim通过与SIG-NETWORK社区的合作,设计并实现了双协议栈。本次访谈中,两位专家介绍了双协议栈项目的方方面面,包括项目动机、技术细节、漫长的历程和路线图,以及双协议栈对Kubernetes各组件的影响,进而谈及在Kubernetes云服务提供商中引发的连锁反应。

InfoQ:Kubernetes提供对IPv6和双协议栈的支持,有何意义?

Khaled (Kal) Henidak:回答这个问题,必须简要回顾一下项目的发展历程。Kubernetes自面世之初,就提出了为运行于其上的每个工作负载实例 (即Pod) 分配唯一IP地址的理念。该理念在当时也并不新颖,这已是虚拟机环境中的标准操作实践,但对于 Kubernetes这样的环境仍具创新性。由此,我们实现了IP层的可寻址工作负载、通过Service API的发现、精心设计的Ingress控制、网络安全策略等多个用例。

与此同时,物联网、边缘计算和仅运行于IPv6之上的5G等多个业界领域正得到高速发展。这样的迅速发展进一步消耗了剩余的少数IPv4地址。对于正考虑使用IPv6以避免上述问题的组织,或只是希望用IPv6来提高性能的组织,难免置身于充满挑战的境地。因为组织的IPv6集群和工作负载,难以连接到几乎只能在IPv4上运行的现有系统。在当时,唯一可用的解决方案是一些地址转换类方法,但这些解决方案将会引入性能损失和操作复杂性。

在IPv4/IPv6双协议栈网络上运行Kubernetes,可在不增加复杂性和损失性能的情况下,支持工作负载本地访问IPv4和IPv6端点。集群操作人员还可在提供外部端点时,根据自身需求选择以任一顺序提供其中一种地址族(Address Family),或是两种均提供。Kubernetes并未对运行的网络做出任何强假设。例如,在运行在小规模IPv4地址空间上的用户,可选择在集群的某个Node子集上启用双协议栈,而其余Node运行在可提供更大可用地址空间的IPv6地址族上。

在我看来,未来大部分的工作负载将转到仅有IPv6的网络上,集群也将仅运行在IPv6网络上。但在此之前,双协议栈将保持新旧两个世界之间的联系。

Tim Hockin:简而言之,Kubernetes现在可同时使用IPv4和IPv6,Pod和Service可各取所需。

展开来说,我们扩展了大量的API去支持多IP地址,而不仅仅是单个地址,包括Pod、Service、Node等。我们更新了一系列的组件去使用这些扩展的API,包括apiserver、controller-manager、kube-proxy、kubelet等。这样用户可以配置自身集群去向Pod和Service提供IPv4和IPv6地址。为最大程度上达到透明和低风险,我们已尽力而为。对于并不需要双协议栈的用户,则完全不会受到影响。但是如果用户确实需要双协议栈,那么也易于启用。对于用户现有的Pod和Service,目前尚不能自动转换,但用户自行实现也很简单。如果用户的控制器只能理解单协议栈,那么一切将会继续如常工作。

鉴于目前已提供对双协议栈的支持,一些工作将得到简化。例如,IPv4限定为32位,即提供40亿个IP地址。“私有”IPv4地址范围仅支持数百万个IP,但通常基于CIDR的路由意味着需要整块地分配地址空间。IPv6具有128位,即可提供万亿兆个IP地址,这降低了预分配大块地址空间的风险,有望简化Kubernetes在Flat IP网络模式下的使用。

InfoQ: 为便于非网络专业人士理解,你们能更多地介绍一些技术实现细节吗?

Henidak:这要从Pod开始介绍。在Kubernetes中,Pod表示为一个API对象,其中有一个状态字段描述分配给该Pod的网络IP地址。该IP由kubelet通过Node上的“容器运行时接口”(CRI,Container Runtime Interface)读取并访问。CRI本身通过调用“容器网络接口”(CNI,Container Network Interface)设置网络,CNI是一个负责设置网络的独立组件,包括Pod的双协议栈。我们扩展了该API字段,使其可以接受双协议栈地址,可以是单个IP地址,或是来自不同IP地址族的两个IP地址,顺序不限。这样就可以修改各种组件,让它们说“嘿,这个Pod是双协议栈的”。

此后,我们以同样的方式扩展了Service API,让用户可以表示Service对象的双协议栈属性。用户可以按任一顺序选择任何单个IP或地址族、双协议栈IP或地址族,或只是“如可用则设为双协议栈”。进而api-server可根据用户的需求和期望顺序,为Service对象预留或分配IP。

下一步,我们转向负责查找符合Service规范的端点的控制器(Endpoint Controller)。我们实现了全新的、性能更好的端点分片(Endpoint-Slice)控制器。这些组件设计用于识别Service的IP地址族规范,相应地在各Pod中找到对应的Service。

最后,我们转向kube-proxy。kube-proxy运行在每个Node上,负责将Service IP转换为负载均衡的Pod IP。这里同样也必须转换为双协议栈。例如,如果用户已将kube-proxy配置为在Linux设备上使用iptables,那么kube-proxy将同时使IPv4和IPv6的iptables,以确保规则能匹配用户所设置的规格。

Hockin:虽然IPv6并非“新鲜事物”,但尚未成为网络的全局默认设置。随着IPv6在全球的日益普及,“双协议栈”网络这一概念起到了一种桥梁作用。双协议栈模式支持各工作负载同时访问已有的IPv4地址和新的IPv6地址。例如,许多网站仍然不支持 IPv6,所以有时需使用IPv6,有时需使用IPv4。

不幸的是,Kubernetes是基于Pod和Service等只有一IP地址这样一个普遍存在的想法构建的。因此这项工作的部分艰苦之处在于,需要找出所有这些地方并更新,实现以安全、兼容的方式支持多IP地址。对于这样的网络密集型系统,需要处理很多地方,甚至是大量不易接触到的边缘用例。

例如,过去Kubernetes Service只具有单个IP地址。要添加双协议栈,我们必须考虑是扩展为两个地址更好,还是告诉用户去创建两个不同的Service,每种IP类型一个Service。这两种方法各有利弊。

InfoQ: 可以说KEP-563涉及到所有的Kubernetes组件。你们如何评价该KEP?介绍一下这样的大范围变更带来了哪些挑战。

Henidak:要回答这个问题,通常是纯粹从构建、测试和发布的角度,但在此我想阐述一些略有不同的事情。一旦意识到变更并非凭空产生的,就会明白挑战是前所未有的。随着变更的应用在持续推进,系统的其它部分也相应地推进和发生变化。例如,在我们致力于改进Service API时,Endpoint Slice控制器也在一并改进,这意味着我们必须同步对齐和修改Kubernetes其他部分代码。这需要协调多个推进中的PR和多位代码库维护人员。很高兴看到各位维护人员密切合作,确保了各项功能的协调和正确性。

另一个挑战是“全新API方法”的理念,在我看来值得铭记。Kubernetes对API及其指南具有严格的维护规范,以确保各版本间的一致性和前后向兼容性,最终为使用CLI和API的用户提供经过改进的、一致的整体用户体验。在修改API时,我们需要对字段做“多值化”(plural-ize)。例如,Pod IP是一个单值字段,需要更改为一个多值字段,表示该Pod现在可以有IPv4和IPv6 IP,与此同时保持对旧集群的后向兼容性,尤其是偏态集群,即集群的某部分是双协议栈的,而其他部分不是。这在Kubernetes API设计中是一个未知领域,我们必须测试各种方法,并对指南做相应的更新。更具挑战性的考虑是,Service API不仅引入了字段多值问题,而且还引入了相互依赖的字段,其中任何字段都可以驱动其余依赖字段的值。这是另一个我们必须开拓的未知领域。

Hockin:KEP-563是这个项目历史上规模最大、影响最广的提案之一。我们不想一头扎进去就直接开始编码,因此我们考虑必须尽可能做好前期工作。启动时相对简单,但随着我们讨论了所有涉及地址处理的地方,事情开始变得越来越复杂。仅编制需更新之处的清单,就花费了大家很长的时间。

但更新清单的规模太长了,一时难以消化,我们不得不把将其分成数个阶段。我们曾认为已达到事无巨细了,但实际开发证明我们仍然有所纰漏。历经多次细节迭代,才达到我们可以称之为“Alpha”的版本。

一旦交付,我们才意识到在很多细节上仍未达到目标,进而我们又做了更多次迭代。我很高兴所有维护人员愿意如此,去额外付出时间。在我看来,结果好于预期。

InfoQ: 对于与传统IPv4应用的后向兼容性,在引入双协议栈后,开发人员和架构师可能会遇到哪些无法预知的问题?采用双协议栈可能遇到什么阻碍?

Henidak:兼容性很难尽善尽美。尤其是面对几乎难以穷尽的Kubernetes配置变体,我们不可能对预期的兼容性问题给出一个全面的声明。

我想从被动和主动两个角度看问题,其责任分别由用户和维护人员社区承担。从主动方面看,我认为我们在设计和测试方面做得很好,尤其是测试。我记得在整个测试过程中,经常说的一句话就是“测试直至担心转为无聊”。在推出稳定版之前,我们一直在密切关注双协议栈在云、Kubernetes Kind、kubeadm等整个生态中的表现,确认是否会存在任何问题。即使已经准备好推出整个发布周期的稳定版,我们还刻意将其维持在Beta阶段,以便给每个维护人员更多的时间进行测试和验证。在社区响应上,我们密切关注报告的动议和问题,与那些已部署双协议栈的用户保持经常性联系。所有这些,并不仅仅是为了兼容性问题,还为了简化变更,处理任何可能存在的问题。

我对API兼容性充满信心。现有集群升级到双协议栈,应该是一个无缝的过程。让我担心的是“回退”。当用户将集群升级到双协议栈,实际上是为Service API分配了更大的地址空间,即将IPv6 CIDR添加到现有的Service IPv4 CIDR,也可选择包含Pod CIDR,具体取决于集群网络的配置方式。如果用户决定回退到单协议栈,那么必须将此作为“Pod和Service CIDR变更”来处理。这个已经应用到集群的复杂变更,通常需要集群用户手动操作。

Hockin:如果我们的工作做得到位,就应该不会导致任何后向兼容性问题。以往一切能工作的,应该都会继续工作。在用户没有特别要求双协议栈的情况下,即便Pod被分配了双协议栈地址,Service API也会默认为单协议栈。

如果用户有任何问题,我们当然愿意倾听意见。

InfoQ: 你们能谈一下对不同的公有云Kubernetes服务和CNI提供商而言,双协议栈实现将产生怎样的级联效应?

Henidak:当我们正努力在Kubernetes上实现双协议栈时,公共云提供商就已经开始针对传统的IaaS工作负载提供双协议栈支持。我相信,尤其是现在Kubernetes 1.23已发布,我们应该能首先看到双协议栈集群以DIY集群的形式提供,之后是托管的集群服务。另一个我非常关注的问题,是非传统因素对集群双协议栈的影响。例如云边协同中,一些或者说大部分集群节点部署在边端,而控制平面是云托管的。由于公共IPv4地址空间受限,此类用例对双协议栈具有强烈的需求。

Hockin: Kubernetes支持双协议栈,并不意味着所有的服务提供商和环境都要支持它。如果用户想在云环境中使用双协议栈,那么需要确保云提供商确实提供了网络级支持。如果用户使用托管Kubernetes产品,那么需要确保服务提供商支持双协议栈。

Kubernetes 1.23是双协议栈的首个非Beta版本,我预计大部分服务提供商需要一定时间才能提供双协议栈支持,进而将其作为受支持的产品提供。

InfoQ: 你们会继续推进IPv4和IPv6地址混用吗?请简单介绍一下双协议栈及相关生态系统的路线图。

Henidak:是的。在Kubernetes双协议栈的设计、实现和测试过程中,这是我们一直坚信的事情之一。不仅是地址的混合,而且还要确保Kubernetes不对IP地址族的排序做任何假设。例如,一些用户更喜欢默认IPv6集群,但能在有需要时支持双协议栈。其他用户可能有不同的偏好。甚至Service API也支持“如可用则使用双协议栈”。这样,开发人员在发布Kubernetes操作符、图表和其他类型规范时,能够以任何他们认为合适的方式表达应用的网络需求。

“路线图”这一方式,是我特别认同的一种社区做法。路线图来自所有参与者的共识,即我们正处于一个永无止境的过程中,总是有更多的事情要做。通常,我们对中长期目标有一个想法,但为应对不断变化的要求或优先事项,我们在计划和执行方面也非常灵活。双协议栈支持是一个重要的里程碑,但它只是我们永无止境的过程中的一个里程碑。我预计近期会有更多的CNI提供商和Ingress控制器支持双协议栈。我希望对双协议栈的支持能扩展到云、负载均衡器和裸机部署。

从长远来看,我看到用户越来越关注多网络和多宿主 Kubernetes Pod,其中一个Pod可能连接到多个网络的多个NIC,一个Pod也能给出来自单个或多个IP地址族的多个地址。这将使网络虚拟设备 (NVA,Network Virtual Appliance) 提供商等重要用例成为可能,并且也能在多集群或多网络环境中很好的工作。

Hockin:澄清一下,这项工作并非是让IPv4客户端与IPv6服务器一起使用,反之亦然。它允许用户表达特定的工作负载可使用任一IP地址族访问服务器,具体取决于用户的需求。它还可以让Kubernetes用户更完整地表达自身的需求。例如,如果用户具有一个双协议栈集群,但希望自己的服务只提供某一种IP地址族。双协议栈支持用户表达此需求,并确切选择所使用的IP地址族,且得到系统其余部分的认同。

这为某些类别的应用开启了大门,特别是面向网络的应用。在此之前,这类问题很难处理,需要深入架构底层。希望大多数用户不会注意或关注双协议栈的存在,但那些真正需要它的人会发现该功能可用,随时可启用。

Kubernetes网络特性的更多详细信息,可访问SIG-NETWORK社区,其中可查看双协议栈实现的相关历史。

原文链接: Kubernetes IPv4/IPv6 Dual Stack Q&A with Khaled (Kal) Henidak of Microsoft & Tim Hockin of Google

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注