无法从Docker容器(node.js客户端)连接到Elasticsearch

时间:2020-02-10 22:25:15

标签: node.js elasticsearch docker-compose

我已经设置了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”,“您知道,用于搜索” ...并且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后端“节点”“ 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({节点:“ http://172.24.0.1:9200”});

然后,我只是“卡住”了,等待响应。 “连接到Elasticsearch”只有一个console.log

我正在使用以下版本:

"@elastic/elasticsearch": "7.5.1"

您可能会看到,我对这里发生的事情不完全了解...我也尝试添加:

links:
  - elasticsearch
networks:
  - elastic

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

有人知道我在做什么错吗?预先谢谢你:)

编辑:

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

"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?

1 个答案:

答案 0 :(得分:1)

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

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

因此,要执行此操作,您需要告诉您的客户端代码以兑现您所设置的指向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容器的已发布端口。