Node.js自动导航模式在docker的应用

RonnieHack 8年前
   <p>自动导航模式使得当程序被部署的时候自能够自动根据配置构建应用程序变得非常简单(容易在开发和测试的时候获得一个拷贝),当应用程序更新或者由于故障需要扩展或者缩减的时候。接下来我们将通过两个Node.js模块如何使用自动导航模式更容易地构建app。</p>    <p>这两个模块分别是 <a href="/misc/goto?guid=4959715490599912718" rel="nofollow,noindex">consulite</a> 和 <a href="/misc/goto?guid=4959715490691021715" rel="nofollow,noindex">piloted</a> ,使用 npm 安装和如何为自动导航模式程序提供常用功能,其中包含使用Consul进行交互以及因为拓扑结构变更而重新加载配置文件的内容。这些虽然不是自动导航模式所必需,但是提供了更加便捷的方式。</p>    <p>让我们看看这两个模块是如何工作的。</p>    <h2><strong>为Node.js提供容器导航</strong></h2>    <p>在我们演示这些模块如何使用之前,让我们先快速浏览下 <a href="/misc/goto?guid=4959715490777458815" rel="nofollow,noindex">容器导航</a> 是如何与在Docker容器中运行的Node.js应用程序进行整合的。下面的图片说明了通常情况下一个应用程序的生命周期在 <a href="/misc/goto?guid=4959715490777458815" rel="nofollow,noindex">容器导航</a> 中配置的要点。</p>    <p><img src="https://simg.open-open.com/show/c728310d9b72fa0308fb5db26fd1a5f0.png"></p>    <p>如图所示,容器导航配置通常会发送一个 SIGHUP 信号给Node.js应用程序。一旦发送完毕,不论这个应用程序是否依赖后台的变更。当 <a href="/misc/goto?guid=4959715490777458815" rel="nofollow,noindex">容器导航</a> 通知这些后台依赖变更的时候,他不会发送应用程序的后台主机名以及端口信息。这个任务留着给应用开发人员决定如何去实现它。下图演示一个类似 <a href="/misc/goto?guid=4958967317511997269" rel="nofollow,noindex">Consul</a> 的典型数据流,从应用程序到 <a href="/misc/goto?guid=4959715490777458815" rel="nofollow,noindex">容器导航</a> 再到服务注册的过程。</p>    <p><img src="https://simg.open-open.com/show/800af31537770656e7692501edc0404c.png"></p>    <p>上面的模块是设计被用来解决上图所示的经常遇到的问题 ,比如处理后台地址由于 onChange 事件而需要重新加载的情况。当后台服务变更的时候 onChange 事件触发。这有可能是因为某个后台服务突然不健康或者新的后台地址通过Consul注册而造成的。无论是哪种方式,容器导航都会执行已经配置好的命令通知Node.js应用。</p>    <p>保存一份应用依赖的健康的后台地址清单对[自动导航模式]( <a href="/misc/goto?guid=4959715490922915098" rel="nofollow,noindex">https://www.joyent.com/blog/category:Autopilot</a> Pattern)而言影响重大。其中一个原因是最初的设计就是为了能够提前了解应用的健康情况,为了确保请求不会被发送到那些不健康的后台服务。这也意味着负载均衡器对部署一个应用及后台服务而言不再那么重要了。</p>    <h2><strong>Consulite</strong></h2>    <p>另一个对于 <a href="/misc/goto?guid=4959715490777458815" rel="nofollow,noindex">容器导航</a> 目标而言,[自动导航模式]( <a href="/misc/goto?guid=4959715490922915098" rel="nofollow,noindex">https://www.joyent.com/blog/category:Autopilot</a> Pattern)显著的收益是我们不需要注册你的应用到服务发现上了。服务导航为你管理这些常用任务,当出现中断或者任何应用依赖的服务发生变更的时候它会第一时间通知应用这一消息。</p>    <p>你无需再为服务注册和从注册订阅的消息担心,你需要知道的只是如何与注册者通信并定位应用依赖的主机及端口信息。 <a href="/misc/goto?guid=4959715490599912718" rel="nofollow,noindex">Consulite</a> 有助于使得获取这些应用依赖的服务信息变得便捷。正如Consul的名字一样,它实现了如何与 <a href="/misc/goto?guid=4959715490599912718" rel="nofollow,noindex">consulite</a> 进行通讯的注册实现。</p>    <h3><strong>实现注册路由</strong></h3>    <p>让我们通过一个实例来演示consulite是如何使得这一切变得便捷和有意义的。这个例子源自 <a href="/misc/goto?guid=4959715491048452308" rel="nofollow,noindex">Autopilot workshop</a> ,一个标准的 <a href="/misc/goto?guid=4959715491129911080" rel="nofollow,noindex">销售者</a> 服务。</p>    <pre>  <code class="language-javascript">const Consulite = require('consulite');    const Wreck = require('wreck');        Consulite.getService('customers', (err, host) => {    if (err) {    return console.error(err);    }        Wreck.get(`http://${host.address}:${host.port}/data`, (err, res, customers) => {    // Handle error or respond with relevant customer data    });    });  </code></pre>    <p>在上面的例子中,没有任何消费者服务被缓存,那么Consul将使得一个请求获取到所有健康的服务地址列表。通常情况,会为一个特定服务提供多功能后台地址列表。为了建立这个服务, <a href="/misc/goto?guid=4959715490599912718" rel="nofollow,noindex">consulite</a> 将会循环遍历这个地址列表。循环的逻辑从当前地址列表的第一个还没有被使用的地址直到最后一个地址完全被使用。这些在一个模块中实现功能的结果有助于减少使用Consul保持与这个地址列表通讯的资源消耗。</p>    <h3><strong>管理注册变更</strong></h3>    <p><a href="/misc/goto?guid=4959715490599912718" rel="nofollow,noindex">Consulite</a> 使得保持与缓存后的健康服务列表通讯变得异常容易,当服务器更新的时候也同时更新了这个服务列表。之前的例子中,已经演示了容器导航是如何当一个后台服务变更的时候通过向配置好的Node.js应用发送一个 SIGHUP 信号通知。下面的实例演示了在 <a href="/misc/goto?guid=4959715490777458815" rel="nofollow,noindex">容器导航</a> 中如何使用 <a href="/misc/goto?guid=4959715490599912718" rel="nofollow,noindex">consulite</a> 管理可配置的 onChange 行为来统一管理这些信号,目的是刷新这些本地服务缓存。</p>    <pre>  <code class="language-javascript">process.on('SIGHUP', () => {    Consulite.refreshService('customers', (err) => {    if (err) {      console.error(err);    }    });    });  </code></pre>    <p>就算是一个应用开发人员都可以通过 <a href="/misc/goto?guid=4959715490599912718" rel="nofollow,noindex">consulite</a> 很容器的调试 <a href="/misc/goto?guid=4959715490777458815" rel="nofollow,noindex">容器导航</a> ,他们的职责仅仅只需计算一直保持通信的初始化服务列表来管理进程事件而以。为了解决这个问题我们创建了 <a href="/misc/goto?guid=4959715490691021715" rel="nofollow,noindex">piloted</a> 项目.</p>    <p><a href="/misc/goto?guid=4959715490691021715" rel="nofollow,noindex">Piloted</a> 项目</p>    <p>为了代替应用程序开发人员去实现管理 SIGNUP 事件以及初始化服务地址列表加载,我们决定用 <a href="/misc/goto?guid=4959715490691021715" rel="nofollow,noindex">piloted</a> 模块来处理这些工作。所有应用依赖的后台和服务们都已经配置在了 containerpilot.json 的配置文件中。因此应用开发人员可以通过 <a href="/misc/goto?guid=4959715490691021715" rel="nofollow,noindex">piloted</a> 来替换这些配置信息,且它会自动加载,并为应用保存一份健康的后台地址信息列表。下面的例子演示了如何发送已经 <a href="/misc/goto?guid=4959715490691021715" rel="nofollow,noindex">piloted</a> 的配置文件信息并取回 customers 服务的后台服务地址列表。</p>    <h3><strong>Usage</strong></h3>    <pre>  <code class="language-javascript">const Piloted = require('piloted');    const Wreck = require('wreck');    const ContainerPilot = require('/etc/containerpilot.json');        Piloted.config(ContainerPilot, () => {    const host = Piloted('customers');        Wreck.get(`http://${host.address}:${host.port}/data`, (err, res, customers) => {    // Handle error or respond with relevant customer data    });    });  </code></pre>    <p>上面的例子中 <a href="/misc/goto?guid=4959715490777458815" rel="nofollow,noindex">容器导航</a> 的配置文件被加载到 <a href="/misc/goto?guid=4959715490691021715" rel="nofollow,noindex">piloted</a> 中.在这之后, <a href="/misc/goto?guid=4959715490691021715" rel="nofollow,noindex">piloted</a> 将会维护一份本地的应用依赖健康服务器列表。在这个事件中,一旦这些服务中有变更发生, <a href="/misc/goto?guid=4959715490691021715" rel="nofollow,noindex">piloted</a> 将会通过Consul更新这个列表信息到最新版本。</p>    <p> </p>    <p>来自:http://dockone.io/article/1694</p>    <p> </p>