当开发者开始构建自己的第一款微服务应用程序时,大家通常不会过多考虑编排之类的问题。这时我们掌握的有两到四台服务器,而Ansible脚本已经能够解决大部分问题。不过一旦大家的应用程序规模更大,或者各位决定使用一套环境承载多个不同项目,那么必然需要更多服务器……还有一款用于管理各服务器之上运行的服务。 不过刚刚我们已经提到了Ansible,难道它还不足以解决问题?这个嘛……答案是否定的。Ansible只能解决一项难题——部署。利用它,大家仍然需要搞定其它多种与微服务相关的问题:我们必须记得每台服务器中还有多少剩余资源、手动管理各清单文件以匹配服务器容量、监控应用程序是否正常运行、当节点出现故障时进行服务回弹以及控制端口号冲突等等。如果大家拥有四台服务器与十项服务,那么这些问题就变得比较明显了。 而以此为基础,我们就需要求助于Mesos了。Mesos是什么?这是一款集群管理器,其能够帮助大家在分布式环境之下运行应用程序。Mesos的关键优势包括: *资源管理与使用效率; *应用程序生命周期控制; *Docker容器支持能力。 最后一点也使得Mesos成为我们最为完美的解决方案选项。 安装由于找到七台无需使用的服务器对于任何企业都是一项难题,因此我们在这里使用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实现的,也不属于我们今天的讨论重点。接下来让我们正式进入主题,通过Ansible设置集群。 集群正如大家在Vagrantfile当中所见,这里有3套主剧本及其各自角色: 主角色- 主机包含: Mesos主实例; Zookeeper实例; Marathon实例; Bamboo + HaProxy实例; 节点- 主机包含: Mesos从实例; Docker服务; Logstash实例; MesosDns实例; 日志- 主机包含: ElasticSearch实例; Kibana + Nginx实例。 接下来,我们将分别考虑各个角色,但这里需要首先强调一点:每个角色都取决于“OS”角色。该角色与本地网络及YUM repo的DNS配置设置相关。严格地讲,我们应当将这种关联性从剧本层级中剥离出来,但为了简单起见,这里我们先让其保持原状。 ZookeeperZookeeper属于我们系统中的一大重要组成部分。它将帮助我们构建集群并允许来自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进行服务发现: 另外还有一套客户端负载均衡机制(我们当然需要尽可能减少故障点数量,对吧?): |
|