【问题标题】:Not able to connect to Elasticsearch from docker container (node.js client)无法从 docker 容器(node.js 客户端)连接到 Elasticsearch
【发布时间】:2020-05-26 07:13:20
【问题描述】:

我已经设置了一个 elasticsearch/kibana docker 配置,并且我想使用节点的 @elastic/elasticsearch 客户端从 docker 容器内部连接到 elasticsearch。但是,连接“超时”。

该项目的灵感来自 Patrick Triest:https://blog.patricktriest.com/text-search-docker-elasticsearch/

但是,为了连接kibana,我做了一些修改,使用更新的ES镜像和新的elasticsearch节点客户端。

我正在使用以下 docker-compose 文件:

version: "3"
services:
  api:
    container_name: mp-backend
    build: .
    ports:
      - "3000:3000"
      - "9229:9229"
    environment:
      - NODE_ENV=local
      - ES_HOST=elasticsearch
      - PORT=3000

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.5.1
    container_name: elasticsearch
    environment:
      - node.name=elasticsearch
      - cluster.name=es-docker-cluster
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - "http.cors.allow-origin=*"
      - "http.cors.enabled=true"
      - "http.cors.allow-headers=X-Requested-With,X-Auth-Token,Content-Type,Content-Length,Authorization"
      - "http.cors.allow-credentials=true"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic

  kibana:
    image: docker.elastic.co/kibana/kibana:7.5.1
    ports:
      - "5601:5601"
    links:
      - elasticsearch
    networks:
      - elastic
    depends_on:
      - elasticsearch

volumes:
  data01:
    driver: local

networks:
  elastic:
    driver: bridge

在构建/启动容器时,我能够从 ES 获得响应: curl -XGET "localhost:9200", "you know, for search"... 并且 kibana 正在运行并且能够连接到索引.

我在后端容器 (connection.js) 中有以下文件:

const { Client } = require("@elastic/elasticsearch");

const client = new Client({ node: "http://localhost:9200" });

/*Check the elasticsearch connection */
async function health() {
  let connected = false;
  while (!connected) {
    console.log("Connecting to Elasticsearch");
    try {
      const health = await client.cluster.health({});
      connected = true;
      console.log(health.body);
      return health;
    } catch (err) {
      console.log("ES Connection Failed", err);
    }
  }
}

health();

如果我在容器外运行它,那么我会得到预期的响应:

节点服务器/connection.js

Connecting to Elasticsearch
{
  cluster_name: 'es-docker-cluster',
  status: 'yellow',
  timed_out: false,
  number_of_nodes: 1,
  number_of_data_nodes: 1,
  active_primary_shards: 7,
  active_shards: 7,
  relocating_shards: 0,
  initializing_shards: 0,
  unassigned_shards: 3,
  delayed_unassigned_shards: 0,
  number_of_pending_tasks: 0,
  number_of_in_flight_fetch: 0,
  task_max_waiting_in_queue_millis: 0,
  active_shards_percent_as_number: 70
}

但是,如果我在容器内运行它:

docker exec mp-backend "node" "server/connection.js"

然后我得到以下响应:

Connecting to Elasticsearch
ES Connection Failed ConnectionError: connect ECONNREFUSED 127.0.0.1:9200
    at onResponse (/usr/src/app/node_modules/@elastic/elasticsearch/lib/Transport.js:214:13)
    at ClientRequest.<anonymous> (/usr/src/app/node_modules/@elastic/elasticsearch/lib/Connection.js:98:9)
    at ClientRequest.emit (events.js:223:5)
    at Socket.socketErrorListener (_http_client.js:415:9)
    at Socket.emit (events.js:223:5)
    at emitErrorNT (internal/streams/destroy.js:92:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
    at processTicksAndRejections (internal/process/task_queues.js:81: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
    }
  }
}

所以,我尝试将客户端连接更改为(我在某处读到这可能会有所帮助):

const client = new Client({ node: "http://172.24.0.1:9200" });

然后我只是“卡住”等待响应。 “Connecting to Elasticsearch”只有一个console.log

我正在使用以下版本:

"@elastic/elasticsearch": "7.5.1"

正如您可能看到的,我没有完全了解这里发生的事情......我还尝试添加:

links:
  - elasticsearch
networks:
  - elastic

到 api 服务,没有任何运气。

有谁知道我在这里做错了什么?提前谢谢你:)

编辑:

我使用 *_elastic 在网络上进行了“docker network inspect”。在那里我看到以下内容:

"IPAM": {
    "Driver": "default",
    "Options": null,
    "Config": [
        {
            "Subnet": "172.22.0.0/16",
            "Gateway": "172.22.0.1"
        }
    ]
},

更改客户端以连接到“GateWay”Ip:

const client = new Client({ node: "http://172.22.0.1:9200" });

然后就可以了!我仍然想知道为什么这只是“反复试验”。有什么方法可以在无需检查网络的情况下获得此 IP?

【问题讨论】:

    标签: node.js elasticsearch docker-compose


    【解决方案1】:

    在Docker中,localhost(或者对应的IPv4地址127.0.0.1,或者对应的IPv6地址::1)一般表示“这个容器”;您不能使用该主机名来访问在另一个容器中运行的服务。

    在基于 Compose 的设置中,services: 块的名称(apielasticsearchkibana)可用作主机名。需要注意的是,所有服务都必须在同一个 Docker 内部网络上。 Compose 会为您创建一个并默认将容器附加到它。 (在您的示例中,api 位于 default 网络上,但其他两个容器位于单独的 elastic 网络上。)Docker 文档中的 Networking in Compose 有更多详细信息。

    因此,要使这项工作正常进行,您需要告诉您的客户端代码遵守您设置的指向 Elasticsearch 的环境变量

    const esHost = process.env.ES_HOST || 'localhost';
    const esUrl = 'http://' + esHost + ':9200';
    const client = new Client({ node: esUrl });
    

    在您的docker-compose.yml 文件中删除所有networks: 块以使用提供的default 网络。 (当你在那里时,links: 是不必要的,Compose 为你提供了合理的container_name:api 可以合理地depends_on: [elasticsearch]。)

    由于我们为$ES_HOST 提供了一个后备,如果您在主机开发环境中工作,它将默认使用localhost;在 Docker 之外,它表示“当前主机”,它将到达 Elasticsearch 容器的已发布端口。

    【讨论】:

    • 感谢大卫的解释,效果很好!
    • 我也有同样的问题。我按照上述步骤操作,但我收到“TimeoutError:request timed out”,为什么会这样?
    猜你喜欢
    • 2020-07-03
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 2017-08-21
    • 2016-12-14
    • 2018-10-10
    • 2015-07-09
    • 2019-09-29
    相关资源
    最近更新 更多