基于容器的虚拟化是一种虚拟化技术。与虚拟机 (VM) 相比,容器更轻量级,部署更方便。Docker是目前主流的容器引擎,支持Linux、Windows等平台,以及Kubernetes(K8S)、Swarm、Rocket(RKT)等主流Docker编排系统。常见的容器网络支持多种模型,如桥接网络、Overlay网络、Host网络和用户自定义网络。K8S 等系统依靠容器网络接口 (CNI) 插件进行网络管理。常用的 CNI 插件包括 Calico 和 Flannel。
本文九河云将介绍容器网络的基础知识。ECS容器网络基于阿里云弹性网卡(Elastic Network Interface,简易)技术,具有高性能、易部署易维护、隔离性强、安全性高等特点。
传统集装箱网络解决方案
本节介绍传统容器网络的工作原理。
CNI 是由云原生计算基金会 (CNCF) 管理的开源项目。它为各大厂商制定标准并提供源码库,以开发用于 Linux 容器网络管理的插件。著名的 CNI 插件包括 Calico 和 Flannel。Calico 通过 Flex/Bird 实现 BGP 等协议,并将其存储到分布式内存数据库中,以建立大型的 Layer 3 网络,使不同主机上的容器无需发送 ARP 即可与不同子网上的容器进行通信。
Flannel 实现了基于 VXLAN 等隧道技术的容器覆盖网络。Calico/Flannel 等 CNI 使用 VETH 对来配置容器网络。将创建一对 VETH 设备,其中一端绑定到容器,另一端绑定到 VM。虚拟机通过网络协议栈(覆盖网络)、Iptables(Calico 插件)或 Linux Bridge 等技术转发容器网络。(当容器网络在ECS中通过网桥连接到交换机时,VPC只能到达ECS级别,容器网络是网桥上的内网。
下图显示了目前主流容器网络的工作流程,它与多网卡容器网络的不同之处体现在以下几个方面:
- 主机 1 上的容器发送的消息通过 VETH 传输到虚拟机上的 Linux 网桥,Linux 网桥运行转发逻辑,将消息虚拟机上的网卡发送到主机上的交换机。
- 主机 2 上的虚拟机接收 vSwitch 发送的消息,并使用 Linux Bridge 的转发逻辑通过 VETH 将其发送到容器。
在整个网络系统中,虚拟机内部需要 K8S 等编排系统的 CNI 插件进行网络配置。交换机支持 Openflow 和 Netconf 等通信协议,这些协议通过软件定义网络 (SDN) 控制器进行管理和配置。主流ToR交换机使用Netconf协议进行远程配置。支持Openflow的SDN物理交换机也已上市。
为了管理整个网络,需要两个不同的网络控制系统。配置相对复杂,由于实现机制等因素,存在一定的性能瓶颈。主机上的安全策略不能应用于容器应用程序。
多网卡容器网络
当 VM 具有多个动态热插拔的网络接口卡 (NIC) 时,可以在容器网络上使用这些 NIC,因此容器网络将不再需要使用 Linux VETH 和 Bridge 等技术。同时,将消息转发到主机上的虚拟交换机(vSwitch),通过简化流程提高网络性能。
解决方案概述
如下图所示,主机上正在运行一个交换机,用于转发来自虚拟机和容器的流量。多个虚拟网卡连接到交换机。在虚拟机上启动容器时,虚拟网卡会动态绑定到主机上容器所在的虚拟机,然后虚拟机内部的网卡绑定到容器所在的网络命名空间,容器中的网络流量可以通过网卡直接发送到主机上的交换机(即 容器网络可以直接连接到交换机)。
在交换机中应用ACL、QoS、Session等规则进行流量转发。当主机 1 上的 VM 上运行的容器访问主机 2 上的 VM 上运行的容器时,流量通常会经过以下过程:
- 网络消息通过容器核心网络协议栈。查询路由后,消息通过eth0网卡发送。
- 主机上的交换机通过虚拟端口接收来自容器的消息,并运行交换机的转发逻辑,通过物理网口将报文发送到架顶式交换机。如果为容器或虚拟机网络建立了 Virtual Private Cloud (VPC),则需要使用 VXLAN 等隧道技术对消息进行封装。
- ToR 交换机通过连接到主机 2 的物理端口查询路由并转发消息。
- 主机2上的交换机接收到物理端口消息,通过转发逻辑发送到连接容器的虚拟端口。
- 容器中的协议栈 eth0 接收另一端发送的消息,然后由容器中的网络协议栈处理该消息。
方案特点
相较于传统容器在虚拟机上运行的方案,该方案具有高性能、易管理、隔离性强等特点。
直连VPC
多网卡方案允许容器直接访问VPC网络面,使每个容器都能提供完整的VPC网络功能,包括EIP、SLB、DDoS高防、安全组、HAVIP、NAT和用户路由。
跨VPC
通过多网卡方案直接访问VPC网络面的容器,可以使用VPC的一些高级功能,如对等功能。跨VPC弹性网卡也可用于访问云产品,不同VPC内的多个网卡可以分配给容器。这确保了容器可以跨多个 VPC 使用。
高性能
在多网卡解决方案中,容器中的网络流量不需要通过虚拟机上的 Iptables/Bridge 转发,而是直接转到主机上的交换机。这样就省去了虚拟机上的数据消息转发逻辑,简化了数据复制过程,大大提升了容器网络的性能。下表列出了不同解决方案在单次测试中的基本性能数据。
|-----------|------------|-----------|-----------|--------------------|
| | 单线程 (Mbps) | 单线程 (pps) | 多线程 (pps) | TBase测试 1 KB (QPS) |
| Linux 桥接器 | 32.867 | 295,980 | 2,341,669 | 363,300 |
| 多网卡解决方案 | 51.389 | 469,865 | 3,851,922 | 470,900 |
| 性能改进 | 56.35% | 58.7% | 64.49% | 29.6% |
强隔离
在传统的桥接方案中,所有容器实例都位于同一个大型二层网络上,导致广播、组播和未知单播泛滥。多网卡方案提供的直连功能,以及ECS网络提供的ACL和安全组功能,可以有效保障安全隔离。即使在容器的管理面上也无法查看容器网络流量。安全规则应用于容器级别,而不是 VM 级别。
易于管理
当管理系统将容器分派到虚拟机时,控制系统会在虚拟机所在主机的交换机上创建一个网卡,通过热插拔将网卡插入虚拟机,并将网卡配置到虚拟机上的容器网络命名空间中。通过配置交换机的流量转发规则,然后在xGW上配置HaVIP,外部应用和客户端可以访问容器提供的服务。
多网卡解决方案还有助于容器迁移。以另一台迁移到同一台主机的虚拟机为例,K8S 的 Kubelet 模块迁移应用,然后通过 CNI 插件重新配置网络,管理容器 IP 和 VIP,并配置访问容器应用的方式。整个过程很复杂,但 NIC 解决方案可以使它变得简单。将容器分派到 VM 后,绑定到旧容器的 NIC 将从旧 VM 中拔出,并插入到新容器所在的 VM 中。然后,将 NIC 绑定到 VM 上的容器网络命名空间。新容器可以正常通信,无需再重新配置网络。
DPDK 支持
由于其优越的性能优势,DPDK已经普及,越来越多的应用是基于DPDK开发的。传统的容器网络使用VETH作为网络设备,目前无法直接使用DPDK的PDK驱动,因此基于DPDK的应用不能直接在容器中使用。在多网卡方案中,容器使用ECS网络设备,即常见的E1000或virtio_net设备。两台设备都有一个 PMD 驱动程序,容器可以使用该设备直接运行基于 DPDK 的应用程序,从而提高容器内应用程序的网络性能。
VM 多 NIC
要启用物理主机的跨域,您需要在物理机中插入多个网卡。由于 PCI 插槽和成本的限制,在一台物理机上部署两个以上的 NIC 的情况很少见。打开或关闭硬件设备的电源或多或少会给整个系统增加脉冲,从而影响机器的稳定性,并限制设备的热插拔。常见的热插拔设备是 USB 设备。PCI 设备的热插拔直到最近几年才获得限制性支持,因为需要两个枚举和电源效应。
在虚拟环境中,虚拟网卡的低成本和灵活性大大提高了虚拟机的可用性。用户可以根据需要动态分配或释放网卡,在不影响虚拟机正常运行的情况下,动态地将网卡插入或拔出虚拟机。libvirt/qemu 模拟虚拟设备的方式具有物理主机无法比拟的以下优势:
资源限制
只要系统有足够的内存等资源,就可以模拟多个网卡,并将它们分配给同一个虚拟机,一个虚拟机上可以安装64个甚至128个网卡。与物理硬件环境相比,软件模拟 NIC 的成本要低得多。它们还具有更好的支持多队列和主流硬件的一些卸载功能,提高了系统的灵活性。
动态热插拔
VM 上的 NIC 由软件模拟。因此,当需要网卡时,软件会分配一些基础资源来模拟网卡。热插拔框架使 libvirt/qemu 能够轻松绑定到正在运行的 VM 上,并且 VM 可以立即使用 NIC 发送网络消息。当不再需要 NIC 时,可以通过 libvirt/qemu 接口调用将其"拔出",而无需停止 VM。分配给 NIC 的资源被销毁,分配给 NIC 的内存被回收,中断被恢复。
容器网络实施
本节介绍如何使用虚拟机多网卡逐步实现容器网络通信。
-
在阿里云控制台创建云主机,创建实例时选择多个网卡。然后,VM 上会显示多个 NIC。
-
在 VM 上部署容器应用程序。
`~# docker run -itd --net none ubuntu:16.04`
注意:启动 Docker 时,将容器的网络类型指定为 none
-
登录到 VM,并将其中一个 NIC 绑定到容器命名空间。在以下示例中,新动态插入的 NIC 是 eth2,容器的网络命名空间是 2017(为澄清起见,docker inspect 看到的 PID 用作网络命名空间)。
`~# mkdir /var/run/netns ~# ln -sf /proc/2017/ns/net /var/run/netns/2017 ~# ip link set dev eth2 netns 2017 ~# ip netns exec 2017 ip link set eth2 name eth0 ~# ip netns exec 2017 ip link set eth0 up ~# ip netns exec 2017 dhclient eth0`
注意:根据发布版本,用户可能不需要通过手动创建连接来"创建"容器的网络命名空间。将 eth2 绑定到容器的网络命名空间后,将其重命名为 eth0。
-
查看 VM 和容器中的 NIC 配置状态。
检查 VM 上是否仍存在 NIC。`~# ifconfig -a`
检查容器中是否有新配置的网卡。
`/# ifcofig -a`
可以看出,eth2 已从虚拟机中移除并应用到容器中。
-
重复步骤 1 到 4 以启动另一个 VM 和容器。
-
使用 sockperf 等工具进行性能测试和比较。
``$ cat server.sh #!/bin/bash for i in $(seq 1 $1) do sockperf server --port 123`printf "%02d" $i` & Done $ sh server.sh 10 $ cat client.sh #!/bin/bash for i in $(seq 1 $1) do sockperf tp -i 192.168.2.35 --pps max --port 123`printf "%02d" $i` -t 300 & done $ sh client 10``
蚂蚁金服使用案例
Tier-Base (TBase) 是一个类似于 Redis 的分布式 KV 数据库。它是用 C++ 编写的,支持几乎所有的 Redis 数据结构。它还支持 RocksDB 作为后端。TBase在蚂蚁金服中应用广泛。本节将介绍该方案的 TBase 业务测试。
传统 Linux 桥接测试
测试环境
服务器:16C60G x 1(半个A8)
客户端:4C8G x 8
TBase 服务器部署:7G x 7 实例
TBase 客户端部署:8 x(16 个线程 + 1 个客户端)=> 128 个线程 + 8 个客户端
检测报告
|--------|-----------|--------|----------|---------|-----------|----------|-----------|-------------|
| 操作 | 数据包大小 | 客户 | 网卡 | 负载1 | 中央处理器 | PP2型 | 平均 rt | 第 99 RT |
| 设置 | 1 KB | 8 | 424兆字节 | 7.15 | 44% | 363,300 | 0.39 毫秒 | < 1 ms |
| 获取 | 1 KB | 8 | 421兆字节 | 7.06 | 45% | 357,000 | 0.39 毫秒 | < 1 ms |
| 设置 | 64 KB | 1 | 1,884兆字节 | 2.3 | 17% | 29,000 | 0.55 毫秒 | < 5 ms |
| 设置 | 128 KB | 1 | 2,252兆字节 | 2.53 | 18% | 18,200 | 0.87 毫秒 | < 6 ms |
| 设置 | 256 KB | 1 | 2,804兆字节 | 2.36 | 20% | 11,100 | 1.43 毫秒 | < 5 ms |
| 设置 | 512 KB | 1 | 3,104兆字节 | 2.61 | 20% | 6,000 | 2.62 毫秒 | < 10 ms |
弹性网卡多网卡测试
测试环境
服务器:16C60G x 1(半个A8)
客户端:4C8G x 8
TBase 服务器部署:7G x 7 实例
TBase 客户端部署:16 x(16 个线程 + 1 个客户端)=> 256 个线程 + 16 个客户端
检测报告
|--------|-----------|--------|--------|---------|-----------|----------|-----------|-------------|
| 操作 | 数据包大小 | 客户 | 网卡 | 负载1 | 中央处理器 | PP2型 | 平均 rt | 第 99 RT |
| 设置/获取 | 1 KB | 16 | 570兆字节 | 6.97 | 45% | 470,900 | 0.30 毫秒 | < 1 ms |
测试结论
基于弹性网卡多网卡方案,整体性能提升,时延明显缩短(QPS提升30%,平均时延降低23%)。假设使用16C60G服务器,QPS在470左右。在本例中,平均 rt 为 900.0 ms,第 30 个 rt 小于 99 ms。 用户、sys、si 和 st 分别消耗了 1%、45%、29% 和 18% 的 CPU。与 Linux Bridge 相比,多 NC 解决方案的 CPU 消耗显著降低。通过内核队列分散,将 st 的 CPU 消耗分布在多个不同的内核上,使处理资源使用更加均衡。
对于VPC路由表Flannel/Canal的解决方案,在带宽和吞吐量上没有实质性的损失。相对于主机,延迟约为 0.1 毫秒。使用Nginx测试QPS,页面较小时损失在10%左右。对于弹性网卡方案,相对于主机,带宽和吞吐量没有实质性的损失,延迟略低于主机。在应用测试中,性能比主机网络上的性能高出 10% 左右,因为 POD 没有受到 iptables 的约束。对于默认的 Flannel VXLAN,带宽和吞吐损失约为 5%,而在 Nginx 小页面测试的最大 QPS 下,相对于主机,性能损失约为 30%。
总结
本文介绍一种基于虚拟机多网卡热插拔的容器网络解决方案。通过动态热插拔虚拟机的网卡并将其应用于容器中,用于发送和接收容器网络数据消息,并通过虚拟机上运行的虚拟软件交换机转发网络消息,大大降低了容器网络管控系统的复杂度,提高了网络性能,增强了容器网络安全性。