Docker容器技术的实现依赖于Linux Container的一些核心技术,通过Cgroups和Namespace等技术实现资源和环境的隔离。其组件架构图如图6-15所示。
图6-15 Docker组件架构图
Docker容器主要由五个重要组件构成:Docker客户端、Docker守护进程、Docker底层驱动程序、Docker镜像文件和镜像仓库。
Docker客户端用于向Docker守护进程发送容器操作请求。
Docker守护进程作为Docker容器功能中的核心部分,可以接受来自上层Docker客户端的请求,然后交由Docker实际的引擎Engine来进行处理,根据请求内容的不同,可以以此开放不同类别的处理器进行处理。
底层驱动程序按照实际功能类型区分可以分为执行驱动、网络驱动和镜像驱动。其将上层传递来的格式化命令转译为统一的操作系统级函数调用,从而由底层处理器完成对容器的创建和管理。
Docker镜像是一个只读文件,它是Docker如何运行的主要参考,每一个镜像都在不同的时间由各种配置层相互叠加而成。如果有新的需求到达,需要配置和修改相应的文件,则在原有的Docker镜像文件上进行操作配置层的叠加即可生成新的镜像文件。
Docker仓库是用来保存镜像文件的代码仓库,可以分为公有仓库Docker Hub和各类私有仓库。
(2)部署Docker容器及虚拟网络功能
在虚拟网络功能的部署上,选择Nginx这一业内常用的负载均衡软件作为VNF来部署在Docker容器中。
第一步,在根目录下需要创建Nginx目录,用来存放相关配置文件;
第二步,进入创建好的Nginx子目录,手动编写新的Dockerfile文件,其配置文件效果如图6-16所示。
图6-16 创建新的Nginx Dockerfile
第三步,通过已经创建好的Dockerfile来创建一个镜像文件;
第四步,利用已有的包含Nginx功能的镜像文件创建容器,其创建方式如图6-17所示。
图6-17 启动Docker
其中,-p 80:80,表示在物理宿主机的80端口和新创建的Docker容器的80端口之间构建映射;
--name NFV_Nginx:表示将新创建的容器命名为NFV_Nginx;
-v$PWD/docker:/docker:表示将主机中当前目录下的docker目录挂载到新创建的NFV_Nginx容器下的/docker文件目录下;
-v$PWD/conf/nginx.conf:/etc/nginx/nginx.conf:表示将主机中当前目录下的nginx.conf挂载到容器的/etc/nginx/nginx.conf;(www.xing528.com)
-v$PWD/log:/nfv_logs:表示将主机中当前目录下的log挂载到容器的/nfv_logs目录下。
至此,一个运行着Nginx负载均衡器的Docker容器即已创建完成。创建完成后运行启动命令成功,运行相关命令查看可以看到运行着Nginx网络功能的容器进程已经开始启动,启动结果如图6-18所示。
图6-18 查看Docker启动效果
(3)优化Docker网络连接
当在一台物理服务器上部署多个Docker容器构建服务功能链时,需要合理规划容器间的网络连接,才能使Docker容器的性能得到最大化的利用。
Docker容器默认的网络通信一般分为五种模式,分别为bridge模式、host模式、none模式、其他容器模式以及用户自定义模式。其中bridge模式是为容器新建立一个独立的Namespace,该容器具有独立的网卡以及独立的网络协议栈,通过与宿主机端口绑定来实现与宿主机通信,通过系统下自带的Linuxbridge实现容器间的通信;host模式是直接使用物理宿主机的Namespace,这种模式下宿主机的IP地址即为容器的IP地址,容器可以将网卡挂载到宿主机的物理网卡上;none模式可以为容器创建一个新的独立Namespace,但是并不做任何配置,容器只有I/O进程,无法与宿主机或者其他容器进行网络通信;其他容器模式可以是的多个容器共享一个Namespace,这些具有共享Namespace的Docker容器之间不具有网络隔离性,但他们与宿主机之间网络仍然具有隔离性;用户定义网络模式可以使用任何Docker支持的第三方网络驱动来对容器的网络进行定制。
部署于Docker容器中的虚拟网络功能有可能是通过单独的应用对外提供服务的,也可能是与部署于其他容器中的虚拟网络功能连接,构建服务功能链来共同对外提供服务。当Docker部署在运行着Linux操作系统的通用服务器上,其默认的网络连接方式是通过Linuxbridge。传统创建容器网络的时候,当一台NFV服务器需要部署多个Docker容器来构造服务功能链时,最简单的网络架构连接方式如图6-19所示,可以使用一个网桥将所有的容器连接在一起,容器之间通过这个网桥进行通信。
图6-19 使用一个Linux bridge来构建网络
当需要容器或者虚拟机运行在网络功能虚拟化场景下时,需要满足NFV数据包高速的需求。而Linuxbridge在接收到来自物理网卡的数据包后,需要向Docker容器进行数据包的转发时,会涉及大量的用户态内核态上下文切换和数据包的拷贝,这造成了极大的性能损耗。根据第三章的对比结果,我们可以看到DPDKOVS和NetMap两种软件交换机效果较好,而DPDK-OVS构建网络时,使用虚拟I/O接口针对虚拟机而言更加合适,所以我们选用NetMapVALE软件交换机来实现数据平面,构建Docker容器网络。
同时,在每个Docker容器之间,如果仅仅是采用一个Linuxbridge来进行数据包的转发,那么如果根据上层需要,部署在宿主机内的容器数目需要进行增加,就需要对进入到用户空间,对这个Linuxbridge进行端口的增加和对MAC地址-端口映射表的修改。当映射表内容过多时,会造成查询访问效率下降,从而导致转发性能下降。为此,我们针对这一情况提出了改进方案。为了提高Docker容器间数据包的转发性能,可以在服务器允许的情况下,在每两个Docker容器之间创建一个Linuxbridge,这个Linuxbridge只负责二者之间的数据包转发。当需要新建容器时,在与其向邻的Docker容器之间再新建一个Linuxbridge并设定相关转发规则即可。
因此,在构建宿主机内部的Docker容器网络时,采用了如图6-20所示的方法。
图6-20 改进后的容器网络
优化后的容器网络设计可以有效地提高了具有通信关系的容器两两之间的数据包拷贝效率问题,解决了因为服务功能链过长带来的查询端口效率低下带来的性能问题。但该方案仍然具有瓶颈,原因在于容器间的通信关系并非固定,由于容器具有简单易部署的优点,其新建容器和删除容器动作十分频繁,当单服务器内网络规模较大时,这给网桥管理带来了极大的不便。
为有效改善这以瓶颈,这里提出使用共享内存的字符设备来实现容器间网络数据包转发,这样既解决了多网桥的管理复杂问题,也避免了在网桥中数据包的频繁拷贝问题。我们在每一条服务功能链上使用一个共享内存的字符设备来作为一个缓冲池,当服务功能链上的第一个虚拟网络功能从NetMap数据面接收到网络数据包后,将这个数据包写入整个功能链共用的缓冲池中,后续的容器直接使用接收到的缓冲池地址即可对查询到数据包并对其进行操作。容器间通信采用进程间通信方法,使用环境队列传递消息,通过传递包缓冲区的偏移地址来进行数据包的传递。优化后的容器网络设计如图6-21所示。
图6-21 使用共享内存的容器网络
实现基于共享内存的容器间通信,首先要实现一个字符设备,再申请一块内存区域,并将其视作一个字符设备以供数据包保存。在实现过程中,关键的步骤是实现mmap()函数,使字符设备中的内存地址可以和容器进程中的虚拟地址互相映射。其实现关键步骤如图6-22所示。
图6-22 字符设备实现mmap函数主要过程
至此,基于Docker容器的网络功能虚拟化平台即已搭建完毕。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。