FastAPI+Docker Compose集成OpenSearch时出现连接拒绝错误怎么办?
问题
我正在开发一个使用Docker Compose集成OpenSearch的FastAPI项目,尝试连接OpenSearch服务时持续遇到ConnectionRefusedError。以下是我的配置:
docker-compose.yml
services: app: container_name: app-search build: . command: "uvicorn main:app --host 0.0.0.0 --port 8000 --reload" ports: - 8001:8000 env_file: - .env networks: - appsearchnet depends_on: - db - opensearch restart: always volumes: - .:/app # Mount the project directory to /app in the container opensearch: image: opensearchproject/opensearch:latest container_name: opensearch environment: - plugins.security.disabled=true - OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_ADMIN_PASSWORD} - cluster.name=opensearch-cluster - node.name=opensearch - discovery.seed_hosts=opensearch - cluster.initial_cluster_manager_nodes=opensearch - bootstrap.memory_lock=true - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" ulimits: memlock: soft: -1 hard: -1 volumes: - opensearch-data:/usr/share/opensearch/data ports: - "9200:9200" networks: - appsearchnet healthcheck: test: ["CMD-SHELL", "curl -s http://localhost:9200 || exit 1"] interval: 30s timeout: 10s retries: 3 volumes: opensearch-data: networks: appsearchnet: name: appsearchnet
main.py
from db import opensearch_client @app.on_event("startup") def on_startup(): opensearch_client.create_index()
OpenSearch客户端配置(db/opensearch_client.py)
from dotenv import load_dotenv from opensearchpy import OpenSearch load_dotenv() opensearch_client = OpenSearch( hosts=[{'host': "opensearch", 'port': 9200}], http_auth=('admin', 'XXXX'), http_compress=True, use_ssl=False, verify_certs=False, ssl_assert_hostname=False, ssl_show_warn=False ) INDEX_NAME = "books" def create_index(): if not opensearch_client.indices.exists(INDEX_NAME): opensearch_client.indices.create( INDEX_NAME, body={ "settings": {"number_of_shards": 1}, "mappings": { "properties": { "id": {"type": "integer"}, "title": {"type": "text"}, "language": {"type": "keyword"}, "chapters": { "type": "nested", "properties": { "chapter_no": {"type": "integer"}, "title": {"type": "text"}, "content": {"type": "text"}, } } } } } )
运行时日志持续出现以下错误:
2024-10-21 12:51:19,796 - WARNING - HEAD http://opensearch:9200/books [status:N/A request:0.002s] Traceback (most recent call last): File "/usr/local/lib/python3.11/site-packages/urllib3/connection.py", line 196, in _new_conn sock = connection.create_connection( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ raise ConnectionRefusedError: [Errno 111] Connection refused
已确认OpenSearch服务正在运行,且能通过浏览器访问http://localhost:9200/获取正常响应:
{ "name" : "opensearch", "cluster_name" : "opensearch-cluster", "cluster_uuid" : "kGBFpJNlReiU2qdifiZsFQ", "version" : { "distribution" : "opensearch", "number" : "2.17.1", "build_type" : "tar", "build_hash" : "1893d20797e30110e5877170e44d42275ce5951e", "build_date" : "2024-09-26T21:59:32.078798875Z", "build_snapshot" : false, "lucene_version" : "9.11.1", "minimum_wire_compatibility_version" : "7.10.0", "minimum_index_compatibility_version" : "7.0.0" }, "tagline" : "The OpenSearch Project: https://opensearch.org/" }
请问该错误的原因是什么,如何解决?
原因分析
depends_on仅保证容器启动顺序,不等待服务就绪:虽然app服务配置了depends_on: [opensearch],但Docker只会确保OpenSearch容器先启动,不会等待OpenSearch服务完全初始化完成。FastAPI启动时执行startup事件,此时OpenSearch可能还在加载中,导致连接被拒绝。- 缺少基于健康检查的依赖等待:当前
depends_on没有关联OpenSearch的健康检查结果,无法确保服务可用后再启动FastAPI。
解决方案
方案1:升级Docker Compose版本并使用健康检查依赖
修改docker-compose.yml中app服务的depends_on配置,让它等待OpenSearch的健康检查通过:
depends_on: opensearch: condition: service_healthy db: condition: service_started # 如果db也需要健康检查,同理修改
注意:该特性需要Docker Compose版本2.1及以上,确保你的Compose版本符合要求。
方案2:在FastAPI启动时添加重试逻辑
修改main.py的startup事件,增加连接重试,直到OpenSearch可用:
from db import opensearch_client import time @app.on_event("startup") def on_startup(): max_retries = 10 retry_interval = 3 for attempt in range(max_retries): try: opensearch_client.create_index() break except Exception as e: if attempt == max_retries -1: raise e print(f"OpenSearch未就绪,等待{retry_interval}秒后重试...") time.sleep(retry_interval)
方案3:优化OpenSearch健康检查(可选)
如果OpenSearch初始化较慢,可以调整健康检查参数,确保更快检测到服务就绪:
healthcheck: test: ["CMD-SHELL", "curl -s http://localhost:9200/_cluster/health?wait_for_status=green || exit 1"] interval: 10s timeout: 5s retries: 10
这里使用_cluster/health?wait_for_status=green可以确保集群状态正常后才标记为健康,比单纯检查端口更可靠。
内容的提问来源于stack exchange,提问作者Rasik
相关产品推荐
相关产品推荐

