如何解决容器网络性能及复杂网络部署问题?

更新时间:2017-04-14 15:27:22 点击次数:2333次

近两年,容器已经随着 Docker 技术的传播火遍全球,现在已经有越来越多的企业用户在开发、测试甚至生产环境中开始采用 Docker 等容器技术。

然而,目前主流的 Docker 管理平台,比如 K8S,当企业想构建一套网络方案,需要精通 Linux 提供的各种高级网络功能,这个技术门槛太高了。特别是对专注于业务开发的 Docker 用户而言,这类操作往往显得过于复杂。

而且,由于在虚机中部署容器,云平台和 Docker 平台都有自己的虚拟化网络实现方案,二者功能重叠,使用时会相互嵌套,导致的其网络性能损耗非常严重,甚至达到 80%。

所以,虽然容器技术正在逐步被大家认可与应用,但其网络性能以及配置的复杂程度一直都在被大家所诟病。今天的内容,将会给大家介绍一种容器部署方案,帮助大家解决网络这个难题。

Docker的网络模型架构

首先,我们先看看 Docker 提供了哪些网络功能,Docker 的网络模型是这样的:

图片描述

Docker 的网络结构分为 3 个层次:Network、Endpoint 和 Container。对比到物理设备可以这么理解:Network 是交换机,Endpoint 是网卡,Container 就是服务器。

决定 Network 这个交换机的工作方式的组件,就是 Network Driver。常用的 Driver 有两个:

Bridge Driver

Bridge Driver 是种比较直接的方式:Bridge 指的是 Linux Kernel 实现的虚机交换机。每个网络在宿主机上有一个 Bridge 实例,默认是 Docker0,有对应的 IP 地址和网段,每个 Docker 实例从网段里面分配一个地址。结构如下:

图片描述

在同一个 Bridge 下的 Endpoint 是一个二层网络,要实现跨宿主机的 Endpoint 之间通信,只能走三层网络,也就是通过路由转发过去。要对外提供服务,还需要对宿主机的 IP 端口做转换(Nat)。这种情况下主要网络性能损失发生在端口转换(Nat)和路由上面。

同时这也和青云 SDN 1.0 里面的基础网络实现方式是完全一样,优点是结构简单可靠,缺点也很明显: 不能把多个宿主机连成一个二层网络。这个问题会导致 Docker 实例的 IP 地址,必须跟当前宿主机定义的网段一致。如果启动到别的宿主机上,IP 就需要更换。

Overlay Driver

Overlay Driver 的作用是把位于多个宿主机的 Docker 实例连接在一个虚拟的二层网络里面。相比 Bridge,在功能上有一定进步,本质上是一个分布式的虚拟交换机。

举个送快递的例子,方便大家理解:有的公司对员工提供内部邮件的服务,位于不同写字楼的员工可以用工位号互发邮件。公司的收发室拿到邮件后,会重新再打个包,上面写着双方写字楼的地址,交给真正的快递公司去投递。收件方的收发室会拿到邮件后,会拆掉外面的信封,把里面的邮件按工位号送给收件的员工。

这例子里面,工位号就是 Underlay 的地址, 写字楼的地址是 Overlay 的地址。Docker 的这个虚拟二层网络,就是企业内部邮件,但是真正派件的还是快递公司。跟普通快递相比,多了个环节:收发室对邮件重新包装,不仅打包费时间,多的包装也占了重量,也就带来了额外的性能损失。

目前,Overlay 模式的虚拟网络应用已经很普遍,青云给用户提供的虚拟二层网络也是相同的工作原理。

容器的部署方式

Docker 目前有两种方式部署:

今天和大家分享的就是为什么要在云平台上部署 Docker。

虽然看起来在公有云的虚拟机部署 Docker 的做法比较奇葩,目前也没有公有云能让用户直接部署 Docker 在物理机上,当然,Softlayer 这种物理机托管的云除外。

因为 Docker 本身的安全性还不够让人放心。虽然 Docker 已经有各种安全保护,包括 Namespace 提供的隔离机制、Selinux、Apparmor 等安全机制,以及近才有的Unprivileged Container 功能来控制 Docker 实例在宿主机上的用户权限,但是由于容器的本质是跟宿主机共用同一个 Linux Kernel,一旦 Kernel 本身有安全漏洞,就有可能被 Docker 用户利用,侵入到云平台的物理机。

比如几个月前发现的 COW 漏洞,就有可能让 Docker 实例获得物理机的 Root 权限,实现容器的“越狱”。这个漏洞存在了十几年才被人发现,完全有可能还有很多类似漏洞存在,只是没有被公开而已。

