如何在 docker 容器中使用 python 脚本 运行 创建(docker 化)Elasticsearch 索引?

How do I create a (dockerized) Elasticsearch index using a python script running in a docker container?

我正在尝试使用从脚本调用的 Python 客户端 https://github.com/elastic/elasticsearch-py(也在容器中的 运行)为容器化的 Elasticsearch 数据库建立索引。

通过查看现有的代码片段,docker-compose 似乎是一个可用于我的目的的有用工具。我的目录结构是

docker-compose.yml
indexer/
- Dockerfile
- indexer.py
- requirements.txt
elasticsearch/
- Dockerfile

我的docker-compose.yml阅读

version: '3'

services:
  elasticsearch:
    build: elasticsearch/
    ports: 
      - 9200:9200
    networks:
      - deploy_network
    container_name: elasticsearch

  indexer:
    build: indexer/
    depends_on:
      - elasticsearch
    networks:
      - deploy_network
    container_name: indexer
  
networks:
  deploy_network:
    driver: bridge

indexer.py 阅读

from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
    
es = Elasticsearch(hosts=[{"host":'elasticsearch'}]) # what should I put here?

actions = [
    {
    '_index' : 'test',
    '_type' : 'content',
    '_id' : str(item['id']),
    '_source' : item,
    }
for item in [{'id': 1, 'foo': 'bar'}, {'id': 2, 'foo': 'spam'}]
]
    
# create index
print("Indexing Elasticsearch db... (please hold on)")
bulk(es, actions)
print("...done indexing :-)")

elasticsearch 服务的 Dockerfile 是

FROM docker.elastic.co/elasticsearch/elasticsearch-oss:6.1.3
EXPOSE 9200
EXPOSE 9300

索引器的是

FROM python:3.6-slim
WORKDIR /app
ADD . /app
RUN pip install -r requirements.txt
ENTRYPOINT [ "python" ]
CMD [ "indexer.py" ]

with requirements.txt 只包含 elasticsearch 可以用 pip 下载。

运行 docker-compose run indexerhttps://pastebin.com/6U8maxGX (ConnectionRefusedError: [Errno 111] Connection refused) 处给我错误消息。 据我所知 curl -XGET 'http://localhost:9200/' 或 运行 docker ps -a.

如何修改我的docker-compose.ymlindexer.py来解决问题?

P.S。为了完整起见,可以在此处找到代码的(工作)版本(由以下答案告知):https://github.com/davidefiocco/dockerized-elasticsearch-indexer.

问题是一个同步错误:当 indexer 尝试连接时,elasticsearch 尚未完全启动。您必须添加一些重试逻辑,以确保 elasticsearch 已启动并且 运行ning 在您尝试对其进行 运行 查询之前。在循环中 运行ning es.ping() 之类的东西,直到它成功进行指数退避应该可以解决问题。

更新:Docker HEALTHCHECK 指令可用于实现类似的结果(即确保 elasticsearch 已启动且 运行ning 在尝试 运行 对其进行查询)。

进行更明确的@Mihai_Todor更新,我们可以使用HEALTHCHECK(docker 1.12+),例如使用如下命令:

curl -fsSL "http://$(hostname --ip-address):9200/_cat/health?h=status" | grep -E '^green'

使用HEALTHCHECK回答这个问题:

FROM python:3.6-slim

WORKDIR /app
ADD . /app
RUN pip install -r requirements.txt

HEALTHCHECK CMD curl -fsSL "http://$(hostname --ip-address):9200/_cat/health?h=status" | grep -E '^green'

ENTRYPOINT [ "python" ]
CMD [ "indexer.py" ]

我使用 retry 来确保 Elasticsearch 已准备好接受连接:

from retrying import retry

client = Elasticsearch()


class IndexerService:

    @staticmethod
    @retry(wait_exponential_multiplier=500, wait_exponential_max=100000)
    def init():
        MyDocumentIndex.init()

# Here we will wait until ES is ready, or 100 sec passed.
IndexerService.init()

它会在 500 毫秒、1 秒、2 秒、4 秒后尝试直到 100 秒。

参考:https://github.com/rholder/retrying