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

2022-03-23 13:55:27 浏览数 (1)

作者 | 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 社区,其中可查看双协议栈实现的相关历史。

原文链接:

https://www.infoq.com/news/2021/12/dual-stack-kubernetes/

0 人点赞