所以,公有云直接让用户在多租户的物理机上运行 Docker,是极不安全的做法。

因此,要在公有云使用 Docker,就只有在虚拟机里面运行 Docker 这一个选择。那么在公有云上部署 Docker 业务,存在哪些问题呢?其实,主要还是性能和功能两方面。

网络性能

网络虚拟化的本质是用软件实现物理网卡和交换机的功能,因此虚拟网络中的所有流量都会消耗 CPU 资源。

Linux 在处理网络流量时,有几个方面会消耗 CPU:

  1. 地址转换(Nat);
  2. 三层路由转发;
  3. Vxlan 封装;
  4. 二层转发;
  5. 虚拟机的 Kernel 和宿主机 Kernel 之间的转发。

其中 1 和 2 占的 CPU 消耗较高,这是因为地址转换和路由都会对数据包的包头做修改,并重新计算 Checksum, 而且地址转换还需要查询 Conntrack 的连接表和 IPtables 的地址转换规则,这些功能都是全靠宿主机的 CPU 完成。

云平台提供的 SDN 网络,是层网络虚拟化,已造成一定的性能损失。但是可以通过利用物理网卡的硬卸载功能,比如 Vxlan Offload, 具体包括 Gso、Gro、Rx Checksum 等在这一层减少虚拟化带来的部分性能损失。

虽然容器本身由于跟宿主机共享 Kernel 的这个特性,相比 VM 网络性能更好,没有 第 5 条的损失,但是 Docker 搭建的虚拟网络,仍然会带来显著的性能损失。

同时,由于第二层虚拟化无法利用硬卸载功能,所以性能损失通常会高于层。两层网络虚拟化带来的性能损耗相叠加,将显著影响网络性能。

举个例子:

在上海一区(SH1A),使用 IPerf -C 命令进行的基本性能测试 (关闭云平台的网络限速)结果如下: 
虚拟主机之间:带宽 9Gbps; 
虚拟主机内:使用 Docker Overlay 插件的 Docker 实例之间带宽下降为 2.3 Gbps。

由此可见,这种使用 Docker Overlay 的方案会带来近 3/4 的性能损耗。而如果算上对外提供服务所需要的地址转换带来的性能损失,整体性能损失将更为巨大。

配置复杂

首先,Docker 自身的网络复杂。Bridge 和 Overlay 都需要配合地址转换功能使用,而地址转换的规则不仅多,而且复杂。

我近遇到个私有云客户,其在云平台上面部署基于 K8S 的业务系统。他们遇到一个问题,同一个宿主机的 Docker 实例之间,用 K8S 提供的业务 IP 无法访问,而不同宿主机之间用相同的 IP 访问正常。

这个开发团队,通宵加班好几天,也没搞清楚怎么回事,来找我帮忙解决。这个问题实际上是因为 K8S 少下发了一条 IPtables 规则,没有对同宿主机的这种情况做源地址转换。

这个问题对熟悉 Linux 网络功能的人来说,不是什么难题,但是对专注于业务开发的 Docker 用户而言,可就很难解决了。

我说这个例子的目地就是要说明,配置 Docker 虚拟网络是件难度很高的事情。

另一方面,要在云平台上面,使用 Docker 对外提供服务,还需要跟云平台的网络做整合。

通常是在云平台的 IP 和 Docker 的 IP 之间做地址转换。本身 Docker 实现这些功能就比较复杂,而在此基础上,再做一层地址转换,会带来额外的复杂度。

使用 Docker 管理平台的初衷是简化产品部署,而通过这样的方式跟云平台整合,却与这一方向背道而驰。

如何解决容器网络性能及复杂网络部署的问题

性能问题的根源在于云平台和 Docker 平台都有自己的虚拟化网络,二者功能重叠,使用时相互嵌套。而配置复杂的难度一个是 Docker 自身网络复杂,另一个方面是跟云平台的网络整合也复杂。

目前青云的 SDN 直通方案通过让 Docker 实例挂载云平台提供的虚拟网卡的方式,让 Docker 实例直接使用云平台的 SDN 功能,代替 Docker 的虚拟网络。

一方面减少了第二层虚拟网络的性能损失;另一方面,云平台的 SDN 是通过 API 和控制台封装好的服务,Docker 直接使用就可以了,不需要自己再配置 Docker 的网络,所以大幅降低了使用难度。

SDN 网络直通方案包含两个方面:

插件已经开源,地址是 https://Github.Com/Yunify/Docker-Plugin-Hostnic

这是青云Qingcloud 自主开发的一款 Docker 网络插件。在启动 Docker 实例的时候,通过该插件,可以将虚拟主机上的绑定的多个网卡一一挂载到 Docker 实例上, 并可以配置 IP 地址和路由。

