Sunday, October 9, 2022

[SOLVED] MongoDB servers running via docker can't see each other (Temporary failure in name resolution)

Issue

OK so, I have a multipass vm running on an M1 mac. It's hosting an ubuntu server. On this ubuntu server I've installed go, gin, and a bunch of other related technologies. I then get to mongo.

I first create the replication set with sudo docker network create mongoCluster

Then I spin up three nodes:

sudo docker run -d -p 27017:27017 --name mongo1 --network mongoCluster -e MONGODB_INITDB_ROOT_USERNAME=myuser -e MONGODB_INITDB_ROOT_PASSWORD=mypassword -e MONGO_INITDB_DATABASE=task mongo:latest mongod --replSet myReplicaSet --bind_ip localhost,mongo1

sudo docker run -d -p 27018:27017 --name mongo2 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip localhost,mongo2

sudo docker run -d -p 27019:27017 --name mongo3 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip localhost,mongo3

Then I initialize the replication set with

sudo docker exec -it mongo1 mongosh --eval "rs.initiate({
 _id: \"myReplicaSet\",
 members: [
   {_id: 0, host: \"mongo1\"},
   {_id: 1, host: \"mongo2\"},
   {_id: 2, host: \"mongo3\"}
 ]
})"

running sudo docker exec -it mongo2 mongosh --eval "rs.status()" shows me it's all set up correctly with mongo1 as the PRIMARY

So far so good!

Then I fire up my app and make the connection with the uri: mongodb://myuser:mypassword@localhost:27017/?retryWrites=true&w=majority Mongo throws an error Failed to ping cluster, but it then reports that it connected Then it throws this:

Could not create Task: server selection error: context deadline exceeded, current topology: { Type: ReplicaSetNoPrimary, Servers: [{ Addr: mongo1:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo1: Temporary failure in name resolution }, { Addr: mongo2:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo2: Temporary failure in name resolution }, { Addr: mongo3:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo3: Temporary failure in name resolution }, ] }

So it looks like the various nodes can't see each other I've been searching the googs for a while, but nothing seems to address my specific issue

I even put the money down on a training course to figure this out, but haven't. Please help!


Solution

There are a few problems here.

First of all MONGODB_INITDB_ROOT_USERNAME and MONGODB_INITDB_ROOT_PASSWORD are wrong. They should be MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_USERNAME.

The problem is then that mongo1 will crash shortly after startup because it requires a secret.key. Check the logs and you will see the error. Fixing that is another issue.

I recommend to try first without authentication. Here is something that works:

The step that you are missing:

echo 127.0.0.1 mongo1 >> /etc/hosts

database startup script:

#!/bin/bash

docker container rm -f mongo1 mongo2 mongo3

docker run -d -p 27017:27017 --name mongo1 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip_all

docker run -d -p 27018:27017 --name mongo2 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip_all

docker run -d -p 27019:27017 --name mongo3 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip_all

docker exec -it mongo1 mongosh --eval "rs.initiate({
 _id: \"myReplicaSet\",
 members: [
   {_id: 0, host: \"mongo1\"},
   {_id: 1, host: \"mongo2\"},
   {_id: 2, host: \"mongo3\"}
 ]
})"

Test program in go:

package main

import (
    "context"
    "fmt"
    "time"

    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readpref"
)

const uri = "mongodb://mongo1:27017/task?replicaSet=myReplicaSet&retryWrites=true&w=majority"

func main() {

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
    if err != nil {
        panic(err)
    }
    defer func() {
        if err = client.Disconnect(ctx); err != nil {
            panic(err)
        }
    }()

    if err := client.Ping(ctx, readpref.Primary()); err != nil {
        panic(err)
    }

    fmt.Println("Successfully connected and pinged")
}

Run this and you should get a successful response:

> go run ./main.go 
Successfully connected and pinged

Also I don't think you need to map all the replicas ports on the host. This should make things cleaner.



Answered By - Mihai
Answer Checked By - David Goodson (WPSolving Volunteer)