在Node.js上使用DNS进行领事服务发现 [英] Consul service discovery with DNS on Nodejs

查看:101
本文介绍了在Node.js上使用DNS进行领事服务发现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL; DR



大家好,
我想通过



这是从领事UI中获得的:



在FE节点上运行领事成员,我得到:

  agent-server 10.0.1.7:8301处于活动状态的服务器1.0.1 2 dc 1< all> 
agent-be-01 10.0.1.5:8301处于活动状态的客户端1.0.1 2 dc1< default>
agent-be-02 10.0.1.6:8301活跃客户端1.0.1 2 dc1< default>
agent-fe 10.0.1.4:8301有效客户端1.0.1 2 dc1< default>

如果我运行 dig @localhost -p 8600 be01.service.consul SRV 在FE节点上,我可以正确得到此结果(领事文档):

  root @ NGINXLB:〜/ node8080 $ dig @localhost -p 8600 be01.service。领事SRV 

; <<>> DiG 9.9.5-3ubuntu0.16-Ubuntu<> @localhost -p 8600 be01.service.consul SRV
; (找到1个服务器)
;;全局选项:+ cmd
;;得到答案:
;; ->> HEADER<--操作码:QUERY,状态:NOERROR,ID:43367
;;标志:qr aa rd;查询:1,答案:2,权限:0,附加:5
;;警告:请求递归,但不可用

;;选择伪指令:
; EDNS:版本:0,标志:; udp:4096
;;问题:
; be01.service.consul。在SRV中

;;解答部分:
be01.service.consul。 0 IN SRV 1 1 8081 agent-be-02.node.dc1.consul。
be01.service.consul。 0 IN SRV 1 1 8080 agent-be-01.node.dc1.consul。

;;其他部分:
agent-be-02.node.dc1.consul。 0 IN A 10.0.1.6
agent-be-02.node.dc1.consul。 0输入TXT consul-network-segment =
agent-be-01.node.dc1.consul。 0 IN A 10.0.1.5
agent-be-01.node.dc1.consul。 0 IN TXT consul-network-segment =

;;查询时间:2毫秒
;;服务器:127.0.0.1#8600(127.0.0.1)
;;何时:星期五十二月01 10:09:00 UTC 2017
;; MSG大小rcvd:246

这是BE服务代码:

  var express = require('express'); 
var bodyParser = require(’body-parser’);
var app = express();
var jsonParser = bodyParser.json()
var urlencodedParser = bodyParser.urlencoded({extended:false})

app.post('/ api / getUserTiles',jsonParser,函数(req,res){
console.log(>'/ api / getUserTiles'的API请求);
if(!req.body){返回res.sendStatus(400)}
else {
var user = req.body.user;
console.log( User: +用户);
res.json({
authorizedTiles :[
{ tileID:个人资料}
,{ tileID:搜索}
,{ tileID:测试}
],
email: max@google.com,
userName: Max,
has_error:false,
error_message:
});
}
});

