skip to Main Content

I created an example repository that makes it easy to reproduce the issue. It also has instructions on how to run it.

I would like to have a MongoDB replica set running locally in Docker Compose and connect to it from both the host and from other Docker Compose services. It needs to be a self contained setup and you can’t make changes to the host, such as modifying /etc/hosts. It needs to work on Linux and MacOS, Windows doesn’t matter. You can’t use network: host. You can add new Docker Compose services though (among other things).

Given the linked repository, running:

docker compose up --build mongo
docker compose up --build app
./check_status

returns the following error:

Current Mongosh Log ID: 65f83906c5927e356113556b
Connecting to:          mongodb://<credentials>@127.0.0.1:27020/foo?replicaSet=rs0&serverSelectionTimeoutMS=2000&authSource=admin&appName=mongosh+2.1.5
MongoNetworkError: getaddrinfo ENOTFOUND mongo

The problematic point is that the replica set is created with mongo as a host, which is the name of the MongoDB service in Docker Compose. That way, the app (also running in Docker Compose) can easily connect to the DB and you benefit from network isolation.

Changing the host to localhost will make ./check_status work, but now the service-to-service connections fail.

The limitations I have given above may seem arbitrary and it might be possible that it can’t be solved under the above mentioned rules. But there are so many GitHub issues and discussions about this that I’d find it great if there was a canonical answer to this.

Applying the following diff to use network_mode: host doesn’t even seem to work on MacOS likely due to this:

diff --git a/docker-compose.yml b/docker-compose.yml
index 9c268c0..7d5c8d6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -13,6 +13,7 @@ services:
     ]
 
   mongo:
+    network_mode: "host"
     build:
       context: .
       args:
@@ -20,11 +21,9 @@ services:
     environment:
       MONGO_INITDB_ROOT_USERNAME: root
       MONGO_INITDB_ROOT_PASSWORD: root
-      MONGO_REPLICA_HOST: mongo
+      MONGO_REPLICA_HOST: localhost
       MONGO_REPLICA_PORT: 27020
       MONGO_COMMAND: "mongosh"
-    ports:
-      - "27020:27020"
     restart: unless-stopped
     healthcheck:
       test: [ "CMD", "mongosh", "admin", "--port", "$$MONGO_REPLICA_PORT", "--eval", "db.adminCommand('ping').ok" ]

2

Answers


  1. Chosen as BEST ANSWER

    You can apply the following Git diff to make it work within the given constraints:

    diff --git a/docker-compose.yml b/docker-compose.yml
    index 9c268c0..1915d80 100644
    --- a/docker-compose.yml
    +++ b/docker-compose.yml
    @@ -4,8 +4,10 @@ services:
       app:
         image: mongo:5
         entrypoint: mongosh 
    +    extra_hosts:
    +      - "localhost:host-gateway"
         command: [ 
    -      "mongodb://root:root@mongo:27020/foo?replicaSet=rs0",
    +      "mongodb://root:root@localhost:27020/foo?replicaSet=rs0",
           "--authenticationDatabase",
           "admin",
           "--eval",
    @@ -20,7 +22,7 @@ services:
         environment:
           MONGO_INITDB_ROOT_USERNAME: root
           MONGO_INITDB_ROOT_PASSWORD: root
    -      MONGO_REPLICA_HOST: mongo
    +      MONGO_REPLICA_HOST: localhost
           MONGO_REPLICA_PORT: 27020
           MONGO_COMMAND: "mongosh"
         ports:
    

    The idea behind it is to use extra_hosts instead of network_mode: host. The end result is more or less the same in that it allows the app service to connect to MongoDB through the exposed port on the host.

    You can now connect to the replica set both from the host (from an IDE or your shell, for example) and from other Docker Compose services.


  2. The problematic point is that replica set members should be accessible by the same name from inside and outside docker network. There is no workaround – it’s mongodb design.

    There are only 2 ways to achieve this – to share the network between guests and the host, or to resolve names to point to right containers in both networks.

    You explicitly said the shared network is not an option.

    Domain name resolution is another matter – /etc/hosts is just one of the options to manually resolve domains. It’s the simplest one but not the only, e.g. you can spin up a bind9 (or any other local dns) container and configure the host network to use it. It would be much more complex set up tho. I wouldn’t recommend it if there was no explicit request to stay away from /etc/hosts.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search