【文章简介】本文讨论了单个容器所无法解决的问题和局限性,并介绍了容器编排的必要性和复杂性及常用工具的比较,提到了诸如Kubernetes、Mesos等容器管理工具。
就像之前已被证实的那样,要在一个机器上创建成千上万个容器还是相对容易的。但如何去部署这么多的容器呢?如何管理且追踪它们?如何管理、如何来处理故障恢复?这些事情看似容易,但解决起来困难重重。让我们来解析一下究竟难在何处。
用一个简单的命令,就可以设立Docker环境,来跑一个Docker直到你将停其掉为止。但如果你需要在两台机器上跑Docker容器呢?如果50台呢?或者如果1万台呢?现在,你可能会问为何要这么做。这里有一些好的理由:
为了服务更多的用户,你可能会遇到你Nginx网络服务器纵向扩容的瓶颈,也就是说,在一个云供应商那儿使用一个更大的实例类型或者在你的披萨盒子里塞下更多的内存。如果你已经碰到那堵墙,你就会需要这么一个选项,可以横向的扩容,典型性的就是采用代理服务器/冗余控制来作为服务稳定的切入口。
另一个方面是容错。如果你可爱的Redis容器停止存在了,该怎么办?有可能是底下的机器死了?你会想要做故障转移。在容器工作的情景下,这意味着你的编排器得在另一个健康的机器中重新启动你需要运行的容器。
所以,这都取决于你的目标动机——容量、容错或者两者皆有——如果你有10个或者1千个机器,那挑战就存在着:如何在这些不同的机器间有效率且有效果地进行容器扩容。
然而,在我们跨入这些挑战之前,让我们来理清一些术语。来自微软和谷歌关于集群的研究表明了如下的工作量的区分:
有一些长期在跑的服务,那应该一直在跑。那些通常是做交互、对延迟敏感的例如面向终端用户的网络应用这样的任务;或者是底层的服务,类似于Cassandra、ArangoDB、HDFS或者 Quobyte。
然后,就有一些批量任务,延续时间从几秒到很多小时。他们通常对表现波动没有那么敏感,然而可能存在例如像独立管理等完成时间上的总体服务水平协议(SLA)。
除了以上这些工作任务的类别区分,还想要支持工作优先度划分:比如对业务尤为关键的、对顶层收入产生直接影响的生产性工作,以及非生产性工作比如质量测试、测试和研发这类。
从一个到两个
把术语理清之后,让我们直接来面对在超过一台服务器上跑容器需要克服的挑战。
最为基本的问题是:在一台服务器上能装下多少容器?我们发现,在裸机上不同负载的测试表明每个机器容纳250个容器是可能的,这是Docker Daemon的潜在极限。对一个平均跑20个Docker镜像的简单的微服务构架的应用而言,产生大约10倍的容量(scale factor)。显而易见,当你在一个机器上跑超过一个应用,这将会非常容易的降低到2倍。另外,资源消耗会产生一个自然的极限:比如,假设一个单独的容器可能消耗内存的为100MB,对于一个32GB的内存(除去操作系统需要的2GB),那就留给我们3万MB或者相当于300个容器。这比我们之前讨论的极限要高的多。因此,即便在中等的负荷下,扩容显得不可避免。
一旦当你跑了两台机器来服务你的容器,你需要关注以下事项:
任何一个容器的健康情况是怎样的?它是否还在运行、在服务,而且如果是这样的话,它的核心健康数据(监控)是怎样的?
我到哪里能找到特定的那个容器?也就是说,在容器的逻辑ID和具体的(路由)IP之间能有一个匹配:端口匹配必须建立和保持,这也被称为服务发现。
应用版本和更新。不管何时当应用的一个新版本被部署时,Docker镜像需要被传递到服务器上(即镜像的实时性和信任)。
上述罗列的这些功能要求是在编排系统核心任务之外的,也就是如何来编排容器(或者,换句话说,来决定在哪台机器上来跑容器)。尽管这个描述,是一个真实情况的简略版,但它能帮助我们理解在多台机器上跑容器的基本挑战。对于两台机器来说,任何包括Docker Swarm、Kubernetes和Mesos的解决方案都适合;有了后两个,尽管是可取的,但似乎也大材小用。直到你的应用被使用的非常厉害,而且当你添加到第三台、第二十台或者第487台机器为止。那么,然后呢?
从两个到多个
今年早些时候,谷歌发布了他们主要的生产集群管理的细节,Borg。
谷歌在10万台机器的区间内,他们中位数集群尺寸大约在1万台机器,也有一些更大的。谷歌称,一个单独的BorgMaster(其专有的分配集群的首脑)在一个cell(谷歌对于集群的术语)内能管理成千上万台机器。一个忙碌的BorgMaster使用10至14个CPU内核以及高至50GB的内存。另外,几个cell有任务到达率在每分钟1万个任务以上。尽管不是每个人都是谷歌或者Twitter,在这个事情上,对于企业级别的需要应对成千上万用户或者一个流行的移动端应用即需要面对百万数量级潜在的多进程用户而言的复杂应用,还是非常容易会到达成百上千个机器的范畴。
在一个分布式系统内,去追踪成千上万件事情(进程、连接等)以及它们的状态是一件很难的事情。真相的来源是什么呢?你是从中心的位置每隔一段时间去检查一下吗?你去跑代理来推送状态到上游吗?这些都是一些已经被讨论了一阵的相关问题,比如从1990年代晚期以C10K问题的形式。
另外,跑成千上万个容器(我们已经从上面描述知道了这需要成百上千的服务器)会给你一个分布式的系统,存在许多复杂的失败模式:从超时引起的问题,到网络划分的问题,到CPU垃圾清理的问题或者是内存耗尽问题。最后的但不仅仅限于此的问题是,为了有效利用服务器,容器需要被以最有效的方式bin-packed;有一件特别难的事,尤其当要考虑到做两种类型的任务(长时期跑的和批量的)和任务优先级划分。你当然不想因为一个以周为单位的Spark批量任务以为它需要你集群中的一大块儿,然后把你企业的应用给耗尽从而丧失每小时10万美金的利润。
总结一下,在集群层面上以最优方式来安排容器意味着要这么做:
如果发生故障,你的服务要能继续跑。
你的最大化利用要很严格、很动态。
另外,故障处理,意味着确保发生故障后能重新安排,要潜在地把其他工作事先清空也是很难且动态的。我说“很难”和“动态”的意思是,这些需要很多计划安排,而且我们在讨论的是一个迅速且一直在变化的环境,这本身是计算机相对于人类而言擅长之初的完美例子。
现在,既然我们已经探索过了存在问题的空间,让我们再来看一下解决办法的空间。
Mesos满足了以上列表的要求,很成熟,而且得益于它的两层安排体系,也使得它极度灵活。和“一种尺寸适应所有情况”的单一安排体系不同的是,Mesos把实际工作分配决定委派给所谓专门的框架安排体系,而它自己则通过应用“专用资源公平算法”(Domain Resource Fairness algorithm,简称DRF算法)来关注资源抽象和管理。DRF算法本质上让不同的工作得以公平地分享不同类型的资源(CPU、RAM等等)。
或许,对这个讨论更为重要的是,Mesos可以线性扩容。早在2010年,在Mesos原始的技术报告中(精确的说,在6.5部分),在AWS上的一个有99个EC2实例的集群进行了一个实验,每个集群都有八个CPU内核和6GB的内存。在集群上跑有5万个slave daemons,结果是一个线性的向上的增加(总在1秒以内),说明在主从daemon之间存在线性扩容的关系。
线性扩容是Mesos一个非常关键的特征,用来跑容器化的工作负载,不管是在某一个云环境中还是在一个混合的云设置中(比如:混合了在终端的云或者不同云提供商之间的云)。迄今为止,Mesos在这方面是唯一一个被证明有追踪记录的开源的社区项目(Twitter、Airbnb、Apple和50多个公司),我们未来也看看它会朝何处发展。
从谷歌10多年前在跑容器扩容方面学到的经验(不管是Kubernetes中的pod概念还是基于谷歌Omega的优化方案),都已经引入了Mesos核心。从另外一方面来说,人们可以得益于使用Data Center Operating System,是Apache Mesos的商业版本,和Kubernetes和Swarm包一起使用。
原文链接:What Makes Containers At Scale So Difficult
翻译:韩佳瑶 ( Caicloud 首席运营官,美国匹兹堡大学信息科学系硕士,Docker爱好者)
(如果需要转载,请联系我们哦,尊重知识产权人人有责)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。