【编者的话】Kubernetes是Google开源的容器集群管理系统,其提供应用部署、维护、 扩展机制等功能。Mesos是Apache下的开源分布式资源管理框架,它被称为是分布式系统的内核。Mesos最初是由加州大学伯克利分校的AMPLab开发的,后在Twitter得到广泛使用。Swarm是Docker公司在2014年12月初新发布的容器管理工具。和Swarm一起发布的Docker管理工具还有Machine以及Compose。我们来看下Rancher对它们有什么评价。

题记:这篇文章出版时我们已经要求提供一个可下载版本,你可以点击


Rancher最新的版本在原有官方标准编排工具Cattle的基础上,新增支持其他几种常用的编排引擎。新增支持的编排引擎包括Swarm(Docker未来本地编排引擎)、Kubernetes和Mesos,它们都是Docker社区中最广泛使用的编排系统,满足用户不同梯度的使用性和特性。尽管Docker是既定事实上的行业容器标准,但是在容器编排上还没有绝对的赢家。这篇文章中我们我们主要介绍三种编排工具的特性,以及适应的场景。

目前Docker原生编排还处于初期阶段,但是新的特性在快速迭代增加中。由于原生的编排工具是官方系统的一部分,因此它成为众多开发者的默认首选编排工具,顺理成章地最有可能成为最受社区欢迎支持的工具。Kubernetes是谷歌支持的容器编排工具,它在众多容器编排工具中用的最广泛的一个。最近,Mesos和Mesosphere(Marathon的开源版)把更多的精力放在服务管理,将更多的功能留给可插拔插件和应用程序管理。这样的话,就使得应用最终容易容易定制部署,因为单个的程序更容易被更新,定制化。然而,这也意味着我们必须要修改一些设置来适配。Kubernetes更关注的是如何构建集群和在常见场景中用例的通用系统集成。

Docker Native Orchestration


基础架构

Docker 1.12引擎中附带了原生的编排工具,对独立的Docker Swarm来说是一种替代。Docker本地集群(Swarm)包涵一系列节点(Docker进程/守护进程),他们同时管理集群及提供工作服务。你可以在容器中启动工作进程也可以启动管理进程维护集群的状态。多管理模式保证了系统的高可用性,但是不推荐超过7个以上管理员用户。内部通过实现主从的一致性。与所有一致性的算法是一样的,多管理中心达到一致性的实现。实际上保持内部管理的一致也意味着Docker本地的编排不依赖外部资源,这样也是集群的管理变得更加容易。

可用性

Docker本机使用单节点Docker的概念,并将它们扩展到Swarm。如果你使用最新的Docker版本,那么学习曲线还是相当平缓的。一旦你想添加已经在多节点运行的Docker到Swarm中,Swarm的设置是很简单的:你只需在其中一个节点上调用docker swarm init,然后在任何其他你想添加的节点上调用docker swarm join即可。您也可以使用相同的Docker Compose模板和相同的Docker CLI命令集设计单一的Docker。

功能集

Docker本地可以使用与Docker Engine和Docker Compose相同的语法提供编排支持。你仍然可以链接到服务,创建卷,定义开放的端口号。所有的这些操作都适用于单个的节点,除了这些新增了两个新的概念:服务和网络。

Docker服务是您的节点上启动的一组容器,并且保持这些批量的容器运行。如果其中一个容器停止,它将被自动替换掉。其中服务分类两类:复制和全局。复制服务在集群中维护指定数量的容器,因为全局服务在每个集群节点上运行一个实例。要创建复制服务,请使用下面的命令:

docker service create          \–name frontend              \–replicas 5                 \-network my-network         \-p 80:80/tcp nginx:latest.


现在可以使用docker network create –driver overlay NETWORK_NAME创建命名为overlay的网络。使用overlay网络我们可以创建一个孤立、扁平、加密的虚拟网络环境用来启动容器。你可以使用约束和标签来做一些非常基本的容器调度。使用约束可以向服务添加关联,并且它将尝试仅启动具有特殊标签的容器。

