Home > Net >  Unable connect to MongoDB listening on localhost (on host) from within a docker container
Unable connect to MongoDB listening on localhost (on host) from within a docker container

Time:10-24

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:[email protected]: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!

CodePudding user response:

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.

CodePudding user response:

--add-host adds a new entry to /etc/hosts inside the container. For this reason it needs to be a mapping between a name and an IP. And that IP needs to be known to (reachable from) the container.

In your case you need to find out the local network IP where MongoDB is listening on the host. Then use that IP like: --add-host db:<IP>. Your application then would connect to the database server named db.

  • Related