I’m working on a FastAPI
project that integrates with OpenSearch
using Docker Compose. I keep encountering a ConnectionRefusedError
when trying to connect to the OpenSearch service.
Here is my setup:
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 Client Configuration (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"},
}
}
}
}
}
)
When I run the setup, I keep getting the following error in my logs:
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
I have confirmed that the OpenSearch service is running, but my FastAPI application can’t seem to connect. It looks like it is unable to reach http://opensearch:9200.
But I can call http://localhost:9200/ in my browser and print this:
{
"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/"
}
What could be causing this error, and how can I fix it?
Adding as an answer for posterity. depends_on
alone doesn't guarantee that the service will wait for the database to be healthy. To wait until the healthcheck succeeds, you need a condition
in the depends_on
block:
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:
opensearch:
condition: service_healthy
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
See the Docker docs here for more information.