本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
Kubernetes 集群中的高性能网络策略
网络策略
自 Kubernetes 1.3 版本于七月发布以来,用户已能够在他们的集群中定义和实施网络策略。这些策略是防火墙规则,用于指定允许进入、传出和 Pod 之间传输的流量类型。如果需要,Kubernetes 会阻止所有未明确允许的流量。策略应用于由通用标签标识的 Pod 组。然后可以使用标签来模拟传统的分段网络,这些网络通常用于隔离多层应用程序中的层:例如,您可以通过特定的“segment”标签来标识您的前端和后端 Pod。策略控制这些段之间的流量,甚至控制进出外部源的流量。
分段流量
这对应用程序开发者意味着什么?Kubernetes 终于获得了提供“深度防御”的必要能力。流量可以分段,并且应用程序的不同部分可以独立地进行安全保护。例如,您可以通过特定的网络策略非常容易地保护您的每个服务:由Replication Controller标识的所有位于服务后面的 Pod 都已由特定标签标识。因此,您可以使用相同的标签将策略应用于这些 Pod。
深度防御长期以来一直被推荐为最佳实践。这种在应用程序不同部分或层之间进行隔离的方法在 AWS 和 OpenStack 上通过将安全组应用于虚拟机很容易实现。
然而,在网络策略出现之前,容器的这种隔离是不可能的。VXLAN 叠加层可以提供简单的网络隔离,但应用程序开发者需要对访问 Pod 的流量进行更细粒度的控制。正如您在这个简单的示例中看到的,Kubernetes 网络策略可以根据来源和出处、协议和端口来管理流量。
apiVersion: extensions/v1beta1
kind: NetworkPolicy
metadata:
name: pol1
spec:
podSelector:
matchLabels:
role: backend
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: tcp
port: 80
并非所有网络后端都支持策略
网络策略是一个令人兴奋的功能,Kubernetes 社区为此付出了长时间的努力。然而,它需要一个能够应用策略的网络后端。例如,简单的路由网络或常用的 flannel 网络驱动本身无法应用网络策略。
目前只有少数支持策略的网络后端可用于 Kubernetes:Romana、Calico 和 Canal;Weave 也表示将在不久的将来提供支持。Red Hat 的 OpenShift 也包含网络策略功能。
我们选择 Romana 作为这些测试的后端,因为它将 Pod 配置为在完整的 L3 配置中使用本地可路由的 IP 地址。因此,网络策略可以直接由主机在 Linux 内核中使用 iptables 规则应用。这使得网络具有高性能且易于管理。
测试网络策略的性能影响
应用网络策略后,需要对照这些策略检查网络数据包,以验证此类流量是否允许。但是,对每个数据包应用网络策略会带来什么性能损失呢?我们能否在不影响应用程序性能的情况下使用所有强大的策略功能?我们决定通过运行一些测试来找出答案。
在我们深入研究这些测试之前,值得一提的是,“性能”是一个很难衡量的东西,网络性能尤其如此。
吞吐量(即以 Gbps 为单位测量的数据传输速度)和延迟(完成请求所需的时间)是衡量网络性能的常见指标。之前已在此处和此处对运行覆盖网络对吞吐量和延迟的性能影响进行了研究。我们从这些测试中了解到,Kubernetes 网络通常非常快,服务器在有或没有覆盖网络的情况下都可以轻松地使 1G 链路饱和。只有当您拥有 10G 网络时,才需要开始考虑封装的开销。
这是因为在典型的网络性能基准测试中,主机 CPU 没有应用程序逻辑需要执行,因此可以用于任何所需的网络处理。因此,我们选择在不会使链路或 CPU 饱和的操作范围内运行测试。这隔离了在主机上处理网络策略规则的影响。对于这些测试,我们决定测量延迟,即通过在一系列响应大小下完成 HTTP 请求所需的平均时间来衡量。
测试设置
- 硬件:两台服务器,配备 Intel Core i5-5250U CPU(2 核,每核 2 线程),运行频率为 1.60GHz,16GB 内存和 512GB SSD。网卡:Intel Ethernet Connection I218-V (rev 03)
- Ubuntu 14.04.5
- 用于数据收集的 Kubernetes 1.3(在 v1.4.0-beta.5 上验证的样本)
- Romana v0.9.3.1
- 客户端和服务器负载测试软件
在测试中,我们让客户端 Pod 向服务器 Pod 发送 2,000 个 HTTP 请求。客户端 Pod 以确保服务器和网络都不会饱和的速率发送 HTTP 请求。我们还通过禁用持久连接(即 HTTP keep-alive)来确保每个请求都启动一个新的 TCP 会话。我们对不同响应大小的每个测试运行,并测量平均请求持续时间(完成该大小的请求需要多长时间)。最后,我们使用不同的策略配置重复每组测量。
Romana 在创建 Kubernetes 网络策略时检测到它们,将其转换为 Romana 自己的策略格式,然后将它们应用于所有主机。目前,Kubernetes 网络策略仅适用于入站流量。这意味着出站流量不受影响。
首先,我们在没有任何策略的情况下进行测试以建立基线。然后,我们再次运行测试,增加测试网络段的策略数量。策略采用常见的“允许给定协议和端口的流量”格式。为了确保数据包必须遍历所有策略,我们创建了多个与数据包不匹配的策略,最后创建了一个会导致数据包被接受的策略。
下表显示了结果,以毫秒为单位测量,适用于不同请求大小和策略数量
响应大小
|策略 |.5k |1k |10k |100k |1M | |---|---|---|---|---| |0 |0.732 |0.738 |1.077 |2.532 |10.487 | |10 |0.744 |0.742 |1.084 |2.570 |10.556 | |50 |0.745 |0.755 |1.086 |2.580 |10.566 | |100 |0.762 |0.770 |1.104 |2.640 |10.597 | |200 |0.783 |0.783 |1.147 |2.652 |10.677 |
我们在这里看到的是,随着策略数量的增加,处理网络策略会引入非常小的延迟,即使在应用 200 个策略后,也从未超过 0.2 毫秒。对于所有实际目的,应用网络策略时不会引入任何有意义的延迟。同样值得注意的是,将响应大小从 0.5k 增加到 1.0k 几乎没有影响。这是因为对于非常小的响应,创建新连接的固定开销在总体响应时间中占据主导地位(即传输相同数量的数据包)。
注意:上图中 0.5k 和 1k 的线条在约 0.8 毫秒处重叠
即使作为基线性能的百分比,影响仍然非常小。下表显示,对于最小的响应大小,最坏情况下的延迟在多达 200 个策略的情况下仍保持在 7% 或更少。对于较大的响应大小,延迟下降到约 1%。
响应大小
策略 | .5k | 1k | 10k | 100k | 1M |
---|---|---|---|---|---|
0 | 0.0% | 0.0% | 0.0% | 0.0% | 0.0% |
10 | -1.6% | -0.5% | -0.6% | -1.5% | -0.7% |
50 | -1.8% | -2.3% | -0.8% | -1.9% | -0.8% |
100 | -4.1% | -4.3% | -2.5% | -4.3% | -1.0% |
200 | -7.0% | -6.1% | -6.5% | -4.7% | -1.8% |
这些结果中另一个有趣之处是,随着策略数量的增加,我们注意到较大的请求所经历的相对(即百分比)性能下降较小。
这是因为当 Romana 安装 iptables 规则时,它确保属于已建立连接的数据包首先被评估。只有对于连接的第一个数据包,才需要遍历完整的策略列表。此后,该连接被视为“已建立”,并且连接的状态存储在一个快速查找表中。因此,对于较大的请求,连接的大多数数据包都通过在“已建立”表中进行快速查找来处理,而不是完全遍历所有规则。这种 iptables 优化使得性能在很大程度上独立于网络策略的数量。
这种“流表”是网络设备中常见的优化,看来 iptables 也非常有效地使用了相同的技术。
同样值得注意的是,在实践中,一个相当复杂的应用程序可能为每个段配置几十条规则。常见的网络优化技术(如 Websockets 和持久连接)将进一步提高网络策略的性能(特别是对于小请求大小),因为连接保持打开时间更长,因此可以从已建立连接的优化中受益。
这些测试是使用 Romana 作为后端策略提供商进行的,其他网络策略实现可能会产生不同的结果。然而,这些测试表明,对于几乎所有应用程序部署场景,都可以使用 Romana 作为网络后端来应用网络策略,而不会对性能产生任何负面影响。
如果您想亲自尝试,我们邀请您查看 Romana。在我们的 GitHub 仓库中,您可以找到一个易于使用的安装程序,它适用于 AWS、Vagrant VM 或任何其他服务器。您可以使用它快速开始使用由 Romana 支持的 Kubernetes 或 OpenStack 集群。