领科云基于Mesos和Docker的企业级移动应用实践分享


本文由李加庆根据2016年1月24日@Container容器技术大会·北京站刘超的演讲《领科云基于Mesos和Docker的企业级移动应用实践分享》整理而成。
1.png

相对于普通的应用,移动应用更具复杂性。如上图,手机能连接到智能硬件,智能硬件对于手机端看来是一个 WIFI,其实它是个 MIFI,所谓 MIFI 后端连接的是 3G、4G 网络,手机通过 3G、4G 网络连接到控制与业务逻辑进行认证和鉴权,必须是合法的用户才能使用流量。当认证和鉴权通过后,及建立了数据通路,就会有数据流量转发,是通过转发网关进行的,转发网关部署在 Linker 的数据中心,通过转发网关进行转发的流量可实现流量的共享、流量的赠与以及流量的免流等。用户手机访问互联网,访问日志会进入大数据平台。这个架构类似于 3G/4G LTE 网络架构,只是经过简化,没有什么 SGWPGWMMEHSS 等。简化后的架构可应用于 IOT 即物联网、车载网这种场景。此类场景会导致我们的应用非常复杂,牵扯到各种各样的东西。首先要有手机连接智能硬件,另外我们业务逻辑使用 JAVA 开发,其次,考虑高吞吐量、高并发,转发网关使用C进行开发,最后大数据平台原来是用 Hadoop,现在改用 Spark,支持实时的数据处理。

如此类复杂的应用进行容器化,会有很多问题。在 Docker 化之前所有东西都是部署在 VM上 的。因为微服务化以及 Docker 化会使得应用更加轻量级、高性能、易部署,于是我们要将应用迁移至Docker,就会遇到一些挑战,例如 JAVA 平台高可用、高并发怎么做?程序宕机后如何自修复?Hadoop、Spark 如何复用数据中心资源?(Spark是用于处理实时的数据流,而 Hadoop 是批量处理数据,原来两个集群是分开部署的)。转发网关要求提供更高的吞吐量,容器如何实现?最具挑战的是智能硬件的远程更新与维护,因为硬件一旦发给客户,就无法收回更新。上述便是我们面临的应用复杂性,解决这些问题最终的思路是 Docker everywhere 容器无处不在。
2.png

上图是领科云的总体架构。底层支持 OpenStackAmazon、阿里云等 IaaS 平台。原来将 DC/OS 部署在IaaS平台的时候使用 Ansible,因为给客户提供解决方案的时候,经常需要给客户部署一套进行联调。使用 Ansible 会遇到问题,就是客户的机器硬件环境千差万别,操作系统也不同,如果使用 Ansible,脚本必须经常改。于是我们将平台和应用全部 Docker 化,就可以用 Docker MachineSwarmCompose 进行部署。IaaS 平台基础上是 Linker DC/OS,Linker DC/OS 之上可部署大数据平台方面,Spark 和 Hadoop 都可以作为 Framework 运行在 Mesos 上,共享资源。Linker DC/OS 上还可以部署 PaaS 平台,用于管理 Java 应用,可实现应用的自发现,自修复,弹性伸缩。Linker 的 PaaS 平台是基于 Marathon 开发了 Linker Controller。当前业界的容器编排的系统都是针对容器本身的,可以配置容器之间的依赖关系,但是很少有人关心容器里面的应用的相互关系,虽然容器启动起来了,并不代表容器中的应用配好了。尤其是在互联网场景下,应用会越来越复杂,经常需要相互依赖,相互发现,相互配置,这种场景当前没有很好的解决方案,我们就开发了 Linker Controller 管理应用的相互关系。再上面是 Marketplace Platform,可以通过 Drag&Drop 托拉拽建立应用模型的方式设计和部署应用。

接下来分别介绍各个部分如何 Docker 化,以及 Docker 化过程中遇到的问题和解决方案。

首先是传统应用的 Docker 化,即 Java 程序的 Docker 化。此类服务在 Docker 化之前是部署在虚拟机中,不可能因为 Docker 化重写程序或者改变架构。所以必须要保证当前的业务架构不发生根本性的改变,在体验到 Docker 轻量级、快速部署、动态扩展的好处以后,然后再逐步进行架构的微服务化。我们原来的架构也是相对紧偶合的,Docker 化了之后逐步进行微服务化,区分有状态服务和无状态服务,通过多轮迭代最终适应全部的 Docker 化。
3.png