docker service create                        \–name frontend                            \–replicas 5                               \-network my-network                       \--constraint engine.labels.cloud==aws     \--constraint node.role==manager           \-p 80:80/tcp nginx:latest.


此外,你可以使用保留的CPU和保留的内存空间标志来定义服务的每个容器使用的资源,以便在swarm上启动多个服务时,容器可以处理最小的资源竞争。

你可以使用以下命令进行初步的部署。这样将会更新容器的镜像,但是两个容器之间有10s的间隔来更新两个容器。然而,health-checks和自动回滚都不支持。

docker service update        \–name frontend            \–replicas 5               \-network my-network       \--update-delay 10s        \--update-parallelism 2    \-p 80:80/tcp nginx:other-version.


Docker使用卷驱动程序支持外部卷持久化,并且使用mount服务命令扩展器使用。执行以下代码段将会将NFS装入到您的容器中。请注意,这需要在Docker外部的底层主机上设置NFS。在没有主机支持的情况下,其他对Amazon EBS卷或Google容器引擎卷驱动程序也能够工作。此外,这个功能还没有完善的文档,可能需要需要在github的docker项目上创建issues得到交流回复。

--mount type=volume,src=/path/on/host,volume-driver=local,\dst=/path/in/container,volume-opt=type=nfs,\volume-opt=device=192.168.1.1:/your/nfs/path


Kubernetes


基础架构

从概念上讲,Kubernetes有点类似于Swarm,它使用一个带有RAFT的管理器(主)节点来达成一致。然而,相似的地方也只有这么多了。Kubernetes使用外部etcd集群为此目的。此外,你将需要Kubernetes外部的网络层,这样overlay 网络就行编织法兰绒外衣一样。使用这些外部工具,您可以启动Kubernetes主组件; API服务器,控制器管理器和调度程序。这些通常作为主节点上的Kubernetes pod运行。除了这些,你还需要在每个节点上运行kubelet和kubeproxy。如果需要的话,工作节点只运行Kubelet和Kubeproxy以及像一个包装一样作为网络层提供者。


在这个设置中,kubelet将控制给定节点上的容器(或者pod)与主控制器上的控制器管理器。主节点上的调度器负责资源分配和平衡,并且将帮助在具有最多可用资源的工作节点上放置容器。 API控制器是您的本地kubectl CLI将向集群发出命令的地方。最后,kubeproxy用于为Kubernetes中定义的服务提供负载平衡和高可用性。

可用性

从头开始设置Kubernetes是一个不平凡的努力,因为它需要设置etcd,网络插件,DNS服务器和证书颁发机构。从头开始设置Kubernetes的详细信息可以在这里,但幸运的是Rancher为我们完成所有这些设置。我们在中介绍了如何设置Kubernetes集群。

除了初始设置,Kubernetes仍然有一些陡峭的学习曲线,因为它使用自己的术语和概念。 Kubernetes使用资源类型,如Pods,部署,复制控制器,服务,守护进程集等来定义部署。这些概念不是Docker专门词汇的一部分,因此您需要在开始创建第一个部署之前熟悉它们。此外,一些命名与Docker冲突。例如,Kubernetes服务不是Docker服务,也是概念上不同的(Docker服务更贴近地映射到Kubernetes世界中的Deployments)。此外,您使用kubectl而不是docker CLI与集×××互,并且必须使用Kubernetes配置文件而不是docker compose文件。

Kubernetes有这样一套详细的概念独立于core Docker,这本身不是一件坏事。 Kubernetes提供比core Docker更丰富的功能集。然而,Docker将添加更多的功能来与Kubernetes竞争,具有不同的实现和不同或冲突的概念。这将几乎肯定重复CoreOS / rkt情况,大部分社区在类似但竞争的解决方案。今天,Docker Swarm和Kubernetes定位于不同的使用场景(Kubernetes更适合于使用专用集群管理团队的面向服务的架构的大型生产部署),但是随着Docker 本地编排的成熟,它将迁移到这个空间。

