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
You can apply the following Git diff to make it work within the given constraints:
The idea behind it is to use
extra_hosts
instead ofnetwork_mode: host
. The end result is more or less the same in that it allows theapp
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.
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.