“ConnectionError: connect ECONNREFUSED”,无法使用 Docker Compose 连接 Node.js 应用程序和 Elasticsearch 数据库

Posted

技术标签:

【中文标题】“ConnectionError: connect ECONNREFUSED”,无法使用 Docker Compose 连接 Node.js 应用程序和 Elasticsearch 数据库【英文标题】:"ConnectionError: connect ECONNREFUSED", cannot connect Node.js app and Elasticsearch database with Docker Compose 【发布时间】:2020-02-28 07:40:04 【问题描述】:

我正在尝试让我的 Node.js 应用程序在 Docker 中的同一个桥接网络上运行时与我的 Elasticsearch 数据库通信。我使用 docker-compose.yml 文件进行配置。这是我得到的相关位和错误消息。

docker-compose.yml

version: '3'

services:
  express-app:
    build: /path/to/app
    container_name: my_app
    depends_on:
      - 'elasticsearch'
    environment:
     - NODE_ENV=local
     - ES_HOST=elasticsearch
     - PORT=3000
    ports:
      - 3000:3000
    networks:
      - backend

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.6.0
    container_name: es-master
    environment:
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - esdata:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
      - 9300:9300
    networks:
      - backend

volumes:
  esdata:
    driver: local

networks:
  backend:

我希望这两个服务(express-appelasticsearch 都可以在创建的 Docker 桥接网络上被发现,“my_app_backend”,以及它们的服务名称。官方Docker documentation 声明“服务可在hostname”。我的意图是通过地址“http://elasticsearch:9200”到达服务elasticsearch。

Node.js 应用内的数据库连接定义 (server/db/index.js)

const  Client  = require('@elastic/elasticsearch');
const hostname = process.env.ES_HOST || 'localhost';
const client = new Client(
  node: `http://$hostname:9200`,
  log: 'error'
);

async function checkConnection () 
  let isConnected = false;
  console.log('Connecting to host', hostname);
  try 
    const health = await client.cluster.health();
    console.log(health);
    isConnected = true;
   catch (err) 
    console.log('process.env.ES_HOST', process.env.ES_HOST);
    console.log('Connection Failed\n', err);
  


checkConnection();

module.exports.client = client;

下面的消息显示了 Node.js 应用程序尝试通过 process.env.ES_HOST 变量“elasticsearch”(在 docker-compose.yml 文件中定义)并在容器运行时执行的结果。错误消息显示了我放置的几个控制台日志,以检查变量的值是否正确。

ECONNREFUSED 之后显示的 IP 地址是 Docker 引擎替换“elasticsearch”的内容。当我运行 docker network inspect my_app_backend 输出容器的网络地址时,也可以找到这一点。

... (redacted)
"MacAddress": "02:42:ac:14:00:03",
                "IPv4Address": "172.20.0.3/16",
                "IPv6Address": ""

错误信息

> NODE_ENV=production node ./server/index.js

Connecting to host elasticsearch
Server listening on port 3000!
process.env.ES_HOST elasticsearch
Connection Failed
 ConnectionError: connect ECONNREFUSED 172.20.0.3:9200
    at onResponse (/src/app/node_modules/@elastic/elasticsearch/lib/Transport.js:214:13)
    at ClientRequest.<anonymous> (/src/app/node_modules/@elastic/elasticsearch/lib/Connection.js:98:9)
    at ClientRequest.emit (events.js:311:20)
    at Socket.socketErrorListener (_http_client.js:426:9)
    at Socket.emit (events.js:311:20)
    at emitErrorNT (internal/streams/destroy.js:92:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
    at processTicksAndRejections (internal/process/task_queues.js:84:21) 
  name: 'ConnectionError',
  meta: 
    body: null,
    statusCode: null,
    headers: null,
    warnings: null,
    meta: 
      context: null,
      request: [Object],
      name: 'elasticsearch-js',
      connection: [Object],
      attempts: 3,
      aborted: false
    
  

另外,我想指出应用程序在启动时无法连接,但是当我通过docker exec -it express-app sh 进入应用程序容器并编辑数据库连接代码并硬编码数据库的 IP 地址 (172.20.0.3) 时,然后重新启动node app,app连接数据库成功。

在尝试通过 docker-compose 实现完全自动化时,我做错了什么?这是 Elasticsearch 的一个怪癖还是我遗漏了一些非常明显的东西?提前感谢您的帮助!

【问题讨论】:

如果你只是重新启动 Node 应用程序而不做任何更改,它可以工作吗?这种设置中的一个常见问题是应用程序在数据库准备好接收连接之前启动;这与收到“连接被拒绝”错误一致(连接的名称解析部分正在工作,elasticsearch 主机名对 Docker 有意义)。 【参考方案1】:

在 express_app 中使用 container_name : es-master 而不是 elasticsearch 作为 ES_HOST 环境变量

ES_HOST : es-master

【讨论】:

【参考方案2】:

我认为你应该链接 elasticsearch 容器

version: '3'

services:
  express-app:
    build: /path/to/app
    container_name: my_app
    restart: always
    depends_on:
      - 'elasticsearch'
    environment:
     - NODE_ENV=local
     - ES_HOST=elasticsearch
     - PORT=3000
    ports:
      - 3000:3000
    networks:
      - backend
    links: 
        - elasticsearch

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.6.0
    container_name: es-master
    environment:
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - esdata:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
      - 9300:9300
    networks:
      - backend

volumes:
  esdata:
    driver: local

networks:
  backend:

【讨论】:

这完全没有区别,在现代 Docker 中也不需要。

以上是关于“ConnectionError: connect ECONNREFUSED”,无法使用 Docker Compose 连接 Node.js 应用程序和 Elasticsearch 数据库的主要内容,如果未能解决你的问题,请参考以下文章