上图左边为传统的 Java 应用,最前端是负载均衡器例如 Nginx。负载均衡器不能是单节点的,一般是双节点的,用 Keepalived 来保持 VIP 在两个 Nginx 间浮动及宕机时自动切换。核心部分是运行在 Tomcat 里的 Java 程序,程序的相互发现是用 Dubbo 框架。比如说 A 要调用 B,那么 B 启动后注册到 Dubbo,A 从 Dubbo 中发现有 B 服务,A 即可调用 B 。后端的数据库我们没有使用MySQL Replication,而是使用MySQL Cluster,包含 MySQL Manager、MySQL和ndbd。

此类传统的架构 Docker 化的时候遇见了图中右面的问题。

第一:传统应用不适应 Docker 的网络架构。如果用 HOST,则同一台机器上不可以部署多个相同的应用,会出现端口冲突。如果使用 HOST 和虚拟机有什么不一样呢?无法体现容器轻量级,可部署多套的优势。如果修改端口,便需要同时修改配置脚本,特别麻烦。如果使用 Port Mapping,问题在于服务发现,Tomcat 启动在 Docker 里面,只是获取 Docker 里面的 IP,无法获取 Docker 外面的 IP(宿主机的 IP),无法将宿主机的 IP 注册到 Dubbo。其他应用从 Dubbo 中读取的是 Docker 里面的 IP,如果不在同一个主机上就无法连接。

第二:传统应用不适应 Docker 的存储方式。容器适合部署无状态的服务,Docker 宕机后 Marathon 再拉起,原来的数据就丢失了,对于传统应用来讲不可思议。所以数据应该存储在 Volume 中,然而一旦出现 Docker 迁移到另一主机,数据还是会丢失?

第三:应用之间的相互关系是如何配置。使用虚拟机部署应用,事先会创建很多虚拟机,虚拟机的 IP 就固定下来,配置文件也可以固定下来,每次部署 IP 不会变。Docker 化后,每次 Docker 启动 IP 会变,对于不同的客户,不可能将所有的配置文件重新调整一遍。如果 IP 是变动的,相互关系的配置就更具挑战。
4.png

首先要解决的是网络问题,也即跨主机 Docker 之间的互联,当时 Flannel 比较火,是否可以解决我们的问题呢?但是发现 Flannel 对于 MySQL Cluster 不起作用。上图是一个 Flannel 的架构图,它是 Overlay 方式,具体说就是 Docker 里面有一个 IP,从这个 IP 发出的包会通过宿主机上的路由表转发给 Flanneld,Flanneld 会将包进行封装加上 UDP 包头,发到另一台机器的 Flanneld,做解封装后发给另一台机器上的 Docker。这样一个 Docker 里面能够 ping 通另外一个 Docker 的 IP。看起来这个架构是没有问题的,但是使用了 MySQL Cluster 的时候发现,MySQL Cluster 是需要相互发现的,MySQL Manager 需要确认注册上来的 MySQL 是合法的,是通过包中的源 IP 地址是配置的合法地址才可以。然而 Flannel 发过来的包中的源 IP 地址不是源 Docker 里面的 IP 地址,而是 10.1.15.0 这个地址,MySQL Cluster 不认为是一个合法的连接,就会拒绝连接,所以说 Flannel 对我们没有起作用。
5.png

我们采取的方式有两种:方式一是在数据中心内部支撑自有业务的时候,使用用 Bridged Flat Networking ,使用桥接的方式,把物理机上的 Docker 以及虚拟机的 Docker 全部拉平。这种方式的优点在于,跨物理机的访问同传统访问没有任何区别,在 Docker 里面与在 VM 里面没有什么区别,性能损耗也会比较小。缺点是存在广播风暴的问题,如果集群特别大,应用全部在同一个二层,则会出现广播风暴。由于是内部使用,可以采取物理隔离的方式的,不同的业务搭建在不同的集群。如果使用 Port Mapping 的方式,从防火墙到服务器需要一次 NAT,很多公司会部署 IaaS 平台 OpenStack,然后 OpenStack 里面运行 Docker,这时候 OpenStack 会有一个 Floating IP,一般在数据中心里 Floating IP 并不是真的公网 IP,因为公网 IP 特别贵。Neutron 会将 Floating IP 做第二次 NAT 映射到虚拟机,然后虚拟机做第三次 NAT 映射到 Docker。于是任何一次应用的访问需要三层 NAT。如果使用这种 Bridged 的方式,则直接从防火墙一层 NAT 就可以。在物理机和虚拟机的选择上,我们的转发层使用物理机,控制层使用虚拟机,因为转发层可能是需要转发性能保证。方式二是使用 OVS 和 Weave,后来我们有了在线的平台,使用公有云和 OpenStack,无法干预虚拟机的网卡配置。当时 Docker Overlay 尚未发布,所以决定用 OVS 实现这个方案,OVS 在不同的机器上通过 GRE/VXLAN 隧道打通。为了实现多租户的隔离,禁止配置非Managed IP,Docker 桥接到 OVS 上的网卡的 IP 是 Linker Controller 分配的,非此 IP 的包则被禁掉。通过 OVS 的 Flow Table + Cgroup QoS,可以实现根据带宽做调度。
6.png