功能集

Kubernetes的完整功能集太大,这篇文章不能涵盖完整,但我们将介绍一些基本概念和一些有趣的区分。首先,Kubernetes使用Pods的概念作为基本单位,而不是单个容器。每个pod是一组容器(集合大小可以是一个),它们总是在同一节点上启动,共享相同的卷并分配一个虚拟IP(VIP),以便可以在集群中寻址。单个pod的Kubernetes规范文件可能如下所示:

kind: Podmetadata:name: mywebservicespec:containers:- name: web-1-10p_w_picpath: nginx:1.10ports:- containerPort: 80


接下来是你的部署。这些松散地映射具体到什么服务是在Docker本地编排。您可以像Docker Native中的服务一样扩展部署,部署将确保正在运行的请求数量的容器。重要的是注意部署仅类似于Docker本地中的复制服务,如Kubernetes使用守护程序集概念来支持其等效的全局调度服务。部署还支持使用HTTP或TCP可达性或自定义exec命令来确定容器/ pod是否正常的运行状况检查。部署还支持使用运行状况检查的自动回滚滚动部署,以确定每个pod部署是否成功。

kind: Deploymentmetadata:name: mywebservice-deploymentspec:replicas: 2 # We want two pods for this deploymenttemplate:metadata:  labels:    app: mywebservicespec:  containers:  - name: web-1-10    p_w_picpath: nginx:1.10    ports:    - containerPort: 80


接下来你有Kubernetes服务,它为部署提供简单的负载平衡。部署中的所有pod都将在服务进入和退出时注册,服务也抽象出多个部署,因此如果您想回滚部署,您将使用相同的服务注册两个Kubernetes部署,然后逐个添加pod同时减少pods从其他。您甚至可以进行blue-green部署,您可以一次性将服务指向新的Kubernetes部署。最后,服务对于Kubernetes集群中的服务发现也很有用,集群中的所有服务都获得VIP,并且作为docker链接样式环境变量以及通过集成的DNS服务器暴露给集群中的所有pod。

除了基本服务,Kubernetes支持作业和。作业创建一个或多个pod,并等待它们终止。作业确保指定数量的pod成功终止。例如,您可以开始一个作业,在最后一天开始处理1小时的商业智能数据。您将启动一个包含前一天的24个pod的作业,一旦它们都运行完成,作业完成。作为名称建议的计划作业是在给定计划上自动运行的作业。在我们的例子中,我们可能使我们的BI处理器是每日计划的工作。作业非常适合向集群发出批处理工作负载,这些负载不总是需要启动的服务,而是需要运行到完成然后清理的任务。

Kubernetes提供给基本服务的另一个扩展是Pet Sets。Pet Sets支持状态服务工作负载,通常很难集中化。这包括数据库和实时连接的应用程序。Pet Sets为集合中的每个“Pet”提供稳定的主机名。Pet就是索引。例如,pet5将独立于pet3可寻址,并且如果第三Pet容器/ pod死掉,则它将在具有相同索引和主机名的新主机上重新启动。

Pet Sets还提供使用持久卷的,即如果pet1死亡并在另一个节点上重新启动,它将获得其重新安装原始数据的卷。此外,您还可以使用NFS或其他网络文件系统在容器之间共享卷,即使它们在不同的主机上启动。这解决了从单主机到分布式Docker环境转换时最有问题的问题之一。

Pet Sets还提供对等发现,通常可以发现其他服务(通过Docker链接等)。然而,发现服务中的其他容器是不可能的。这使得类似Cassandra和Zookeeper基于gossip协议的服务非常难以启动。

