Докер создает сеть с ошибкой axios (узел) ENOTFOUND - PullRequest
0 голосов
/ 10 мая 2018

У меня есть стек для создания докеров с несколькими контейнерами. Эти два вопроса представляют собой расширенный контейнер python:3-onbuild (см. Базовое изображение здесь ) с запущенным веб-сервером falcon и базовый контейнер node:8.11-alpine, который пытается отправлять запросы на веб-сервер python. Это упрощенная версия моего составного файла:

version: '3.6'

services:
  app: # python:3-onbuild
    ports:
      - 5000
    build:
      context: ../../
      dockerfile: infra/docker/app.Dockerfile

  lambda: # node:8.11-alpine
    ports:
      - 10000
    build:
      context: ../../
      dockerfile: infra/docker/lambda.Dockerfile
    depends_on:
      - app

Я знаю, что сеть работает, потому что если я ssh в лямбда-контейнер

docker exec -it default_lambda_1 /bin/ash

и запустите ping app Я получу ответ.

$ ping app
PING app (172.18.0.4): 56 data bytes
64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.184 ms
64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.141 ms

Я могу даже бежать ping app:5000

ping app:5000
PING app:5000 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.105 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.176 ms

Я даже создал конечную точку /status на своем API, чтобы попытаться решить эту проблему. Он запрашивает имена всех таблиц в базе данных, поэтому он должен потерпеть неудачу, если база данных не готова. Но, если я запускаю curl http://app:5000/status, я получаю ответ со всеми именами таблиц, никаких проблем вообще.

Проблема возникает только тогда, когда процесс моего узла пытается сделать пост-запрос (используя axios)

this.endpointUrl = 'http://app:5000';
const options: AxiosRequestConfig = {
    method: 'POST',
    url: `${this.endpointUrl}/session/get`,
    data: {
        'client': 'alexa'
    },
    responseType: 'json'
};

axios(options)
    .then((response: AxiosResponse<any>) => {
        console.log(`[SessionService][getSession]: "/session/get" responseData = ${JSON.stringify(response.data)}`);
    })
    .catch(err => {
        console.error(`[SessionService][getSession]: error = ${err}`);
    });

Я получаю следующую ошибку:

console.error src/index.ts:111
  VirtualConsole.on.e at project/node_modules/jsdom/lib/jsdom/virtual-console.js:29:45
   Error: Error: getaddrinfo ENOTFOUND app app:5000
        at Object.dispatchError (/project/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
        at Request.client.on.err (/project/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
        at emitOne (events.js:121:20)
        at Request.emit (events.js:211:7)
        at Request.onRequestError (/project/node_modules/request/request.js:878:8)
        at emitOne (events.js:116:13)
        at ClientRequest.emit (events.js:211:7)
        at Socket.socketErrorListener (_http_client.js:387:9)
        at emitOne (events.js:116:13)
        at Socket.emit (events.js:211:7) undefined

  console.error src/index.ts:111
    axios_1.default.then.catch.err at services/Service.ts:94:25
     [SessionService][getSession]: error = Error: Network Error

Я узнал больше об этом ENOTFOUND сообщении об ошибке здесь

getaddrinfo по определению является проблемой DNS

Итак, я изучил использование узла dns packge для поиска app

> dns.lookup('app', console.log)
GetAddrInfoReqWrap {
  callback: [Function: bound consoleCall],
  family: 0,
  hostname: 'app',
  oncomplete: [Function: onlookup],
  domain:
   Domain {
     domain: null,
     _events: { error: [Function: debugDomainError] },
     _eventsCount: 1,
     _maxListeners: undefined,
     members: [] } }
> null '172.18.0.3' 4
> dns.lookup('app:5000', console.log)
GetAddrInfoReqWrap {
  callback: [Function: bound consoleCall],
  family: 0,
  hostname: 'app:5000',
  oncomplete: [Function: onlookup],
  domain:
   Domain {
     domain: null,
     _events: { error: [Function: debugDomainError] },
     _eventsCount: 1,
     _maxListeners: undefined,
     members: [] } }
> { Error: getaddrinfo ENOTFOUND app:5000
    at errnoException (dns.js:50:10)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:92:26)
  code: 'ENOTFOUND',
  errno: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'app:5000' }

Похоже, он может найти app, но не app:5000? Weird. С тех пор как я это выяснил, я попытался изменить порт веб-сервера python на 80, чтобы я мог сделать запросы axios равными ol 10 *, но это привело к той же самой ошибке ENOTFOUND.

Я не могу найти много информации о том, как это исправить. Одна идея от здесь

проблема в том, что http.request использует dns.lookup вместо dns.resolve

Ответ предлагает использовать оверлейную сеть. Я не очень понимаю, что это такое, но если это потребуется, я сделаю это. Но мне интересно, есть ли более простое решение сейчас, когда я использую compose yml версии 3.6. В любом случае, dns.resolve дает мне вывод, аналогичный dns.lookup

> dns.resolve('app', console.log)
QueryReqWrap {
  bindingName: 'queryA',
  callback: [Function: bound consoleCall],
  hostname: 'app',
  oncomplete: [Function: onresolve],
  ttl: false,
  domain:
   Domain {
     domain: null,
     _events: { error: [Function: debugDomainError] },
     _eventsCount: 1,
     _maxListeners: undefined,
     members: [] },
  channel: ChannelWrap {} }
> null [ '172.18.0.3' ]
> dns.resolve('app:5000', console.log)
QueryReqWrap {
  bindingName: 'queryA',
  callback: [Function: bound consoleCall],
  hostname: 'app:5000',
  oncomplete: [Function: onresolve],
  ttl: false,
  domain:
   Domain {
     domain: null,
     _events: { error: [Function: debugDomainError] },
     _eventsCount: 1,
     _maxListeners: undefined,
     members: [] },
  channel: ChannelWrap {} }
> { Error: queryA ENOTFOUND app:5000
    at errnoException (dns.js:50:10)
    at QueryReqWrap.onresolve [as oncomplete] (dns.js:238:19)
  code: 'ENOTFOUND',
  errno: 'ENOTFOUND',
  syscall: 'queryA',
  hostname: 'app:5000' }

РЕДАКТИРОВАТЬ: Кстати, я могу сделать те же POST-запросы из лямбда-контейнера через https во внешний мир (рабочий сервер работает с тем же кодом, что и служба приложения)

EDIT: если я удаляю http:// из endpointUrl, как предложено здесь , я получаю Error: Invalid protocol: app

РЕДАКТИРОВАТЬ: я думал, что это может быть связано с этой проблемой с базовым образом узла-альпийского, но изменение на node:8.11 или node:carbon привело к той же проблеме DNS ENOTFOUND

РЕДАКТИРОВАТЬ: Я уверен, что это не проблема синхронизации, потому что я жду, чтобы запустить мои тесты в течение 100 секунд, делая тестовый запрос каждые 10 секунд. Если я пропущу шаг теста и позволю контейнеру вращаться как обычно, я смогу свернуться app из контейнера lambda задолго до 100-секундной отметки ...

1 Ответ

0 голосов
/ 11 мая 2018

Проблема закончилась с моим бегуном, шутка.

Средой по умолчанию в Jest является среда, подобная браузеру, через jsdom. Если вы создаете службу узла, вы можете использовать опцию узла для использования среды, подобной узлу.

Чтобы это исправить, мне нужно было добавить это в мой файл jest.config.js:

{
  // ...
  testEnvironment: 'node'
  // ...
}

Источник: https://github.com/axios/axios/issues/1418

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...