node.js - docker 与 axios (node) 组成网络错误 ENOTFOUND

标签 node.js docker docker-compose axios

我有一个包含一些容器的 docker compose 堆栈。有问题的两个容器是一个扩展的 python:3-onbuild 容器(参见基础镜像 here ),其中运行着 falcon Web 服务器,还有一个基本的 Node:8.11-alpine 容器,它试图向 python Web 服务器发出 post 请求。这是我的撰写文件的简化版本:

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 进入 lambda 容器

docker exec -it default_lambda_1 /bin/ash

并运行ping应用程序我得到了响应。

$ 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

我什至在我的 api 上创建了一个 /status 端点来尝试解决此问题。它查询数据库中所有表的名称,因此如果数据库未准备好,它应该失败。但是,如果我运行curl http://app:5000/status,我会收到包含所有表名称的响应,完全没有问题。

只有当我的 Node 进程尝试发出 post 请求(使用 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

我从 here 了解了有关此 ENOTFOUND 错误消息的更多信息

getaddrinfo is by definition a DNS issue

然后,我考虑使用 Node dns包来查找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?诡异的。发现这一点后,我尝试将 python Web 服务器端口更改为 80,以便我可以向普通的 http://app 发出 axios 请求,但这导致了相同的 ENOTFOUND 错误。

我找不到太多有关如何解决此问题的信息。一个想法来自here

the problem is that http.request uses dns.lookup instead of 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' }

编辑:顺便说一句,我可以通过 https 从 lambda 容器向外界发出相同的 POST 请求(与应用程序服务运行相同代码的生产服务器)

编辑:如果我按照建议从端点Url中删除http:// here ,我收到错误:协议(protocol)无效:应用程序

编辑:我认为这可能与this issue有关使用 node-alpine 基础镜像,但更改为 node:8.11node:carbon 导致相同的 DNS 问题 ENOTFOUND

编辑:我确定这不是计时问题,因为我正在等待运行测试 100 秒,每 10 秒发出一次测试请求。如果我跳过测试步骤并让容器像平常一样旋转,我就可以在 100 秒标记之前从 lambda 容器内部 curl app...

最佳答案

问题最终出在我的测试运行程序上,开玩笑。

The default environment in Jest is a browser-like environment through jsdom. If you are building a node service, you can use the node option to use a node-like environment instead.

要解决此问题,我必须将其添加到我的 jest.config.js 文件中:

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

来源:https://github.com/axios/axios/issues/1418

关于node.js - docker 与 axios (node) 组成网络错误 ENOTFOUND,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50263684/

相关文章:

node.js - 我怎样才能建立一个可以从其他文件访问的全局 mongodb 连接

ubuntu - 尝试连接到 Docker 守护程序套接字时权限被拒绝

linux - 安排每日 Docker 容器重启/重置

docker - 将参数传递给 docker compose

javascript - MongoDB 对象未从数据库中删除

javascript - Socket.IO 无法通过 https 连接

docker - 在确定分区位置之前 60000 毫秒的 Kafka 客户端超时已过期

javascript - Gulp 构建任务在 docker 内失败

node.js - 为什么node.js找不到avconv?

mongodb - docker-compose在mongodb中创建用户