这是一篇“温和有趣”的技术文章,若是你初识Docker,对微服务充满兴趣,不妨一读。或许你的第一次微服务体验,就从本文开始……node
在本文中,Mesos、Zookeeper、Marathon、Bamboo + HaProxy、Logstash、MesosDns、ElasticSearch和Kibana + Nginx等纷纷亮相,并配有详细的代码说明。本文旨在从最初的安装和环境基础创建开始,一步步指引你搭建本身的集群,实现你的目标架构,并在其上运行分布式服务。算法
小数友情提示:本文篇幅很长,干货多多,值得收藏。docker
当开发者开始构建本身的第一款微服务应用程序时,你们一般不会过多考虑编排之类的问题。这时咱们掌握的有两到四台服务器,而Ansible脚本已经可以解决大部分问题。不过一旦你们的应用程序规模更大,或者各位决定使用一套环境承载多个不一样项目,那么必然须要更多服务器……还有一款用于管理各服务器之上运行的服务。服务器
不过刚刚咱们已经提到了Ansible,难道它还不足以解决问题?这个嘛……答案是否认的。Ansible只能解决一项难题——部署。利用它,你们仍然须要搞定其它多种与微服务相关的问题:咱们必须记得每台服务器中还有多少剩余资源、手动管理各清单文件以匹配服务器容量、监控应用程序是否正常运行、当节点出现故障时进行服务回弹以及控制端口号冲突等等。若是你们拥有四台服务器与十项服务,那么这些问题就变得比较明显了。网络
而以此为基础,咱们就须要求助于Mesos了。Mesos是什么?这是一款集群管理器,其可以帮助你们在分布式环境之下运行应用程序。Mesos的关键优点包括:架构
资源管理与使用效率;负载均衡
应用程序生命周期控制;框架
Docker容器支持能力。curl
最后一点也使得Mesos成为咱们最为完美的解决方案选项。tcp
因为找到七台无需使用的服务器对于任何企业都是一项难题,所以咱们在这里使用Vagrant(这是一款管理虚拟化流程的完美工具)在一台本地设备(惠普Z230,i7-4770 3.40 GHz,16 GB内存)上构建本身的集群。另外,咱们也提到了Ansible是一种便捷的部署方式,所以咱们彻底能够将整个安装流程拆分红多个Ansible角色,从而封装其内部所须要使用的标准Linux命令。
首先,咱们须要创建Mesos集群基础——这是一系列虚拟机系统,供咱们在如下步骤中使用。这项工做利用Vagrant可以轻松完成。
如下为来自Vargantfile的部分代码:
如你们所见,咱们可使用一点Ruby代码执行如下步骤:
基于CentOS 7.1镜像构建虚拟机;
设置各虚拟机的资源上限(CPU与内存);
将其与一套网络相结合;
*利用每台主机上的一组预约义变量启动一套Ansible剧本(ansible/master.yml)。
简单来说,Vagrant文件负责描述如何构建7套虚拟机系统:3套主虚拟机、3套从虚拟机与1套日志存储(从技术层面讲,这部分也应该进行分布处理,不过主机设备的资源较为有限)。你们须要作的是利用下面这条简单命令将其投入运行:
`vagrant up`
前三步都是由Vagrant实现的,也不属于咱们今天的讨论重点。接下来让咱们正式进入主题,经过Ansible设置集群。
正如你们在Vagrantfile当中所见,这里有3套主剧本及其各自角色:
主角色- 主机包含:
Mesos主实例;
Zookeeper实例;
Marathon实例;
Bamboo + HaProxy实例;
节点- 主机包含:
Mesos从实例;
Docker服务;
Logstash实例;
MesosDns实例;
日志- 主机包含:
ElasticSearch实例;
Kibana + Nginx实例。
接下来,咱们将分别考虑各个角色,但这里须要首先强调一点:每一个角色都取决于“OS”角色。该角色与本地网络及YUM repo的DNS配置设置相关。严格地讲,咱们应当将这种关联性从剧本层级中剥离出来,但为了简单起见,这里咱们先让其保持原状。
Zookeeper属于咱们系统中的一大重要组成部分。它将帮助咱们构建集群并容许来自Mesos生态系统中的其它应用程序(例如Bambbo、MesosDns)与之进行通讯。
Zookeeper的安装过程很是简单,并且不须要什么技巧——从RPM软件包中获取一套repo便可。我发现不少朋友倾向于利用现有源代码构建应用,但在这里咱们将使用基于供应商的Mesosphere软件包。
你们须要的就是安装该软件包,设置节点ID,更新配置并启动该服务。
下面来看Zookeeper安装任务中的代码片断:
在这里,咱们须要回顾一下前面提到过的Vagrantfile——你们还记得下面这部份内容吗?
Vagrant将所有必要的变量传递至Ansible,所以咱们能够轻松在角色中对其加以利用。
正如Zookeeper的配置同样,咱们只须要对其中的主机IP进行配置:
如下为咱们集群最终状态下的简单Zookeeper UI(简称ZK UI)屏幕:
正如以前所提到,MesoSphere的工做人员很是贴心地把Mesos软件包加以整合,所以整个安装流程也将变得更加轻松。
其中唯一须要注意的是,Mesos实际上由两部分构成:
主节点(负责所有管理逻辑);
从节点(负责运行应用并收集与主机资源相关的信息);
换句话来讲,咱们须要为主节点与从节点实现不一样的安装逻辑。幸运的是,Ansible可以很是轻松地完成这项任务。
如下为Mesos安装任务的代码片断:
面向这两者,咱们须要安装“mesos”软件包(请记住,相关repo由“OS”角色提供)与Zookeeper URL。
下一站是进行设定。在这里,咱们只提供诸如主节点quorum size与从节点docker支持等强制性设定。若是你们但愿了解更多与特定配置相关的内容,不妨阅读Mesos官方说明文档。
因为MesoSphere软件包同时提供主与从服务,所以咱们须要根据当前角色(主/从)禁用其中的冗余部分。
为实现这一目标,你们应当使用Ansible的“conditional”机制。若是你们曾经认真阅读过“master”剧本,就会发现咱们已经传递了一条特殊的mesos_type变量:
在Mesos安装完成后,你们能够审视其Web UI并尝试点击其中的按钮:http://192.168.99.11:5050。
须要注意的是,若是当前主机并不是Mesos Master的集群主节点,那么UI会将你们从新定向至主节点主机。另外,因为咱们在虚拟机当中使用了DNS快捷方式(例如“master1”),所以你们也应当在本身的主机设备上使用一样的快捷方式。
好了,就是这样——咱们的集群已经构建完成了。
在痛饮庆功酒以前,咱们还须要回顾其中一些有趣的细节。
首先,你们须要记住——每一个任务都拥有本身的背景信息,咱们将其称为“sandbox”。你们能够将其打开并分析所有输出结果(可参阅Marathon部分的截屏内容)。须要注意的是,Docker容器必须首先进行pull——所以,若是你们没有分配足够的时间用于容器启动,那么任务可能没法在UI中w/o任何消息(你们仍然可以在相关节点的/var/logs/messages中看到消息内容):
要对其进行修复,须要如以上片断所示配置其中的
另外,也不要忘记设置运行状态检查的宽限时长(Java应用每每会长时间处于活动状态)。不然你们的应用极可能被关闭,并在其从新启动前进行回弹(运行状态检查设定问题稍后咱们再继续讨论):
因为咱们须要在本身的从主机上运行Docker容器,所以在这些主机上安装Docker本体就成了必要任务。幸运的是,其安装过程很是简单:
下面来看Docker安装任务中的代码片断:
该步骤后的集群状态:
尽管咱们的Mesos集群已经上线并开始运行,但咱们仍然没法在其上运行本身的Docker容器。严格地讲,这时咱们可以在Mesos上直接运行的只有一套Mesos框架。固然,咱们还拥有另外一个更符合需求的选项——Marathon。
从技术角度来看,Marathon只是一款简单的Java软件包,且可以经过jar命令进行启动。但好在咱们还拥有一套RPM软件包,所以咱们不须要担忧其“后台化”、配置与控制等问题。此外,因为咱们的软件包由MesoSphere负责提供,所以其使用的是一样的配置文件(Zookeeper URL),因此咱们不须要对其另行设置。
Marathon安装任务中的代码片断:
Marathon还拥有一套Web UI,你们能够经过URL: http://master1:8080
进行访问。
下面让我们找点乐子,部署一项简单的REST服务(该服务及部署设定稍后另行讨论):
如今咱们已经能够监控其状态以及分配端口:
所以,咱们能够对其进行调用并检查其是否正常工做(固然,结果一切正常)。
咱们甚至能够对服务进行规模扩展——若是有必要的话(目前规模扩展尚未任何意义):
另外,经过“sandbox”分析其日志(经过Mesos UI):
在以上示例当中,咱们只部署了一个服务实例。不过若是咱们但愿在其中使用大量实例与负载均衡机制,又该如何处理?这个嘛,做为答案的一部分,咱们将采用HaProxy。这确实是一款很是出色的负载均衡器。不过如何对其进行配置?很简单,交给Bamboo项目处理便可——它可以与Zookeeper相对接,读取Mesos状态并生成HaProxy配置(利用每款Mesos应用的用户定义角色)。
其安装过程原本很是简单,不过遗憾的是目前尚未任何集成有Bamboo软件包的公共RPM repo。你们能够对其进行手动构建,并经过本地文件实现安装,但整个过程其实有点复杂。
如下为Bamboo安装任务中的代码片断:
在Bamboo安装完成以后,你们能够经过其Web UI进行设置: http://master1:8000
另外也能够经过HaProxy访问咱们的服务: http://master1/services/fibonacci/1
请注意,咱们在Bamboo安装中使用了单独的Ansible剧本(master_bamboo.yml)。之因此这样处理,是由于咱们须要借此保证其RPM软件包在于剧本内运行以前被上传至虚拟主机当中。
因为Vagrant会在虚拟机初始化过程当中自动执行Ansible配置任务,所以唯一的解决办法就是将Bamboo相关内容提取至单独的剧本当中,并执行如下算法:
利用vagrant up启动虚拟机;
将RPM文件经过SCP上传至虚拟机当中;
对Vagrantfile中的ansible.playbook进行变动;
运行vagrant provision master1命令。
如你们所见,Bamboo是整套生态系统中最为杂乱的部分。因此咱们不妨了解其替代方案——例如Marathon负载均衡器。
该步骤后的集群状态:
咱们一直没有谈到一个重要的问题——若是咱们的服务须要彼此进行通讯,该如何加以实现?咱们是否可以立足于单一Mesos集群内部实现服务发现?是的,答案是确定的!相关方案也很是明确——MesosDns。这里咱们的解决思路很是明确——读取Mesos集群状态并经过DNS(A与SRV记录)及HTTP API进行发布。后一点很是重要,由于这将帮助咱们轻松构建客户端负载均衡w/o【1,2】。
整个安装过程稍有些麻烦,不过没什么特别之处须要注意。
如下为MesosDns安装任务中的代码片断:
Config文件中也没有什么值得一提的内容:
你们能够经过如下SRV记录请求检查已安装的实例:
http://172.17.42.1:8123/v1/services/_fibonacci-service._tcp.marathon.mesos.
欢呼!咱们距离成功已经很近了!必须认可,若是你们已经耐着性子读到这里,那么这个议题确定很是有趣。
值得庆幸的是,这部分并无太多内容可谈。日志记录就是日志记录。咱们只须要将Logstash安装在所有Mesos从节点当中便可……
如下为LogStash安装任务中的代码片断:
另外对其config文件进行配置,确保将数据发布至日志节点当中:
与此同时,咱们还须要在这些节点上安装ElasticSearch与Kibana。
ELK安装任务中的代码片断:
这里使用Docker的唯一理解就是其更为简便。固然,咱们也不须要也不该该将日志数据保存在容器当中。
在安装完成以后,你们就能够经过Kibana的Web界面分析ES当中的日志了:http://log1:5601
下面就是咱们的目标架构,或者说咱们的最终构建成果。看起来不错,对吧?
图十八
在咱们的脚本当中,唯一的单点故障来源就是HaProxy/Bamboo。不过你们能够将两者部署至所有主节点当中并面向用户使用基于DNS的轮循机制,从而轻松解决这个问题。
到这里咱们已经拥有了本身的集群。如今,是时候考虑咱们计划运行于其上的分布式服务了(运行简单应用太过无聊,这里再也不赘述)。
我已经开发出了一套基于REST服务的小巧SpringBoot,其可以计算斐波那契序列中的第N个数字。这项服务的核心功能在于,其能够调用自身其它实例以计算该序列中的前一个值。
我知道,这种实现方式效率极低并且很容易致使死锁(你们不妨想一想这是为何),但我在这里主要是借此对跨服务通讯进行说明。
该服务利用MesosDns HTTP API进行服务发现:
另外还有一套客户端负载均衡机制(咱们固然须要尽量减小故障点数量,对吧?):
在咱们开始部署工做以前,首先须要为本身的应用程序构建一套Docker镜像。在这里我就不赘述整个流程了,感兴趣的朋友能够查看Gradle配置与Docker说明文件了解相关内容。
完成以后,咱们将该镜像发布至一套Docker注册表当中(也能够经过Gradle实现),这样Marathon就可以经过从节点上的Docker实例对其进行下载了。你们能够在这里找到我建立的示例: https://hub.docker.com/r/krestjaninoff/fibonacci-service/
最后也是最重要的部分,Marathon。如以前所提到,咱们能够利用Marathon UI实现部署任务。不过这并非最具“技巧性”的办法。Marathon也拥有本身的REST API,咱们能够经过简单的“curl”客户端对其加以使用:
如下为SpringBoot mesos installation manifest中的代码片断:
让我来简单介绍一下该配置文件中的内容(各部分逐一说明):
应用程序 id (在Bamboo配置中使用);
资源限制(若是该集群不具有必要容量,应用程序将不会启动——这一点对于基于虚拟机的集群尤其重要)与实例数量;
容器设置:
forcePullImage是在正确时间点对容器进行更新的唯一方式;
SpringBoot容许咱们经过各环境变量进行config文件覆盖,所以这是一种良好的容器操做方式;
因为$HOST变量负责提供DNS名称(这一点甚至在Marathon官方说明文件中亦没有体现),所以从Docker容器内获取主机本地IP的唯一方式就是默认Docker网络接口172.17.42.1;
backoff因数/设定避免集群运行“异常”应用,即没法正常启动并将所以形成反复尝试的应用(具体方式为延后每一次启示尝试);
运行状态检查容许Marathon了解应用实例处于正常运行抑或是必须执行回弹;
upgradeStrategy帮助你们在无需接入能力的前提下实现应用更新(首先延后新版本,然后中止当前版本)。
最后要提到的是Bamboo,其一样能够经过REST API进行配置。这项任务很是简单:
到这里,咱们就已经拥有了“deploy”角色……
如下为Deployment安装任务中的代码片断:
你们能够经过运行“deploy”剧本的方式进行调用:
到这里所有结束!
调用该服务 curl http://master1:5000/service/fibonacci/15 (或者直接调用curl http://node2:31135/15);
检查结果(正确值为610);
检查日志内容(http://log1:5601)。
最后一点很是有趣。你们能够看到哪台主机被调用或者响应耗费了多长时间:
好了,今天的文章到这里就结束了。没错,其篇幅远超通常的“Hello World”指南——不过平心而论,内容仍是很是有趣的,对吧?
英文原文连接:http://trustmeiamadeveloper.com/2015/12/17/mesos-as-a-docker-containers-farm/