最后,Pet Sets提供启动和拆卸排序,这是持久、可扩展的服务,例如Cassandra。 Cassandra依赖一组种子节点,当您上下扩展服务时,必须确保种子节点是第一个启动的节点和最后一个要删除的节点。在撰写本文时,Pet Sets是Kubernetes的一大特色,因为在没有这种支持的情况下,持久的有状态工作负载几乎不可能在Docker的生产规模上运行。
Kubernetes还提供命名空间来隔离集群上的工作负载,保护管理和自动扩展支持。所有这些特性更意味着Kubernetes也支持大型,多样化的工作负载,Docker Swarm目前还没有准备就绪。

Marathon


基础架构

大规模集群的另一个常见的编排设置是在Apache Mesos之上运行Marathon。 Mesos是一个开源集群管理系统,支持各种工作负载数组。 Mesos由在群集中的每个主机上运行的Mesos代理组成,它向主机报告其可用资源。可以有一个或多个Mesos主机使用ZooKeeper集群进行协调。在任何给定时间,主节点之一使用主选举过程是活动的。主服务器可以向任何Mesos代理发出任务,并报告这些任务的状态。虽然您可以通过API发出任务,但正常的方法是在Mesos之上使用一个框架。 Marathon是一个这样的框架,它为运行Docker容器(以及本地Mesos容器)提供支持。

可用性

与Swarm相比,Marathon有一个相当陡峭的学习曲线,因为它不与Docker共用大部分概念和术语。然而,马拉松并不复杂,因此比Kubernetes更容易学习。然而,管理Marathon部署的复杂性来自于它是分层在Mesos,因此有两层工具要管理。此外,Marathon的一些更高级功能(如负载平衡)仅作为在Marathon之上运行的附加框架提供。某些功能(如身份验证)只有在DC / OS上运行Marathon时才可用,而后者又在Mesos上运行 - 为堆栈添加另一层抽象。

功能集

要在Marathon中定义服务,您需要使用其内部JSON格式,如下所示。一个简单的定义,如下面的一个将创建一个服务,每个运行nginx容器的两个实例。

{"id": "MyService""instances": 2,"container": {"type": "DOCKER","docker": {  "network": "BRIDGE",  "p_w_picpath": "nginx:latest"}}}


以上定义稍微更完整的版本如下所示,我们现在添加端口映射和health check。在端口映射中,我们指定一个容器端口,这是docker容器公开的端口。主机端口定义主机公共接口上的哪个端口映射到容器端口。如果为主机端口指定0,则在运行时分配随机端口。类似地,我们可以可选地指定服务端口。服务端口用于服务发现和负载平衡,如本节后面所述。使用健康检查,我们现在可以执行滚动(默认)和 部署。

{"id": "MyService""instances": 2,"container": {"type": "DOCKER","docker": {  "network": "BRIDGE",  "p_w_picpath": "nginx:latest"  "portMappings": [    { "containerPort": 8080, "hostPort": 0, "servicePort": 9000, "protocol": "tcp" },  ]}},"healthChecks": [{  "protocol": "HTTP",  "portIndex": 0,  "path": "/",  "gracePeriodSeconds": 5,  "intervalSeconds": 20,  "maxConsecutiveFailures": 3}]}


除了单一服务之外,您还可以定义Marathon应用程序组,使用嵌套树结构的服务。在组中定义应用程序的好处是能够将整个组缩放在一起。这在微服务堆栈中非常有用,其中调整单个服务可能是困难的。到目前为止,扩展假设所有服务将以相同的速率扩展,因此如果您需要一个服务的“n”个实例,您将获得所有服务的“n”个实例。

{"id": "/product","groups": [{  "id": "/product/database",  "apps": [     { "id": "/product/mongo", ... },     { "id": "/product/mysql", ... }   ]},{  "id": "/product/service",  "dependencies": ["/product/database"],  "apps": [     { "id": "/product/rails-app", ... },     { "id": "/product/play-app", ... }  ]}]}


除了能够定义基本服务之外,Marathon还可以基于指定约束来执行容器的调度,包括指定服务的每个实例必须在不同的物理主机“约束”上:[[“hostname”, “UNIQUE”]]。您可以使用cpus和mem标记来指定该容器的资源利用率。每个Mesos代理报告其总资源可用性,因此调度程序可以以智能方式在主机上放置工作负载。

