Unable to reach MongoDB listening on localhost (on host, Ubuntu 22.04) from within docker container

On Linux Ubuntu 22.04 I have created a docker container with a simple python script that has to connect to a MongoDB instance working on the host and listening on localhost.
To have a reproducible example consider what follows.
The Dockerfile is:

FROM ubuntu
RUN apt-get update
RUN apt-get install curl pip micro netcat -y
COPY requirements.txt app/requirements.txt

WORKDIR /app

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

COPY . /app

The requirements file contains:

fastapi==0.85.1
uvicorn==0.19.0
motor==3.1.0dev
black==22.10.0
python-dotenv==0.21.0 
orjson==3.8.0
requests==2.28.1

While the python script (inside app/db directory) is mongodb.py and contains:

import asyncio
import requests
from motor.motor_asyncio import (
    AsyncIOMotorClient,
    AsyncIOMotorCollection,
)

 
from bson.codec_options import DEFAULT_CODEC_OPTIONS

def get_collection(
     
) -> AsyncIOMotorCollection:
    # SET OPTION TO RETURN DATES AS TIMEZONE AWARE
    options = DEFAULT_CODEC_OPTIONS.with_options(tz_aware=True)


    motor_client = AsyncIOMotorClient(
        "mongodb://usr:pwd@host.docker.internal:27020/?authSource=admin&replicaSet=Replica1"
    )
    database = motor_client["DBNAME"]
    # APPLY OPTIONS TO RETURN DATETIMES AS TIMEZONE AWARE
    return database.get_collection(collName, codec_options=options)


async def main():
    # client = ClientMotor().client
    coll = get_collection()
    response=requests.get('http://host.docker.internal')
    print(response.text)
    async for doc in coll.find({}).limit(10):
        print(doc)


if __name__ == "__main__":
    try:
        asyncio.run(
            main()
        )
    except KeyboardInterrupt:
        pass

On host, I have installed and started NGINX that forwards stream to MongoDB from PORT 27020 to default port 27017 (always localhost).
The previous code works fine if not within a docker container (specifying localhost instead of the host.docker.internal) and I can connect to MongoDB from Compose by specifying PORT 27020 in the connection string.
If I build the container with

docker build -t test_motor .    

and thereafter run it with

docker run -it --add-host host.docker.internal:host-gateway test_motor  bash

Running

python3 mongodb.py.

From within /app/db, I correctly get a response from NGINX but I’m not able to connect to MongoDB.
If I execute from within the docker container

nc -zvw10 host.docker.internal 27020

the host/port is reachable.
What’s the problem? I don’t want to run the container with host=net, the only working solution so far!

Finally solved as following.
I had to add directConnection=True in the connection string to MongoDB and I had to set bindIp: 0.0.0.0 in MongoDB configuration file (in /etc/mongod.conf). To be clearer I changed motor_client as follows:

motor_client = AsyncIOMotorClient(
 username="user",
 password="secret",
 connectTimeoutMS=5000,
 socketTimeoutMS=5000,
 authSource="admin",
 host="host.docker.internal",
 port=27017,
 directConnection=True
)

Actually I don’t know why I had to set directConnection=True but this, in my configuration, solved the problem.

Hi @Sergio_Ferlito1,

It appears you are connecting to a replica set per the connection string:

replicaSet=Replica1

If so, the expected behaviour as per the MongoDB Server Discovery and Monitoring (SDAM) specification is to discover the replica set configuration and connect using configured the hostnames and ports.

If you remove the replicaSet parameter, the default behaviour in Motor 3.0+ is to automatically try to discover replica sets.

The directConnection=True option is used to connect to a single member of a deployment. This connection mode does not support failover or replica set discovery/monitoring, but will work with a configuration where you are forwarding via hostnames and/or ports that do not match the replica set configuration.

Regards,
Stennie

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.