其次要解决的是存储的问题。实现 Docker 跨机器的HA,数据不丢失,我们选用 Ceph 作为共享存储。最初使用 Ceph FS 做统一存储,每台机器上都有 Volume,把这些 Volume 打成同一个池,上面有个 Ceph FS,两个机器上的 Mount Point 都能够看到相同的东西。A 机器上的 Docker 写入 Mount Point 里的文件是写到 Ceph FS 上的,当 A 机器上的 Docker Crash,在 B 机器上启动后,可以从相同的路径读到相同的文件。后来我们改用 Ceph Block Storage,原因是有两个:一个是业内称 Ceph FS 不是特别的稳定。我们自己测试发现,积累的数据特别多的时候,写入的性能就会差一些。另一个问题是我们的 Ceph 也会 Docker 化,如果用 Ceph FS,如果 Mount Point 在 Docker 里面的话,其他容器在外面无法访问。但是 Block Storage 是 Mapping 出来被其他容器访问到的。后来的方式是 Ceph 可以 Mapping 出来一个 Block,就可以格式化为一个文件系统,Docker 写入的是本地的文件系统,不用访问 Ceph 的 MDS,而是使用 Linux 的 VFS 就可以了。当容器宕机后,本地的 Block 会 Unmapping,然后到 Docker 迁移到的主机上重新 Mapping 出来,就可以访问到数据了。
7.png

最后是相互关系的问题。随着互联网行业包括云计算发展,如上图最左边这种 Load Balancer 依赖于 Web Server,Web Server 依赖于 Database 这种简单的应用越来越少了。越来越多应用如 MySQL Cluster 和 ZooKeeper,都需要互相配置,互相发现,形成环形甚至网状的结构。对于这种应用,我们发现当前没有更好的方式去做,所以我们开发了一个基于模型的 Linker Controller 来做这件事情,我们借鉴了 Puppet、Chef、Ansible 等部署工具中 Notify 的方式,使得应用之间通过 Notify 修改相应的配置。

模型设计的第一个基本概念叫应用模型,所谓的应用模型就是一些原子模型,每个应用模型对应一个 Docker Image,对于应用模型都会配置一些参数,如 CPU、实例数量、镜像名称等。可以配置 Linker 的镜像,也可以配置 Docker Hub 的镜像,用户可以参考到 Docker Hub 上的镜像说明文档,按照文档上面的说明去配置参数即可。

有了应用模型,第二个概念是服务模型。服务模型是一个或者多个有相互依赖关系的应用模型的组合。举例来说,部署一个 WordPress 非常简单,只需要给这个服务模型起一个名字,然后设置这个服务模型依赖于 WordPress,WordPress 依赖于 MySQL,只需要把 WordPress 的应用模型拖拽进来,MySQL 的应用模型拖拽进来,服务模型就基本上配置完毕了。最后唯一要做的一件事情是,WordPress 需要配置 MySQL 的 IP 地址,只要在依赖关系中选择 MySQL,MySQL 的 IP 地址就会自动放入 WordPress 的环境变量中。最后保存并提交审核进行发布。这时候在 Marketplace 里面就能够看到这个服务模型了。用户点击订购,WordPress 就会部署出来。所以想部署一个简单的 WordPress,依赖于 MySQL,根本不用写任何代码,也不用任何命令,只需要拖拽两下就可以搞定了。

WordPress 应用是单向依赖的应用。还无法展示到这个平台的一些特性。对于相对复杂的应用,如 ZooKeeper,每一个节点都要知道所有的其他节点的IP。一般 ZooKeeper 采取使用 Host 的方式进行部署,如果部署在某三台机器上,这三台机器的 IP 地址事先就会就知道,创建Docker的时候,三个 IP 都传给环境变量,ZooKeeper 集群就能正常启动了。但是我们的平台能解决一个扩展性的问题,也即可以从三个节点扩展到五个节点、七个节点。从三个节点扩展到五个节点的时候,如何让所有的节点获取另外的两个 IP,这时候就需要大家去通知它,这需要一个通知的机制。我们从 Weave 的命令行进入容器,就能看的 5 个 IP 全部配置进去了。