默认情况下,Mesos依赖于传统的Docker端口映射和外部服务发现和负载平衡机制。但是,最近的测试功能添加了对使用Mesos DNS的DNS服务发现或使用Marathon LB的负载平衡的支持。 是一个在之上运行的应用程序,它查询Mesos API以获取所有正在运行的任务和应用程序的列表。然后,它为运行这些任务的节点创建DNS记录。然后,所有Mesos代理手动更新,以使用Mesos DNS服务作为其主DNS服务器。 Mesos DNS使用用于向主机注册Mesos代理的主机名或IP地址;并且端口映射可以查询为SRV记录。由于Marathon DNS在代理主机名上工作,并且主机网络端口必须被公开,因此不能发生冲突。 Mesos DNS确实提供了一种方法来为状态负载持续引用单个容器,例如我们将能够使用Kubernetes宠物集。此外,与群集中任何容器上可寻址Kubernetes VIP不同,我们必须手动将/etc/resolve.conf更新到Mesos DNS服务器集,并在DNS服务器更改时更新配置。 使用马拉松赛事总线跟踪所有服务的启动和撤销。然后,它在代理节点上启动HAProxy实例,以将流量中继到必需的服务节点。

Marathon还对以及提供测试支持。然而,这两个特征都处于非常原始的状态。持久卷只在容器重新启动的单个节点上持久化,但是如果删除使用它们的应用程序,则会删除卷,但磁盘上的实际数据不会被删除,必须手动删除。外部卷需要DC / OS,并且当前只允许您的服务扩展到单实例。

最终裁决

今天我们看了Docker容器编排的三个选项:Docker Native(Swarm),Kubernetes和Mesos / Marathon。很难选择一个系统来推荐,因为最好的系统高度依赖于你的用例,规模和历史。此外,所有三个系统都在大量开发,一些涵盖的功能是测试版,可能会很快更改,删除或替换。

Docker Native给你提供了最快的升级,很少甚至没有供应商的封闭超出了对Docker的依赖。对Docker的依赖不是一个大问题,因为它已经成为了实际上容器标准。鉴于在编排战争中缺乏明确的赢家,而且Docker本机是最灵活的方法,因此它是简单的web/stateless应用程序的不错选择。但是,Docker Native目前还只是一个架子,如果你需要得到复杂的,大规模的应用程序到生产,你需要选择一个Mesos / Marathon或Kubernetes。

在Mesos / Marathon和Kubernetes之间也不是一个容易的选择,因为两者都有自己的优点和缺点。 Kubernetes肯定是更丰富和成熟的两个,但它也是一个非常有见地的软件。我们认为很多这些意见是有意义的,但Kubernetes没有马拉松的灵活性。这是有道理的,当你考虑非Docker,非容器化的应用程序,可以运行在Mesos除了Marathon(例如Hadoop集群)的丰富的历史。如果你正在做一个绿色领域实施,也没有强烈的意见,如何布局集群,或你的意见同意谷歌,那么Kubernetes是一个更好的选择。相反,如果你有大的,复杂的遗留工作负载,将逐渐转移到容器,那么Mesos / Marathon是要走的路。

另一个问题是规模:Kubernetes已经测试了数千个节点,而Mesos已经测试了成千上万的节点。如果您正在启动具有数万个节点的集群,则需要使用Mesos来获得底层基础架构的可扩展性 - 但请注意,将高级功能(例如负载平衡)扩展到该范围仍将保留。然而在这样的规模下,除了仔细调整和猴子补丁(一种运行时动态替换的热更新方法,编者注),很少再有现成的解决方案能够直接使用。

Usman是一名服务器和基础设施工程师,具有在各种云平台之上构建大规模分布式服务的经验。你可以在上阅读更多他的工作,或者在twitter 或者上关注他。

原文链接:(翻译:ylzhang)