Reputation: 21
I am working on a small personal project and recently switched from PostgreSQL to MongoDB. Mongo is running in a docker container, and when running my API locally, everything works fine. However, when I try to run my API in docker, the only way I can get it to connect successfully to Mongo is by using my local network IP for the connection string. When I try to connect via hostname (either host.docker.internal
or the mongo container name mongo
), it fails to connect. I've confirmed that both curl host.docker.internal:27017
and curl mongo:27017
succeed.
In other words, The connection string is formatted as mongodb://user:pwd@host/database
. When running locally, this works with host = "localhost"
, and it works in docker with host = "my.local.ip"
, but not with host = "host.docker.internal"
or host = "mongo"
.
Connecting:
var mongoClient = new MongoClient(
$"mongodb://{dbCreds.Username}:{dbCreds.Password}@{dbCreds.Host}/{dbCreds.Database}");
docker_compose.yaml:
version: '3.7'
services:
homenotify.api:
build: ./HomeNotify.API
ports:
- '5000:80'
networks:
- api
- db
environment:
- GOOGLE_CREDENTIAL=service_account_key.json
- DB_CREDENTIALS=db_credentials_docker.json
networks:
api:
name: api
driver: bridge
db:
name: db
external: true
Stack trace:
Unhandled exception. System.TimeoutException: A timeout occured after 30000ms selecting a server using CompositeServerSelector{ Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0150000 } }. Client view of cluster state is { ClusterId : "1", ConnectionMode : "Automatic", Type : "Unknown", State : "Disconnected", Servers : [{ ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/mongo:27017" }", EndPoint: "Unspecified/mongo:27017", ReasonChanged: "Heartbeat", State: "Disconnected", Type: "Unknown", HeartbeatException: "MongoDB.Driver.MongoConnectionException: An exception occurred while opening a connection to the server.
---> System.PlatformNotSupportedException: Sockets on this platform are invalid for use after a failed connection attempt.
at System.Net.Sockets.Socket.ThrowMultiConnectNotSupported()
at System.Net.Sockets.Socket.BeginConnect(String host, Int32 port, AsyncCallback requestCallback, Object state)
at MongoDB.Driver.Core.Connections.TcpStreamFactory.ConnectAsync(Socket socket, EndPoint endPoint, CancellationToken cancellationToken)
at MongoDB.Driver.Core.Connections.TcpStreamFactory.CreateStreamAsync(EndPoint endPoint, CancellationToken cancellationToken)
at MongoDB.Driver.Core.Connections.BinaryConnection.OpenHelperAsync(CancellationToken cancellationToken)
Upvotes: 0
Views: 2524
Reputation: 21
Apparently, dotnet has an issue with sockets not supporting hostnames on non-Windows platforms. This is why it works locally but not in docker: it's on Windows when running locally, and Linux when running in docker. This was supposedly fixed years ago, but that's what the issue is.
Manually resolving the IP address from the hostname, and using the IP to connect instead, resolved my issue. Found the code snippet here.
dbCreds.Host = Dns.GetHostAddresses(dbCreds.Host)
.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork)?.ToString();
Upvotes: 2