启动之后,Docker 实例就加入了云平台 SDN 提供的网络,能够使用云平台所有的网络功能。云平台网卡管理,就是能够让虚拟主机挂载多个网卡。网卡对应到 Docker 的网络组件,就是Endpoint,这个设备受云平台管理,底层由 SDN 内部的控制器下发规则,可以使用 DHCP 管理 IP 地址,并接入所有云平台的网络模块。

相比 Docker 的网络功能,青云的网卡可以提供更多的功能:

VPC

前面说过,Docker 的 Overlay 网络实际上是虚拟的二层网,而 VPC 提供的是一个虚拟的三层网。可以理解为一个分布式的核心交换机。青云的 VPC 多可以创建 252 个虚拟网络,容纳超过 6 万台虚拟主机。

就技术上来看,虚拟二层网使用 Vxlan 实现,是现在较成熟的技术。而虚拟的三层网,是 SDN 技术的一个关键点,因为它背后需要有个分布式网关才能做到虚拟机数量增加时,VPC 整体网络性能不变。

目前 SDN 厂商和技术好的云计算公司都有各自的实现,还没有看到靠谱的开源产品能够做到。

当 Docker 挂载上青云的网卡时,就加入了对应的 VPC,跟其他实例连在了一起。用户可以根据网卡对应的网络来定义实例间是二层还是三层联通。

公网 IP

每个网卡可以绑定自己独享的公网 IP,也可以使用 VPC 共享的公网 IP 对外提供服务。公网和私网地址的转换,由云平台的分布式网关来做,不需要 Docker 配置任何 IPtables 规则。

负载均衡器

网卡可以作为负载均衡器的后端,以集群的方式,对外提供高可用和高性能的服务。相比 Docker 的负载均衡器,青云的负载均衡器有许多优点:

给虚拟主机挂载网卡之后,需要使用到 Hostnic 插件,有 3 步:

  1. Docker-Plugin-Hostnic 是个 Docker 像,把它启动成 Docker 实例,效果就是加载了一个叫 Hostnic 的 Docker 网络插件;
  2. 创建 Docker 网络。比如:Docker Network Create -D Hostnic –Subnet=192.168.1.0/24 –Gateway 192.168.1.1 Hostnic,其中网段和网关是网卡在 VPC 对应的网络的属性;
  3. 启动 Docker 实例,传入网卡对应的 Mac 和 IP 地址。比如: Docker Run -It –Ip 192.168.1.5 –Mac-Address 52:54:0E:E5:00:F7 –Network Hostnic Ubuntu:14.04 Bash。

这样就完成了对 Docker 实例网络的所有功能配置。

前面说的公网 IP、负载均衡器和防火墙,都可以通过青云控制台、SDK、 CLI 或者 API 的方式去单独配置。对这些功能使用上有疑问的话,可以通过工单跟我们的工程师沟通,不必在死磕 Docker 那些复杂的网络配置。

除了青云自己研发的 Hostnic,现在已经有另外一款 Docker 插件支持青云 SDN 直通。是希云Csphere 开发的 Qingcloud-Docker-Network,同样也已经开源: Https://Github.Com/Nicescale/Qingcloud-Docker-Network 。

跟 Hostnic 相比,这款插件整合了青云 API,能够在启动 Docker 实例时,自动创建,并绑定网卡,使用起来更方便一些。

对于公有云,目前只能选择在虚拟主机里面使用 Docker,但是对于私有云,可以在青云提供的容器主机里面部署 Docker。

容器主机的工作原理跟 Docker 一样,都是用到了 Linux Kernel 的容器技术,但是用起来更接近虚拟主机,有着几乎相同的功能,比如:挂载 SSH 密钥、Web Terminal、镜像制作、备份等功能,跟虚拟主机镜像全兼容,还能做到在线扩容 CPU、内存、系统硬盘。

也就是说,对于私有云用户,可以使用跟公有云虚拟主机完全一样的操作方式,在容器主机里面部署 Docker,从而减少 KVM 虚拟化这一层在性能上的损失,能达到接近物理机的性能。

跟直接在物理机上部署 Docker 相比,使用容器主机可以有云平台便捷的功能,比如秒级创建或者消毁一个容器主机。云平台的副本可以保证物理机宕机后,通过离线迁移,迅速恢复业务。再加上前面说的这些云平台的网络功能,为构建用户业务集群,节省大量时间。同时青云的 SDN 网络在 Linux Kernel 上有深度优化,相比直接在物理机上使用 Docker 的 Overlay 网络性能还会好不少。

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!