Docker 化以后我们还可以 CI/CD,大家通过这个系统还可以看到其实我们已经订购了 CI/CD 系统。包含的组件包括Gerrit、Nexus、LDAP等,这个 CI/CD 系统大家也是可以一点就直接出来,然后用户就可以直接使用了。对于创业的小公司,其实是非常好的。
8.png

再就是大数据平台的 Docker 化。原来大数据平台需要手动部署,现在都是用 DCOS 的方式,基于 Mesos 的集群部署 Framework。Spark 和 Hadoop 都可以作为 Framework 共享整个集群。DC/OS 安装 Spark 的方式为给 Marathon 发送一个 Json,部署一个 Docker,这个 Docker 会注册到 Mesos master 成为 Framework,真正运行 Spark 的任务的时候就是远程对这个 Docker 发起指令,Spark Framework 会告知 Mesos 说要执行 Spark 的命令,那么 Mesos 就会把所有的东西下发下去,然后所有的 Mesos slave 就会执行 Spark 的 task。

再就是智能硬件的 Docker 化。Java 程序和 Gateway 程序都 Docker 化了,大数据平台也 Docker 化了,最难做的就是智能硬件的 Docker 化,智能硬件的更新是比较复杂的。原来方式是有一个更新服务器,智能硬件可以通过 3G、4G 网络连接更新服务器。智能硬件上面会运行下列程序:监控程序、更新程序,转发程序,Web界面,安卓程序等。每次更新需要保持这些程序的一致性,如果不一致则智能硬件就不工作。但是问题是如何保持一致?一个办法是每次都全部下载,全部重装一遍,因为你永远不知道用户的硬件状态,那么如何保持一致性就是一个很大的问题。另外一个问题是如何保持完整性。原来是用过 MD5 做 Checksum。还有一个问题是如果更新不成功如何回滚。回滚就比较困难了,采取的一些比较传统的方式,比如说有三个文件夹,update、running、backup来回倒,当前运行的是 running,将来要更新的是 update,正在更新的时候 backup,backup 不行,把 backup 拷回来再装一遍。最难解决的问题是如何更新新加的功能。更新程序只能写更新当前有的功能。
9.png

我们能不能用 Docker?就是说在硬件的盒子里面装上 Docker,采取上面这么一个架构来进行智能硬件的更新和管理。开发者可以把代码上传到 Git Server 上,因为硬件是基于 ARM CPU 的,所以说不能在普通的 X86 平台上进行编译,需要用 QEMU。然后来模拟一个机器和一个 ARM CPU,把代码 pull 下来进行编译,编译成一个 Image,放在一个 Docker Registry 里面,这时候 IoT Controller 发现有更新了,就会去通知智能硬件,这个硬件就会把 Image pull 下来进行更新。这种情况下更新程序关心的,并不是里面的一个个的程序而是 Docker。

有了 Docker 这些问题其实都能解决了,比如把所有的程序放在一个 Docker 里面,那么无论是从 1.0 升到 2.0,其实你肯定能够保证 2.0 这个版本的一致性和完整性。回滚就很简单了,我们原来有个 1.0,那现在升到 2.0,如果 2.0 功能不正确,可以完全回到 1.0,能确保回滚就是原来 1.0 的版本。另外可以更新新的功能,就是说我们本来只有 A 功能,现在突然想要有 B 功能,只要拉一个新的 Docker 下来就可以了。

再做一个简单的演示。在这个智能硬件盒子上插了一根线,上面是温度、湿度测试的这么一个仪器,能够把本地的温度和湿度测试出来。盒子里面有两个 Image,一个是 1.0,一个是 2.0,1.0 我们只能取到温度,我们模拟这种场景,这个模块既可以测温度,也可以测湿度,突然有一天除了测温度,还想再测一下湿度,那么就可以 1.0 升到 2.0,那么湿度也可以测试出来了。

在我们把所有应用程序都可 Docker 化了以后,最后做的事情就是做领科云自身的 Docker 化。

核心组件 Docker 化,一是 Mesos 和 Marathon 的 Docker 化 。第二个就是使用 Weave。第三个是 Ceph 的 Docker 化。所有东西 Docker 化了以后, 我们就可以 Docker Machine 和 Docker Swarm 部署整个集群。整个数据中心的部署将来给客户时是从一个 Docker 开始的,这个 Docker 里面安装 Docker Machine、Swarm、Compose,先用 Docker Machine 创建出虚拟机并安装 Swarm,然后 Compose 通过 Swarm 部署Marathon、Mesos、Weave、Ceph 这些核心组件。

点击下载PPT,观看视频

1 个评论

请问,关于调度框架的选择,k8s、mesos、docker swarm 你们当时是如何选择的呢

要回复文章请先登录注册