Lukas Short
Lukas Short

Reputation: 21

Can't connect to MongoDB in docker container via hostname

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

Answers (1)

Lukas Short
Lukas Short

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

Related Questions