编辑推荐: |
本文来自于dockone.io,主要针对Docker
Swarm和Kubernetes在大规模部署的条件下展开讨论。在大规模部署下它们的性能如何?它们是否可以被批量操作?需要采取何种措施来支持他们的大规模部署和运维? |
|
我们需要使用侧重于用例的基准测试来对所有容器平台进行比较,这样采用者才可以做出正确的决策。
笔者从用户的角度建立了一套测评工具,用普通的方法测试Docker Swarm和Kubernetes。我只评估了通用的功能:容器的启动时间和容器罗列时间。
Swarm的性能比Kubernetes好。
Kubernetes和Swarm都在1000个节点的集群上执行同样的工作。
无论从架构还是功能的角度来看,Kubernetes都是一个更加成熟且复杂的系统,因此它就需要更多的精力去部署和运维。
以下所分析和呈现的数据可以帮助用户基于自身的需求来选择一个合适的平台。
序文
我很高兴地向大家透露,这篇文章是被资助的独立研究与开发的成果。Docker公司不仅贡献了工程师们的宝贵时间,并且购买AWS的服务来支持该工作的不断迭代和测试。发布全部的相关内容用于检测,重复利用以及第三方测试是我们的共同目标。如果你或者你的组织对资助其他的创新研究感兴趣,请通过http://allingeek.com联系我。
我在这次研究的过程中学习到很多知识,不仅局限于测评的结果和集群架构。如果你想要随时参与讨论,请在Twitter上关注我或阅读我的博客,因为这些内容细节将随着时间流逝被我渐渐淡忘。
这个项目带来一个黑暗的现实那就是——云不是无限的——当我用光us-west-2a上所有m3.medium的容量时,集群放置位置成为了我的关注焦点。Oops!正在回滚……
现实中Swarm和Kubernetes在大规模集群中的性能表现怎么样?
我承认,当我最初提出这个问题时并不知道怎么回答。我读过一些文章,比如Kubernetes Performance
Measurements and Roadmap和Scale Testing Swarm to 30,000
Containers等。但是这些文章都存在一个问题:我们很难理解作者真正要测什么,以及测试环境是怎么样的。更加让人痛苦的是,没有提供清晰的步骤或工具让测试重现。每个呈现出来的数据会变得没有意义,因为读者已经迷失在上下文中。我认为,对于读者来说,这些数据比起没有被证明的表述反而更加危险。因为读者会更愿意去相信你的数字,即使它们很难理解。
现有的研究和文献的另一个问题是,很少有文章在测量相同的东西。这样就很难来比较结果报告。我们需要一个通用或完整的功能测试基准,让这类的工具可以测试每个平台(不仅仅是Swarm和Kubernetes),这样就可以帮助到DevOps社区,就如同QuirksMode.org帮助网页开发者一样。
这个项目面临的挑战是建立一个通用的框架来评估在一个现实部署环境中的通用功能,同时帮助读者记录流程。毕竟我需要让每个普通读者可以拿到结果信息。而在真正的执行前,建立一个通用的命名方式是很重要的,例如Docker是采用Container技术,一个“pod”是Kubernetes中的最小部署单元,一个pod由至少一个Container组成。我们所描述的工作都是使用单容器的pod,所以接下来的这篇文章中,我会使用Container来替代pod。文章中接下来的内容,我将引用Kubernetes的作业(job)。一个作业是一个Kubernetes的控制面板所管理的单元,是用户希望完成的任务。一个作业通过一个pod执行,在这里也是一个Container。
选择用于测量的操作
Swarm和Kubernetes提供了不同的API和功能的抽象。 Swarm是Docker的一个子项目,它的作用在集群级别下就如同Docker在一台单独的机器中起到的功能。你可以使用Swarm来管理单个容器或者列出集群中所有运行的容器。而Kubernetes拥有并行启动,自动扩容,有差别的批处理和服务生命周期,负载均衡等特性。因此,经过全面的评价后,我将"容器启动延迟"和"容器罗列时间"作为两个最佳的候选操作。
最小化容器的启动时间对于延迟敏感的程序而言非常重要。举个例子,类似于AWS lambda的即时编译(Just-in-time)容器服务会在收到一个依赖于它特定功能的请求之后,才真正地启动一个容器。
而即时编译容器在物联网(IoT)领域也有其实际的应用。另外,作业或者批处理软件本质而言就是“按需的”。而无状态的微服务和固化的部署单元也是被广泛提倡和采用的。我坚信当上述提到的趋势进一步的趋向于作为即时编译服务存在时,响应式部署基础架构的盛行会是一种自然地演化结果。而对于这种类型的系统而言,低延迟是一个必要的需求。
对于“容器罗列时间”所需的低延迟而言,并没有相关的用例支持。但从目前所积累的相当经验来看,在一个集群上罗列容器命令的延迟与否会和运维人员的效率有密切的联系。如果罗列容器操作相当慢,那么运维人员可以考虑建立用于更新本地容器列表缓存的一个后台执行任务,基于此我们可以提供比直接执行罗列容器操作更加好的性能来提升效率。
开发测试工具套件
Kubernetes和Swarm都提供了同步API调用来获取容器列表。 这意味着他们的命令行客户端同时会被阻塞,直至收到整个列表信息以后才会退出。所以可以方便的使用time命令来测试两者罗列容器所需要的时间。
Swarm另外提供了同步的接口来创建容器,因此我可以使用同样的测试模式(基于time命令)来测定启动的延迟。不过,Kubernetes使用异步的方式来完成同样的功能(创建一个容器),换句话说,客户端会在容器真正启动之前就已经退出。
所以,对于Kubernetes启动时间的测定需要使用不同的方法。
使用罗列容器的接口来获取完整的信息,或者使用“运行时间”来确定一个容器启动所需要的时间是十分有吸引力的方案。这个策略依赖于获取信息操作本身有足够合理的精度。但结果将显示,罗列容器的延迟非常巨大,以至于使用精度在十到百毫秒的测定命令来确定时间不是十分合理。
使用这样的测试方法会引入太多的错误。
因此,使用等同和通用的测试方法来做测定是一个更好的方案。在上述讨论案例中,两个平台都会最终启动一个容器。当它收到新容器的信息时,超时的进程将会退出。
按照上述方法测定启动延迟会引入一定的额外开销,但是额外开销对于所有的平台而言都是均衡的,因此也就不影响比较的结果。
测试环境
我在AWS上使用1000个节点的集群测试了Kubernetes和Swarm。这是AWS平台上比较受欢迎的测试方法。节点运行在m3.medium的实例(1
vCPU,3.75 GB)上。基础设施机器使用m3.xlarge的实例(4 vCPU,15GB)。键值数据库运行在c4.xlarge
的实例(4 vCPU,7.5 GB)上。Kubernetes的API层采用6个冗余备份。测试运行在同一个VPC中的一台单机(t2.micro)上。
我基于以上配置选择了这些实例种类用于其它研究,并且在早期的迭代中观察性能。通用组件的性能特征:测试节点,worker节点和etcd都是一样的。每个集群节点所提供的资源不会影响到这些测试的性能,除非这些资源不支持平台组件。你可以根据你自己大致的资源要求,规模大小和成本要求来决定自己部署的实例类型,集群大小。在这个测试中,软件没有太强需求。
用预加载到机器中的一些休眠程序来填充每个节点。使用者一般会采用预加载镜像这个通用的策略用来减少不稳定性和启动延迟。Kubernetes节点用“gcr.io/google_containers/pause:go”镜像,而Swarm使用Dokcer
Hub上的“alpine:latest”镜像中的休眠命令。被测试的容器都是通过“alpine:latest”镜像创建的,并且都只执行nc命令。
所有集群都根据大规模部署最佳实践和领域专家的指导意见进行配置。这些配置与一个产品环境有着如下不同之处:
1.不采用multi-host网络部署
2.不采用高可用的键值数据库配置
3.不采用安全TLS通信,并且对网络配置并不进行安全加固。
4.Kubernetes并不启用身份认证和授权的功能
我测试的软件版本是Kubernetes v1.2.0-alpha.7和Dokcer Swarm v1.1.3-rc2(是从dockerswarm/swarm:master拉取的)。两个集群的键值数据库都采用etcd
v2.2.1。
此次测评的目的是给预测级别的性能概率建立一些统计置信度。要完成该任务需要多次测量(或采样)相同的操作。每个目标级别,相同集合的性能分布可以帮助我们理解“下一次”操作的性能概率。大采样量可以提高精度,并且降低噪声或异常样本带来的的影响。
这个测评程序集群使用率分别为10%、50%、90%、99%和100%,每个目标使用级别收集1000*的样本。在这个环境下,当一个节点运行30台容器时就会满了。所以,当一个1000节点的集群有30000台运行的容器时,这个集群也满了。测量时每次就采集一个样本,所以在测试盒或API服务上并不会产生任何的资源竞争。
在对Kubernetes测评时,会使某些级别的一系列操作样本数量降低到100个。随后,测评程序上的每个操作都会消耗超过100多秒。最终,1000个样本将会消耗大约28小时来完成每个目标级别的操作。
测试结果
由于统计结果的数据经常被曲解,所以下列显示的图表和周围的注释我们会尽量保持简洁,确保不会给读者带来困惑。此外,在阐述相关数据的时候,我永远不会跟你说“相信我吧”。我得到的所有数据都在GitHub上。你可以用来做你自己的分析。
下面4个图表所提供的数据,可以帮助我们来回答一个问题:“当我的集群资源使用率是X%的时候,将需要多长时间来启动下一个容器?”每个图表有一个小标题比如:“10%的样本容器在少于……时间内启动”。这就表示,在同样的目标水平,你有10%的概率将在少于图表中给的时间启动的下一个容器。所有值的单位都是秒。
如果你想要在Kubernetes上在一秒内启动一台容器,如果你的系统上已经有一些负载的话,这可能性比较小。第3001台容器想要在1.83秒内启动的概率是10%。
只要集群负载没有达到90%,Swarm有一半的概率可以在小于0.5秒的时间内启动一台容器。如果集群负载达到50%或更多,Kubernetes有一半的时间概率可以在大于2秒的时间启动一台容器。
到了资源占用率为90%时,在两个平台之间的测评数据有最明显差别,那就是Swarm在启动容器的速度上快大约4至6倍。
在分析结果之前,我们看到在Kubernetes的90%至99%资源占有率过程中,数据有点走样。在和同事讨论该异常时,我们推测是etcd测试的线性性质和“模型建立”原因导致的问题。这些问题导致系统经历一个异常的减速,并且在后面99%部分的变得很不稳定。我仍然在图中标注上该数据,是因为这些数据也许可以表明集群长期运行下会出现的稳定性问题,这是非常有趣的。我曾经听到一些说法是etcd
v3会有一些改进,包括性能增强和清理任务等,也许可以帮助解决这个问题。所以,之后我使用了一个全新的集群来测试负载100%下的Kubernetes。由于该原因,所以我在以下的分析中不计在90%和99%资源使用率下的测试数据。
在分析这些图表和得到的数据,你可以做一些着重的观察:
1.Kubernetes的第30001台容通常在2.52秒至3.1秒启动,而Swarm则只需要0.56秒至0.67秒。
2.当集群中有3000台至30000台容器时,Kubernetes容器的启动延迟会增加0.69秒至0.74秒,而Swarm只有0.22-0.27秒。
3.观察到Swarm的最长启动延迟是1.14秒(第30001台容器),比Kubernetes的最短延迟(在第3001台容器是1.69秒)还短大约0.5秒多。
当做这类的测评时大的采样量是很重要的,因为数据可以让你更好地理解遇到一个特殊结果的可能性。在这个案例下,我们知道Kubernetes将花费几秒的时间来启动单台容器。Swarm通常可以在一秒内启动一台容器,一般可以在0.7秒内启动,除了10%的其他情况。那么这么小的延迟肯定会对一个真实的基础架构决策有着实际的应用。
如果要我去建立一个“刚好及时”的容器系统,像AWS Lamda,那么我肯定会采用Swarm为基础来搭建那个系统。
有趣的是,我想补充一点,复制控制器提供的Kubernetes并发容器调度的效果是很惊人的。使用Kubernetes复制控制器,我可以在155秒内创建3000个容器副本。如果没有使用并发的话,将在Swarm上需要大约1100秒,在Kuberntes上则需要6200秒。
一些时候采用并行的方法是一个非常好的想法,这也正是编排系统平台的闪光点所在。
罗列容器命令的测试结果如下所示。请注意,Kubernetes在99%资源占有率下的测试结果是异常的,随后我会用是一个健康的集群来在100%负载下重新测评。
Kubernetes里罗列容器命令的性能在集群资源使用率为90%至100%时,表现跟其他迭代测试的结果一致。
Swarm和Kubernetes在容器密度较低时都表现得很好。在10%集群资源使用率的情况下,Kubernetes罗列所有容器所花费的时间总是比创建一个容器耗费的时间短。
数据表明,在集群资源使用率为50%至90%之间的某一点,Kubernetes的性能会超过某个阈值,而性能的降低也比它在10%至50%时的快。更深层地探究数据,我发现第50个百分点是6.45秒,而第75个百分点时是28.93秒。对于这一点,我更愿意解释为Kubernetes在集群使用率达到50%的时候罗列容器命令的性能开始出现大幅下滑。
Swarm的性能数据则比较少有戏剧性的变化但仍然说明了一些问题。就如同Kubernetes,Swarm也会有一个性能的临界点,由有一个平缓的增长趋势后跳到一个高很多级别的平缓增长趋势。就是说该临界点会影响集群在负载90%-99%时使效率提高,而在负载为50%到90%的区域使效率降低。
在所有的测试级别中,Swarm在集群使用率为99%时的性能表现比Kubernetes在集群使用率为10%时的性能仍快4到6倍。
在我跑完该基准测试后,我想对照现有可搜集到的其他测试数据确认一下我的发现。最终找到GitHub上一个从2015年1月开始的对调查容器启动时间的项目。他们号称可以达到他们的目标,“在一个100节点,3000个pod的集群上,可以使99%的预先拉取过镜像的点对点pod的启动时间达到小于5秒的性能指标。”我不能确定他们使用的是什么测试环境,但是我所收集的数据有着相同的数量级。
GitHub上的评论指出,测试端对端容器的启动时间的延迟与测试调度吞吐量是不同的。CoreOS的Hongchao
Deng在几周前发布了一篇文章,关于Kubernetes的调度程序,并在一个虚拟或空环境中测试性能。那个测试把调度程序的性能与其他来源如网络,资源竞争的噪音隔离开来。但真实环境并没有那样的隔离,所以想要在自然环境下有那样的性能,有点不现实。CoreOS的文章写得非常好,我逐字拜读了。它是在实际应用工程中如何提高单个组件性能最好的一个例子。
总结一下,这些测评结果显示我们所测试的操作在Swarm上运行得比Kubernetes的快。两个集群用的都是相同的数据库技术,相同的测试工具和网络拓扑。我们可以推测,造成不同结果的原因是在架构和算法选择上。在下一章,我们会深入到两种架构中来了解。
Kubernetes和Swarm是否真的具有操作1000个节点的能力?
我曾经把两个集群都扩建到1000个节点。这需要的时间就像90次迭代一样,用了100多小时的研究和实践。这一章将阐述了它们的架构,资源利用的设计理念等。
我在每个平台都启动了默认工具。Kubernetes运行一个叫做kube-up.sh的脚本来启动一个在某个云服务上的单主控节点的集群。大多数的Swarm教程和指导会让读者用Docker
Machine来生成集群(包括我自己)。然而两种方法都不能让集群扩到1000个节点。
为Kubernetes所创建的单主节点运行着etcd数据库、API服务、kubelet、scheduler,、controller-manager、
flannel、kube-proxy和 一个 DNS server。Kube-up.sh可以提供这个集群但只要一个有300个备份的备份controller节点准备运行,那么master节点的性能就会下降。内存不会产生问题,但这些负载会消耗CPU。资源消耗所产生不稳定性和性能问题,会导致集群不可用。
用Docker Machine部署机器太慢了,并且当生成一个1000节点的集群时,经常会遇到不可恢复的错误,造成无法成功部署。我最初的实验采用一些比如并行10个进程的方法。那会花费大约4个小时来创建前100个节点。当我增加并发数到100时,我马上就后悔这么做。
那导致我的第一次经历AWS的流量限速,并且导致AWS的web console不能用。
经过好几个小时,又创建了另外100个节点来弥补错误(大约有10%的错误率——机器挂了,不是Docker)。我承认这不是个好想法,并终止了实验。
自定义模板
当时我只在AWS上做测试。我选择了CloudFormation,因为这是云服务上自带的。但后来反思我觉得我还是应该使用Terraform来在其他云上测试。
我根据现有的最佳实践和社区专家的专业知识设计了每个模板。我首先注意到,Swarm大集群的最佳之间与我之前创建了100次的演示集群有着相同的架构。Kube-up提供的Kubernetes集群需要一个架构上的改变。两个架构图如下图所示。
左图:Swarm的节点和管理器直接依赖于基于etcd的键值对存储。而用户端直接与Swarm的管理器连接。右图:全部的Kubernetes节点,主组件和用户端通过一个横向扩展的API和一个负载均衡器通信。只有API服务与etcd通信。
上图中,“Docker Group”和“Node Group”是各个集群的1000个节点组成的组。这些是用户请求运行容器的机器。标注为“test-node”的机器用于跑测试。
有一个很有意思的地方是,根据Google这篇“Borg, Omega, and Kubernetes”文章描述,Swarm的框架与Omega类似。两个系统都让控制板组件直接与数据库连接。而Kubernetes把全部组件间的通信都集中在一个横向扩展的API上。
Kubernetes的API服务允许你根据资源和组类别关联数据库,通过设置--etcd-servers-overrides标志字就可以完成。我把热数据(例如指标和事件)与可操作资源如job和pod隔离开来。Kubernetes
large cluster configuration guide这篇指导描述了怎么关联数据库。实现1000个节点或更多节点的集群就需要这么做。
下图表示启动一个容器的不同序列以及不同顺序会怎么影响性能数据。每个灰色的列代表一个网络上的不同host。
启动Swarm(1)中的一个容器,就会有一个客户端连接到Swarm管理器。管理器执行一个基于以及采集好的资源数据设计的计划算法。然后(2)管理器会直接连接到目标节点,并且启动容器。当节点启动容器,它会反馈给管理器。管理器会立即给客户端响应。在操作的过程中,客户端的连接是打开的。
以下这个序列图是基于我对系统架构大致了解的介绍,可能会包含细节上的错误。该图忽略了大多数内部进程和非正式的交互(某些API服务或组件在工作是因为它在运行的状态,并不是因为它与一个请求在进行交互)。
在Kubernetes,(1)一个客户端通过一个负载均衡器连接到一个API服务,(2)会在etcd中产生一个资源。Etcd执行它的状态机然后(3、4)通过API服务器就新的资源数据更新观察者服务,之后,(5、6)controller-manager会对一个新的job请求做出响应并且通过再次调用API服务来创建一个新的pod资源。然后,(7、8)etcd会通过API更新这个新资源的监视器,(9)同时会触发程序调度器做一个新的调度决策,并且(10、11)通过API把pod指派给一个节点。最后,(12、13)etcd和API把指派信息通知目标Kubernetes节点并(14)启动容器。在容器启动之后,(15、16)会通过API来吧状态改变记录在etcd中。
Kubernetes的工作流程比Swarm涉及更多在网络的交互,API调用和数据库中的资源。同时,Swarm的架构缺少一个控制的中心点和一个组件来分担未来更多功能加进来时对数据库造成的负担。
在大规模的Kubernetes系统中,API机器的运行会占用15%到30%的CPU。数据库也差不多。Swarm的管理器会占用大约10%的CPU,而数据库大约是8%。
笔者个人猜想,Swarm可以再扩展几千个节点,数据库才会遇到一些问题。而Kubernetes扩展架构则需要更过的API
host(你会知道什么时候应该关注这些机器的CPU使用量)。
如何支持这些大规模系统是另一个问题
每个人都有自己的偏爱和己见。市场上的宣传,痛苦的经历,长长的评论栏,冷却的推测都会使偏爱升温。不做量化的综述,
我提出两种估算应用的方法,同样可以适用于估算建立一个系统所需的工作量。如果你有其他的定义或改进我的估算方法,我希望听到你的意见。
总的说来,Docker Swarm一定程度上比Kubernetes集群组件更加容易应用和支持。
应用工作量(adoption effort)指的是从一个新手到熟练地操作一项新技术所需要的工作量。这适用于一个团队采用一项新的技术和每次团队新增一个成员时的情景。观察发现,任何组件的学习曲线和这个组件的抽象概念的数量成正比,所以我提出下列这个公式来计算一个应用工作量指数(adoption
effort index ,AEI):
adoption effort = component count * abstraction count
就像AEI,一个运维工作量指数(a support effort index ,SEI)是一个指标,表示长期运维一个平台所需要的工作量级别是多少。基于笔者自己的实验,发现这个指数应该与组件之间交互序列的平均长度成比例。SEI反映了一个操作失败的机会数。我提出了以下的计算公式:
support effort = component count * interaction sequence
length
诸如此类的标准对于社区可以专注于讨论具体的论点是非常重要的。不然对话可能会变得模凌两可或情感导向。在这种情况下,社区的发展很难有进一步前进。
Kubernetes提供的功能相对于Swarm来说是一个超集。出于单项对比的考虑,我们只比较测试他们之间可以类比的组件。测试的Kubernetes配置有以下组件:
Docker Engine
kubelet binary
Pod-master
Controller-manager
Scheduler
API server
Etcd
一个包含网络环境的生产环境配置也需要包括:
Flannel
kube-proxy
kube-dns
测试的Swarm配置有如下组件:
Docker Engine
Swarm Manager
Swarm in Join Mode
etcd
一个multi-host的网络的Swarm集群应该只需要增加一个组件:libnetwork——这个是Docker
daemon的一部分——也在其他的一些工具如Flannel、Weave或者是Calico项目之中。
剔除通用组件(Docker Engine和etcd)和不计一些影响不大的组件,如负载均衡器等等之后,Kubernetes的组件数只剩5个,而Swarm只有2个。
Docker和Swarm提供相同的抽象功能,但Swarm还把集群本身抽象成为一台机器。相同的抽象有:
Containers
Images
Kubernetes还提供“集群”抽象,另外在测试中还使用以下抽象:
Containers
Images
Pods
Jobs
最终结果是Swarm的抽象数量为3,而Kubernetes是5个。Kubernetes的功能丰富,这个数字还忽略了“replication
controllers,” “services” 。采用这些抽象会提高AEI。
把这些数值插入到应用工作量指数等式中,得到的Kubernetes的指数是25,而Swarm是6。
对比支持工作量指数可以用模糊数学评估。据我所知,全部的Swarm操作都需要引入单个内部组件交互来完成。那么列举操作可能频繁使用这种并发的交互。Kubernetes中最短的操作可能是列举操作需要至少两步完成。我所理解的创建job操作需要5或更多的交互。
Swarm的运维工作量指数是2,Kubernetes是至少25。
反观这些数字,我想确定的是,很明显,选择Kubernetes并不是我的意图。这些数字反映Kubernetes是一个庞大的项目,有很多可移动的部分,有很多方面可以学习,但也有更多潜在失败的机会。即使如此,Kubernetes所完成的架构可以防止一些Swarm上已知的弱点,这就有可能产生更多深奥的问题和细微差别。
所调查的这些工作量可以作为参考,只作为一个实施者想要使用Kubernetes提供的扩展功能集所需要投入的时间与精力。
行动的召唤
整个工程社区似乎都醉心于容器和上述提到那些奇妙的工具之中。 我非常高兴有机会去实验或者实践其中的一些。
这些推动的力量加上这些工具帮助整个社区以比起以往更加快的速度推动技术的进步。
但是"拥有某个工具"和"理解某个工具在大生态圈中表现出来的优势和劣势"是有差别的。而优化一个没有任何衡量标准的工具是非常困难的。
因此,进一步的做类似的研究和开发对于整个社区而言是有益的。同时, 制定开放和可复验的测试基准,透明的分析过程和清晰的相关标准将会帮助决策制定者在一个数据驱动的环境中完成他的决策工作。
|