0

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)
8
  • Have you tried defining db as a bridge network? Commented May 9, 2020 at 17:44
  • It is, it's just in a different yaml that has mongodb and mongo Express in it. Different yamls because I don't want to have to take the DB down every time I rebuild the API. And curl mongo:27017 works, just not the actual connection. Commented May 9, 2020 at 17:46
  • curl works from inside the API-container? Commented May 9, 2020 at 17:49
  • Yes, inside the API container. I can also ping homenotify.api from the mongo express container (mongo doesn't have ping or curl installed). Commented May 9, 2020 at 17:51
  • Hmm, weird. Can you confirm that your credentials does not contain an '@' sign? Commented May 9, 2020 at 17:56

1 Answer 1

2

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();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.