Обнаружение службы Consul с DNS на Nodejs

TL;DR

Привет всем, я пытаюсь вызвать микросервисы backend nodejs из интерфейса nodejs, написанного на Express, через Consul интерфейс DNS, но у меня возникают ошибки.

Я использую nodejs dns api, чтобы установить DNS для приложения с единственным узлом, чтобы последующие вызовы dns.resolve () к локальному интерфейсу Consul DNS.

Цель

Я хотел бы иметь возможность отправлять HTTP-запросы к моей серверной службе без необходимости связывать ее IP-адреса и порты в моем клиентском коде. Я также не хочу писать собственный код для запроса HTTP API Consul для получения пары ip: port для моей службы в любое время, когда мне нужно ее вызвать.

Проблема

Проблема в том, что когда я использую axios (аналогично request), чтобы выполнить HTTP-вызов серверной службы, я всегда получаю сообщение об ошибке, потому что она не может разрешить адрес. Кажется, Axios не использует DNS, которые я ранее установил:

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

Обновление_1

Установка dns виртуальной машины (/etc/resolv.conf) на localhost e с использованием параметра командной строки -recursor для consul с dns по умолчанию, все работает! Я все еще хотел бы понять, что я делаю неправильно, устанавливая DNS только в моем приложении nodejs.

Настраивать

  • 1 узел FE с процессом nodejs, на котором запущен простой веб-сервер с Expressjs. В маршруте app.get ('/') он выполняет вызов REST POST для серверной службы, называемой be01, через consul и axios (например, request).
  • 2 BE с процессом nodejs, на котором запущен простой веб-сервер с Expressjs, предоставляющий REST api.
  • 1 узел Consul с Consul, работающим в качестве сервера.
  • На каждом узле работает собственный агент консула, подключенный к кластеру.
  • TCP-порты открыты правильно

Это серверы:  введите описание изображения здесь

Это из пользовательского интерфейса Consul:  введите описание изображения здесь

Работая с членами консула на узле FE, я получаю:

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>

Если я запускаю dig @localhost -p 8600 be01.service.consul SRV на узле FE, я правильно получаю этот результат (как в документации Consul):

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

Это сервисный код 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, 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": "[email protected]",
      "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)
})

Вызов его из FE по его ip: port с помощью curl работает без проблем:

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":"[email protected]","userName":"Max","has_error":false,"error_message":""}

Веб-сервис на узле FE, упрощая, выглядит примерно так:

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");
  });

Запустив его, я получаю следующий результат:

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,
  ...
  ...

Заключение

Как видите, клиент nodejs вызывает службу be, но не пытается разрешить be01.service.consul. Более того, он использует порт 80 вместо 8080 или 8081, как это предусмотрено интерфейсом Consul DNS. Что мне не хватает?


person Roberto    schedule 01.12.2017    source источник


Ответы (1)


Проблема в том, что axios использует dns.lookup, который не использует серверы, установленные dns.setServers. dns.lookup и dns.resolve не используют один и тот же механизм для разрешение.

В чистом узле возможны варианты: либо преобразовать доменное имя в IP-адрес с использованием dns.resolve* перед вызовом axios, либо что-то вроде этого пример перехватчика (не пробовал).

Вероятно, лучшим решением будет не делать этого в узле, а использовать опцию привязки consul agent выполняется локально для разрешения DNS.

person typingduck    schedule 14.12.2017