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. Что мне не хватает?