var服务器= app.listen(8080,function(){
var host = server.address()。address
var port = server.address()。port
console.log(示例应用程序在http://%s:%s上监听,主机,端口)
})

使用带有curl的ip:port从FE调用它可以正常工作:

  root @ NGINXLB:〜/ node8080 $ curl -d = user = Max -X POST http://10.0.1.5:8080/api/getUserTiles 
{ authorizedTiles:[{ tileID: profile},{ tileID: search},{ tileID: test}], email: max@google.com, userName: Max, has_error: false, error_message:}

FE节点上的Web服务(简化)是一种排序

  var axios = require('axios'); 
var dns = require(‘dns’);
var consul = require(’consul’)();

dns.setServers([’127.0.0.1:8600’]);
//console.log(dns.getServers());

dns.resolveSrv( be01.service.consul,function(err,records){
console.log( \nDNS SRV query);
if( err){
console.log(err);
} else {
console.log(records;
}
});

consul.health.service({
service: be01,
dc: dc1,
passing:true
},function(err,result){
console.log( \nConsul.health.service query:);
if(err){console.log(err); throw err ;}
else if(result.length> 0){
for(var i = 0; i console.log(result [i]。 Node.Address +: + result [i] .Service.Port);
}
}
});

axios.post( http://be01.service.consul/api/getUserTiles,{'user':'Max'})
.then(function(response){
if(response.data.has_error){
console.log( \nRESPONSE HAS ERROR!);
} else {
console.log( \nSUCCESS !);
}
})
.catch(function(err){
console.log( \nERROR CAL BE BE SERVICE);
});

运行它,我得到以下结果:

  root @ NGINXLB:〜/ node8080 $节点app.js 

DNS SRV查询
[{名称:'agent-be-01.node .dc1.consul',
端口:8080,
优先级:1,
权重:1},
{名称:'agent-be-02.node.dc1.consul ',
端口:8081,
优先级:1,
权重:1}]

Consul.health.service查询:
10.0.1.5: 8080
10.0.1.6:8081

错误呼叫BE服务
{错误:getaddrinfo ENOTFOUND be01.service.consul be01.service.consul:80
在errnoException (dns.js:50:10)GetAddrInfoReqWrap.onlookup上的
[作为未完成](dns.js:92:26)
代码: ENOTFOUND,
errno: ENOTFOUND
系统调用:'getaddrinfo',
主机名:'be01.service.consul',
主机:'be01.service.consul',
端口:80,
...
...



结论



您可以看到nodejs客户端正在被调用启用be服务,但尝试解析 be01.service.consul失败。此外,它使用的是端口80,而不是Consul DNS接口提供的8080或8081。我缺少什么?

解决方案

问题是axios正在使用 dns.lookup 不使用 dns.setServers 设置的服务器。 dns.lookup dns.resolve 不要使用相同的机制用于解析



在纯节点中,可能的选择是使用<$将域名解析为IP c $ c> dns.resolve * ,然后调用axios或类似拦截器示例(我还没有尝试过)。



可能更好的解决方案是不在节点中执行此操作,而是使用领事代理在本地运行以进行dns解析。


TL;DR

Hi all, I'm trying to call nodejs backend microservices from a nodejs frontend written in Express, through Consul DNS interface but I am having errors.

I am using the nodejs dns api to set the dns for the sole node application in order to make subsequent dns.resolve() calls to the local Consul DNS interface.

Target

I would like to be able to make an http request to my backend service without the need to wire its IPs and ports in my client code. Neither I want to write a custom code to query the Consul HTTP API to get the ip:port couple for my service any time I need to call it.

Problem

Problem is that when I use axios (similar to request) to make an HTTP call to the backend service I always get an error because it cannot resolve the address. It seems Axios is not using the dns I previously setted with:

dns.setServers(['127.0.0.1:8600']);

Update_1

Setting the dns of the virtual machine (/etc/resolv.conf) to localhost e using the -recursor command line option for consul with the default dns everything works! I still would like to understand what I am doing wrong setting the dns only on my nodejs app.

Setup

  • 1 FE node with a nodejs process running a simple webserver with Expressjs. In the app.get('/') route it make a REST POST call to a backend service called be01 through consul and axios (like request).
  • 2 BE node with a nodejs process running a simple webserver with Expressjs exposing REST api.
  • 1 Consul node with Consul running as a server.
  • Every node has it own consul agent running and joined to the cluster.
  • TCP ports are correctly open

This are the servers:

This is from the Consul UI:

Running consul members on the FE node I get:

agent-server  10.0.1.7:8301  alive   server  1.0.1  2         dc1  <all>
agent-be-01   10.0.1.5:8301  alive   client  1.0.1  2         dc1  <default>
agent-be-02   10.0.1.6:8301  alive   client  1.0.1  2         dc1  <default>
agent-fe      10.0.1.4:8301  alive   client  1.0.1  2         dc1  <default>

If I run dig @localhost -p 8600 be01.service.consul SRV on the FE node I correctly get this result (as in the Consul docs):

root@NGINXLB:~/node8080$ dig @localhost -p 8600 be01.service.consul SRV

; <<>> DiG 9.9.5-3ubuntu0.16-Ubuntu <<>> @localhost -p 8600 be01.service.consul SRV
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43367
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 5
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;be01.service.consul.       IN  SRV

;; ANSWER SECTION:
be01.service.consul.    0   IN  SRV 1 1 8081 agent-be-02.node.dc1.consul.
be01.service.consul.    0   IN  SRV 1 1 8080 agent-be-01.node.dc1.consul.

;; ADDITIONAL SECTION:
agent-be-02.node.dc1.consul. 0  IN  A   10.0.1.6
agent-be-02.node.dc1.consul. 0  IN  TXT "consul-network-segment="
agent-be-01.node.dc1.consul. 0  IN  A   10.0.1.5
agent-be-01.node.dc1.consul. 0  IN  TXT "consul-network-segment="

;; Query time: 2 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Fri Dec 01 10:09:00 UTC 2017
;; MSG SIZE  rcvd: 246

This is the BE service code:

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var jsonParser = bodyParser.json()
var urlencodedParser = bodyParser.urlencoded({ extended: false })

app.post('/api/getUserTiles', jsonParser, function (req, res) {
  console.log("> API request for '/api/getUserTiles'");
  if (!req.body) { return res.sendStatus(400) }
  else {
    var user = req.body.user;
    console.log("User: " + user);
    res.json({
      "authorizedTiles": [
        {"tileID": "profile"}
        ,{"tileID": "search"}
        ,{"tileID": "test"}
      ],
      "email": "max@google.com",
      "userName":"Max",
      "has_error": false,
      "error_message": ""
    });
  }
});

var server = app.listen(8080, function () {
  var host = server.address().address
  var port = server.address().port
  console.log("Example app listening at http://%s:%s", host, port)
})

Calling it from the FE using its ip:port with curl works without problems:

root@NGINXLB:~/node8080$ curl -d="user=Max" -X POST http://10.0.1.5:8080/api/getUserTiles
{"authorizedTiles":[{"tileID":"profile"},{"tileID":"search"},{"tileID":"test"}],"email":"max@google.com","userName":"Max","has_error":false,"error_message":""}

The web service on the FE node, simplifying, is sort of this:

var axios = require('axios');
var dns = require('dns');
var consul = require('consul')();

dns.setServers(['127.0.0.1:8600']);
//console.log(dns.getServers());

dns.resolveSrv("be01.service.consul", function(err, records){
        console.log("\nDNS SRV query");
        if(err){
                console.log(err);
        }else{
                console.log(records);
        }
});

consul.health.service({
        "service": "be01",
        "dc": "dc1",
        "passing": true
        }, function(err, result){
                console.log("\nConsul.health.service query:");
                if(err){console.log(err); throw err;}
                else if(result.length > 0){
                        for(var i=0; i<result.length; i++){
                                console.log(result[i].Node.Address + ":" + result[i].Service.Port);
                        }
                }
});

axios.post("http://be01.service.consul/api/getUserTiles", {'user':'Max'})
  .then(function(response){
      if (response.data.has_error) {
       console.log("\nRESPONSE HAS ERROR!");
      }else {
        console.log("\nSUCCESS!");
      }
  })
  .catch(function(err) {
        console.log("\nERROR CALLING THE BE SERVICE");
  });

Running it I get the following result:

root@NGINXLB:~/node8080$ node app.js 

DNS SRV query
[ { name: 'agent-be-01.node.dc1.consul',
    port: 8080,
    priority: 1,
    weight: 1 },
  { name: 'agent-be-02.node.dc1.consul',
    port: 8081,
    priority: 1,
    weight: 1 } ]

Consul.health.service query:
10.0.1.5:8080
10.0.1.6:8081

ERROR CALLING THE BE SERVICE
{ Error: getaddrinfo ENOTFOUND be01.service.consul be01.service.consul:80
    at errnoException (dns.js:50:10)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:92:26)
  code: 'ENOTFOUND',
  errno: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'be01.service.consul',
  host: 'be01.service.consul',
  port: 80,
  ...
  ...

Conclusion

As you can see the nodejs client is calling the be service but it fails trying to resolve 'be01.service.consul'. Moreover it is using the port 80 instead of 8080 or 8081 as provided by the Consul DNS interface. What am I missing?

解决方案

The problem is that axios is using dns.lookup which does not use the servers set by dns.setServers. dns.lookup and dns.resolve do not use the same mechanism for resolving.

In pure node the possible options are to either resolve the domain name to an IP using dns.resolve* before calling axios or something like this interceptor example (I haven't tried it).

Probably better solution is not to do this in node but use the bind option of the consul agent running locally to do the dns resolving.

这篇关于在Node.js上使用DNS进行领事服务发现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