模式五:使用Marathon和Mesos
使用场景:万节点集群,多定制
当集群规模大一些,几百个节点时,很多人就不愿意使用Docker Swarm Mode了,很多的选择是既没有用DC/OS,也没有用Kubernetes,而是仅仅用了Marathon和Mesos。
因为Mesos是一个非常优秀的调度器,它的双层调度机制可以使得集群规模大很多。
Mesos的调度过程如图所示:
Mesos有Framework、Master、Agent、Executor、Task几部分组成。这里面有两层的Scheduler,一层在Master里面,allocator会将资源公平的分给每一个Framework,二层在Framework里面,Framework的scheduler将资源按规则分配给Task。
其它框架的调度器是直接面对整个集群,Mesos的优势在于,第一层调度先将整个Node分配给一个Framework,然后Framework的调度器面对的集群规模小很多,然后在里面进行二次调度,而且如果有多个Framework,例如有多个Marathon,则可以并行调度不冲突。
详细的调度机制非常复杂,可以看《号称了解mesos双层调度的你,先来回答下面这五个问题!》这篇文章。
而且Mesos的架构相对松耦合,有很多可以定制化的地方,从而运维人员可以根据自己的需要开发自己的模块。详细的定制方式看文章《定制化Mesos任务运行的几种方法》。
这也是很多优秀的公司使用Marathon和Mesos的原因。
例如爱奇艺、去哪儿、携程、当当等都选择了使用Mesos,需要提一下的是,大家如果参加社区,能发现裸用Marathon和Mesos的很多,但是整个DC/OS都用得比较少,而用Marathon和Mesos往往不能解决一些问题,因而这些IT能力非常强的互联网公司做了大量的自己的定制化,增加了Marathon和Mesos的外围模块。
模式六:使用开源Kubernetes
使用场景:千节点集群,少定制
Kubernetes模块划分得更细,模块比较多,比起裸Marathon和Mesos来讲功能丰富,而且模块之间完全的松耦合,可以非常方便地进行定制化。
而且Kubernetes的数据结构的设计层次比较细,非常符合微服务的设计思想。例如从容器->Pods->Deployment->Service,本来简单运行一个容器,被封装为这么多的层次,每次层有自己的作用,每一层都可以拆分和组合,这样带来一个很大的缺点,就是学习门槛高,为了简单运行一个容器,需要先学习一大堆的概念和编排规则。
但是当需要部署的业务越来越复杂时,场景越来越多时,你会发现Kubernetes这种细粒度设计的优雅,使得你能够根据自己的需要灵活的组合,而不会因为某个组件被封装好了,从而导致很难定制。例如对于Service来讲,除了提供内部服务之间的发现和相互访问外,还灵活设计了headless service,这使得很多游戏需要有状态的保持长连接有了很好的方式,另外访问外部服务时,例如数据库、缓存、headless service相当于一个DNS,使得配置外部服务简单很多。很多配置复杂的大型应用,更复杂的不在于服务之间的相互配置,可以有Spring Cloud或者Dubbo去解决,复杂的反而是外部服务的配置,不同的环境依赖不同的外部应用,External Name这个提供和很好的机制。
包括统一的监控cadvisor,统一的配置confgMap,都是构建一个微服务所必须的。
然而Kubernetes当前也有一个瓶颈——集群规模还不是多么大,官方说法是几千个节点,所以超大规模的集群,还是需要有很强的IT能力进行定制化,这个在模式七中会说一下我们在网易云上做的事情。但是对于中等规模的集群也足够了。
而且Kubernetes社区的热度,可以使得使用开源Kubernetes的公司能够很快地找到帮助,等待到新功能的开发和Bug的解决。
模式七:深入掌握使用Kubernetes
使用场景:万节点集群,IT能力强
随着Kubernetes使用规模的越来越大,大型的公司可以对Kubernetes进行一定的定制化,从而可以实现万节点甚至更大规模的支撑,当然需要IT能力比较强,网易在这方面有很多的实践。
从APIServer看集群的规模问题
随着集群规模的扩大,apiserver的压力越来越大。
因为所有的其他组件,例如Controller、Scheduler、客户端、Kubelet等都需要监听apiserver,来查看etcd里面的变化,从而执行一定的操作。
很多人都将容器和微服务联系起来,从Kubernetes的设计可以看出,Kubernetes的模块设计时非常的微服务化,每个进程都仅仅干自己的事情,而通过apiserver的松耦合关联起来。
而apiserver则很像微服务中的api网关,是一个无状态的服务,可以很好地弹性伸缩。
为了应对listwatch,apiserver用了watchcache来缓解压力,然而最终的瓶颈还是在etcd上。
最初用的是etcd2,这时候listwatch每次只能接受一个事件,所以压力很大。为了继续使用etcd2,则需要使用多个etcd2的集群来解决这个问题,通过不同的租户分配到不同的etcd2集群来分担压力。
将来会迁移到etcd3有了事件的批量推送,但是从etcd2到etcd3需要一定的迁移工作。
通过优化Scheduler解决并行调度的问题
大的资源池的调度也是一个很大的问题,因为同样一个资源只能被一个任务使用,如果并行调度,则存在两个并行的调度器同时认为某个资源空闲,于是同时将两个任务调度到同一台机器,结果出现竞争的情况。
为了租户隔离,不同的租户是不共享虚拟机的,这样不同的租户是可以参考Mesos机制进行并行调度的。因为不同的租户即便进行并行调度,也不会出现冲突的现象,每个租户不是在几万个节点中进行调度,而仅仅在属于这个租户的有限的节点中进行调度,大大提高了调度策略。
并且通过预过滤无空闲资源的Node,调整predicate算法进行预过滤,进一步减少调度规模。
通过优化Controller加快新任务的调度速度
Kubernetes采用的是微服务常使用的基于事件的编程模型。
当有增量事件产生时,则controller根据事件进行添加、删除、更新等操作。
但基于事件模型的一个缺点是,总是通过delta进行事件触发,过了一段时间,就不知道是否同步了,因而需要周期性地Resync一下,保证全量的同步之后,然后再进行增量的事件处理。
然而问题来了,当Resync时,正好遇到一个新容器的创建,则所有的事件在一个队列里面,拖慢了新创建容器的速度。
通过保持多个队列,并且队列的优先级ADD优于Update优于Delete优于Sync,保证相应的实时性。
模式八:深入掌握使用DC/OS
使用场景:万节点集群,IT能力强
前面说过Mesos由于本身独特的调度机制,从而支撑的集群规模比较大,但是大多数使用Mesos的公司都没有使用DC/OS,而是裸使用Marathon和Mesos外加自己定制开发的一些组件。
Mesos可以支持当集群规模非常大,单个Marathon的性能不足以支撑时,可以使用自己的Framework机制,使得不同的租户使用单独的Marathon来解决问题。
后来DC/OS在最基础的Marathon和Mesos之上添加了很多的组件,如图所示,现在已经非常丰富,例如DCOS的客户端(kubectl)、API网关admin router(类似apiserver)、服务发现minuteman(类似kube-proxy)、Pod的支持、CNI插件的支持、存储插件的支持等,和Kubernetes已经非常像了。
很多公司裸用Marathon和Mesos而没有进一步使用DC/OS,可能是因为和核心组件Mesos已经经过大规模生产性支撑不同,这些外围的组件也是新的,对其稳定性也是有一定的顾虑,所以需要比较长的学习曲线,并且对于这些新的组件有非常好的把控,才敢上生产。
所以从这个角度来讲,虽然Mesos的稳定性和大规模无容置疑,但就整个DC/OS来讲,和Kubernetes从功能和稳定性来讲,在伯仲之间,都需要使用者有强大的IT能力,对于开源软件的各个模块非常熟悉,甚至能够做一定的代码修改和Bug fix,才敢在大规模集群中使用。
模式九:部署大数据,Kubernetes vs. Mesos
Mesos还有一个优势,就是Mesos可以通过开发Framework,构建大数据平台,例如Spark就有基于Mesos的部署方式。
基于Mesos的Spark有两种方式,粗粒度和细粒度。
粗粒度模式(Coarse-grained Mode):应用程序的各个任务正式运行之前,需要将运行环境中的资源全部申请好,且运行过程中要一直占用这些资源,即使不用,最后程序运行结束后,回收这些资源。组粒度的方式浪费资源。
细粒度模式(Fine-grained Mode):按需分配,应用程序启动时,先会启动executor,但每个executor占用资源仅仅是自己运行所需的资源,不需要考虑将来要运行的任务,之后,mesos会为每个executor动态分配资源,每分配一些,便可以运行一个新任务,单个Task运行完之后可以马上释放对应的资源。细粒度的缺点是性能有问题。
其实细粒度模式才是真正能够发挥Mesos动态资源调度最有效的方式,但是考虑到有大幅度的性能降低,https://issues.apache.org/jira/browse/SPARK-11857,很可惜这种方式在Spark 2.0.0被deprecated掉了。
如果使用kubernetes部署大数据,其实和部署一个普通的应用思路差不多,和Mesos不同,kubernetes不会干预到大数据运行的上下文中,Kubernetes启动的容器仅仅作为资源预留方式存在,容器内的资源分配则大数据平台自己解决。这样的利用率就降低了,相当于粗粒度模式。
基于容器部署大数据平台,也是建议部署计算部分,例如Map-Reduce,或者Spark,对于数据部分HDFS,应当另行部署。
模式十:容器和虚拟化混合部署
使用场景:大型公司,逐步容器化
对于很多大公司但是非互联网公司,使用容器还是需要小心对待的,因而需要逐步容器化,所以存在有IaaS平台,并且虚拟机和容器混合使用的状态,这种状态可能会持续相当长的时间。
在这种情况下,建议容器套在虚拟机里面使用。
使用Flannel和Calico都仅仅适用于裸机容器,而且仅仅用于容器之间的互通。
一旦有IaaS层,就会存在网络二次虚拟化的问题。
虚拟机之间的互联是需要通过一个虚拟网络的,例如vxlan的实现,而使用Flannel或者Calico相当于在虚拟机网络虚拟化的上面再做一次虚拟化,使得网络性能大幅度降低。
而且如果使用Flannel或者Calico,那容器内的应用和虚拟机上的应用相互通信时,则需要出容器平台,多使用node port,通过NAT的方式访问,或者通过外部负载均衡器的方式进行访问。在现实应用中,不可能一下子将所有的应用全部容器化,只是部分应用容器化,部分应用部署在虚拟机里面是常有的现象。然而通过NAT或者外部负载均衡器的方式,对应用的相互调用有侵入,使得应用不能像原来一样相互调用,尤其是当应用之间使用Dubbo或者SpringCloud这种服务发现机制时,尤其如此。
网易云开发了自己的NeteaseController,在监听到有新的Pod创建时,调用IaaS的API创建IaaS层的虚拟网卡,然后在虚拟机内部,通过调用Netease CNI插件将虚拟网卡添加到容器里面。添加技术用的就是上一节提到的setns命令。
通过这个图我们可以看出,容器的网卡是直接连接到虚拟私有网络的OVS上的,和虚拟机是一个平的二层网络,在OVS来看,容器和虚拟机是在同一个网络里面的。
这样一方面没有了二次虚拟化,只有OVS一层虚拟化。另外容器和虚拟机网络打平的好处是,当部分应用部署容器、虚拟机时,对应用没有侵入,应用原来如何相互访问,现在还是如何访问,有利于应用逐步容器化。
OpenStack里面有一个项目Kuryr可以很好地去做这件事情,完全使用开源的OpenStack和Kubernetes可以尝试集成一下。
容器服务是网易云提供的无服务器容器服务,让企业能够快速部署业务,轻松运维服务。容器服务支持弹性伸缩、垂直扩容、灰度升级、服务发现、服务编排、错误恢复及性能监测等功能。点击可免费试用。
更多网易技术、产品、运营经验分享请点击。