几周前,我曾写过一篇关于基于容器的应用的服务发现的文章,并为已存在的应用提供了一个工具来实现这类工作,并展示了一个动态更新Nginx虚拟主机配置的例子,展示了如何基于容器的变化来更新外部的DNS。本文将会将上述内容整合到一个多层级的应用中用于作为一个微服务架构的蓝图(原型)。本文所述例子的源代码请参考Github仓库。
原文地址:http://thenewstack.io/microservices-seconds-node-js-docker-nosql/
译者:景庄,前端工程师,关注前端工程化技术、Node、ES6、React等。
本文我们将要整合的应用名叫Touchbase,它是一个Node.js应用。主要包括如下几个部分:
该技术栈可以被用于任何微服务应用,并且每一个独立组件都可以被轻松的置换(swap out)掉。如果你更喜欢HAProxy而不是Nginx?没问题——只需要更新docker-compose.yml
文件,替换为你想要使用的镜像即可。
Node.js应用Touchbase是由Couchbase实验室编写的,主要用于演示Couchbase 4.0的新的N1QL查询特性。它并不是针对容器化应用而设计的,因此我们需要使用Containerbuddy来使其满足我们在服务发现上的基本需求。
Touchbase使用Couchbase作为数据层。我们可以使用它来直接处理请求,但我们并不准备这么做,而是在其前方增加一个Nginx作为负载均衡器,因为我们想要借助Nginx的能力来实现零停机时间的配置重载。(在真实的生产环境中,在Nginx后面可能包括多个应用)我们将会使用Touchbase的一个去除了SendGrid配置信息的Fork版本,因为配置交易邮件服务并不在本文的讨论范围内。
Touchbase服务的Containerbuddy有一个onChange
事件的处理器,用于调出consul-template
并基于存放在Consul中的模版来编写新的config.json
文件。遗憾的是,Touchbase并不能实现优雅的重载方式,因此为了能够让Touchbase的初始配置包含Couchbase的集群IP,我们需要一个预先启动的脚本来做这件事。在主应用的复制前有权选择是运行onChange
处理器或者是另一个启动脚本,这对Containerbuddy而言是一个非常有用的特性,关于这部分的内容我会在下一篇文章中再次进行讨论。
Nginx虚拟主机的配置有一个upstream
指令,用于为后端的Touchbase应用节点运行一个具备最少连接(least-conns)的负载均衡器。当Touchbase节点上线的时候,它们将通过Consul来进行自身的注册。
正如在我们最初的Containerbuddy实例项目中的那样,Nginx服务的Containerbuddy有一个onChange
事件的处理器,用于调出consul-template
,并基于我们存放在Consul中的模版来写入虚拟机的新的配置文件。然后它会触发nginx -s reload
信号来重新载入Nginx,从而使得Nginx能够以更优雅的方式进行重新载入配置信息。
Couchbase是一个集群NoSQL数据库。我们将会使用的是一个运行在容器中的Couchbase集群的原型,它是由我在Joyent的同事Casey Bisson编写的。它使用了面向Couchbase 4.0的triton-couchbase仓库用于获取新的N1QL特性。
当第一个Couchbase节点启动的时候,我们使用docker exec
来启动集群,然后用Consul来注册第一个节点用于支持服务发现。然后我们将运行合适的REST API调用来创建Couchbase通(buckets),并且为我们的应用进行索引。
此时,我们将通过docker-compose scale
命令来添加新的节点,并且这些节点将会从Consul中挑选一个Couchbase集群IP,之后,我们将会切换为Couchbase的自主集群(self-clustering)。
正如在我们之前的动态DNS项目中的那样,cloudflare容器将包括一个Containerbuddy onChange
事件的处理器,并通过它们的API更新CloudFlare。该处理器是一个用于从已有A记录中查询CloudFlare APIbash脚本,
然后将它们与Consul中已知的IP地址进行比较。如果有变化的部分,我们就首先将新的记录加入进去,然后移除掉任何过期的记录。
你可以通过运行该项目中的start.sh
脚本脚本来运行整个技术栈,该文件位于Github仓库的最外层。你需要一个CloudFlare账户和一个你已经在CloudFlare中委托(delegated)了的DNS的域名,当然你也可以跳过这个步骤,你只需要在脚本中注释掉startCloudFlare
这一行即可。
一旦准备好了,可以遵循如下步骤:
docker
和docker-compose
),以及Joyent CloudAPI CLI tools(包括masrtdc
和json
工具)。此刻你就可以在Triton上运行你的应用了:
./start.sh env
# here you'll be asked to fill in the .env file
./start.sh
或者在你的本地Docker环境中(你可能需要增加内存需求来满足docker-machine虚拟机来运行完整规模的集群):
./start.sh env
./start.sh -f docker-compose-local.yml
.env
文件需要安装如下格式进行创建:
CF_API_KEY=
CF_AUTH_EMAIL=
CF_ROOT_DOMAIN=
SERVICE=nginx
RECORD=
TTL=600
CB_USER=
CB_PASSWORD=
当启动脚本运行后,他会启动Consul的web界面和Couchbase的Web界面。一旦Nginx运行了,它会启动Touchbase站点的登录页。目前为止只有一个Couchbase节点,一个应用服务器,和一个Nginx服务器,你将会看到如下消息:
Touchbase cluster is launched!
Try scaling it up by running: ./start scale
如果你这么做了你将需要运行docker-compose scale
操作来增加2个Couchbase和Touchbase节点和一个Nginx节点。
你可以通过Consul和Couchbase的Web界面来观察新的节点的运行状况。
本文的主要内容是介绍应用在Docker化后所具有的优势。首先,通过这种方式我们能够获取一个更简单、更可重复的部署过程,这使得我们能够进行快速简单的本地测试,并将整个应用栈推送到生产环境中。其次,我们的应用能够实现自动发现和配置,并且使得部署也更加的简单。再其次,我们的应用能够更容易的进行水平扩展,并且各个层次能够进行更好的细粒度的规模控制。最后,我们能够进行全局发现,这要感谢与CloudFlare的集成。
之前我们已经使用了Containerbuddy作为一个最小的shims的例子,它需要能够让任何应用实现容器化。但是目前,我们已经可以看到一个运行在Triton中的能够应用于生产环境中的多层级应用,我们已经可以看到基于容器的服务发现可以是任何特定的调度框架。这使得它能够非常简单的连接到没有被容器化的组件中。
将应用部署到Triton也使得这一切变得更加简单。对于应用容器拥有它们自己的NIC(s)的环境而言,正如Triton那样,
我们可以依赖应用容器来更新发现服务,而无需一个重量级的调度器。这意味着你可以使用诸如Docker Compose这类简单的工具来部署和链接容器,而无需其他附加的软件。使用Triton的容器化的应用架构无需提供虚拟机,Triton负责控制每一个容器,因此你可以很轻松的跟踪你的应用在扩展时的开销。你可以使用Joyent提供的公有云服务中的Triton进行部署,当然也可以是你的自有数据中心进行部署。只需要配置Docker和start.sh
即可。