Docker镜像部署单节点Elasticsearch后curl连接被拒问题求助
Docker构建镜像时Elasticsearch启动后无法访问的问题解决
问题描述
尝试构建包含本地单节点Elasticsearch实例的Docker镜像,计划容器启动后完成:
- 启动Elasticsearch实例
- 通过Python脚本创建索引并加载文档
- 通过Flask服务提供索引查询能力
但构建镜像时执行elasticsearch-8.6.0/bin/elasticsearch -d后,执行curl localhost:9200返回000连接被拒;注释掉启动ES的命令构建镜像后,手动进入容器执行相同启动命令,curl可正常返回200。
现有Dockerfile
FROM ubuntu:latest SHELL ["/bin/bash", "-c"] RUN apt-get -y update && apt-get install -y --no-install-recommends \ sudo \ wget \ gnupg \ curl \ unzip \ tar \ ca-certificates \ lsb-release \ python3-pip \ python3-setuptools \ nginx \ && rm -rf /var/lib/apt/lists/* #setup elasticsearch RUN wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.6.0-linux-aarch64.tar.gz RUN tar -xzvf elasticsearch-8.6.0-linux-aarch64.tar.gz ##create a new user and give es permissions to it to start a node RUN useradd es_user RUN chown es_user:es_user -R elasticsearch-8.6.0 USER es_user RUN echo "discovery.type: single-node" >> elasticsearch-8.6.0/config/elasticsearch.yml RUN echo "xpack.security.enabled: false" >> elasticsearch-8.6.0/config/elasticsearch.yml #RUN echo "network.host: 0.0.0.0" >> elasticsearch-8.6.0/config/elasticsearch.yml #RUN echo "http.port: 9200" >> elasticsearch-8.6.0/config/elasticsearch.yml #RUN echo "http.host: 0.0.0.0" >> elasticsearch-8.6.0/config/elasticsearch.yml RUN elasticsearch-8.6.0/bin/elasticsearch -d RUN sleep 30 RUN echo $(curl -s -w '%{http_code}' localhost:9200)
构建日志curl输出
#18 [15/15] RUN echo $(curl -s -w '%{http_code}' localhost:9200) #18 sha256:94cb4cd9486b0bf9a80c77c7648ba19ab373c3f8ec8e1131b3d68a0a55e0b268 #18 0.182 000 #18 DONE 0.2s
手动进入容器测试结果
{ "name" : "5bced6805917", "cluster_name" : "elasticsearch", "cluster_uuid" : "IAcnbmcfTmC84MjI3Y-jiA", "version" : { "number" : "8.6.0", "build_flavor" : "default", "build_type" : "tar", "build_hash" : "f67ef2df40237445caa70e2fef79471cc608d70d", "build_date" : "2023-01-04T09:35:21.782467981Z", "build_snapshot" : false, "lucene_version" : "9.4.2", "minimum_wire_compatibility_version" : "7.17.0", "minimum_index_compatibility_version" : "7.0.0" }, "tagline" : "You Know, for Search" } 200
问题原因
Docker的RUN指令是在独立的临时容器层中执行的,每个RUN步骤结束后,该层的所有进程都会被终止,不会保留到后续的RUN步骤中。因此,在RUN elasticsearch-8.6.0/bin/elasticsearch -d启动的ES进程,会在该步骤执行完成后被销毁,下一个RUN步骤的环境中没有运行的ES实例,自然无法通过curl访问。
而手动进入容器时,所有操作都在同一个容器进程环境中,ES启动后会持续运行,因此curl可以正常访问。
解决方案
将服务启动逻辑从构建阶段(RUN)转移到容器启动阶段,使用ENTRYPOINT或CMD执行启动脚本,步骤如下:
1. 创建启动脚本start.sh
#!/bin/bash # 启动Elasticsearch后台运行 elasticsearch-8.6.0/bin/elasticsearch -d # 等待Elasticsearch完全启动(替代固定sleep,更可靠) until curl -s localhost:9200 > /dev/null; do echo "等待Elasticsearch启动..." sleep 5 done # 执行Python脚本创建索引并加载文档(替换为你的脚本路径) python3 /app/create_index.py # 启动Flask服务(确保Flask监听0.0.0.0,允许外部访问) flask run --host=0.0.0.0 --port=5000
2. 修改Dockerfile
FROM ubuntu:latest SHELL ["/bin/bash", "-c"] RUN apt-get -y update && apt-get install -y --no-install-recommends \ wget \ curl \ tar \ ca-certificates \ python3-pip \ python3-setuptools \ && rm -rf /var/lib/apt/lists/* # 安装Elasticsearch RUN wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.6.0-linux-aarch64.tar.gz RUN tar -xzvf elasticsearch-8.6.0-linux-aarch64.tar.gz && rm elasticsearch-8.6.0-linux-aarch64.tar.gz # 创建ES用户并配置权限 RUN useradd es_user RUN chown es_user:es_user -R elasticsearch-8.6.0 # 配置Elasticsearch USER es_user RUN echo "discovery.type: single-node" >> elasticsearch-8.6.0/config/elasticsearch.yml RUN echo "xpack.security.enabled: false" >> elasticsearch-8.6.0/config/elasticsearch.yml RUN echo "network.host: 0.0.0.0" >> elasticsearch-8.6.0/config/elasticsearch.yml # 允许容器外部访问 # 复制启动脚本和Python代码(假设你的脚本在当前目录的app文件夹下) USER root COPY start.sh /start.sh COPY app /app RUN chmod +x /start.sh && chown es_user:es_user -R /app USER es_user # 容器启动时执行脚本 CMD ["/bin/bash", "/start.sh"]
关键修改点
- 移除构建阶段启动ES和curl的
RUN指令,只保留环境准备和配置步骤 - 添加启动脚本,将ES启动、Python脚本执行、Flask启动逻辑放到容器启动时执行
- 启用
network.host: 0.0.0.0,确保容器外部可以访问ES(如果不需要可注释) - 使用
until循环替代固定sleep,等待ES完全启动后再执行后续操作,避免因启动慢导致的失败
内容的提问来源于stack exchange,提问作者armen
相关产品推荐
相关产品推荐

