Chicky
Chicky

Reputation: 1257

NodeJS cannot connect to mongo replicat set

I created 3 containers on docker for mongo:

docker pull mongo

docker network create mongo-cluster

docker run -d -p 27017:27017 --name m1 --net mongo-cluster mongo mongod --replSet mongo-rs

docker run -d -p 27018:27017 --name m2 --net mongo-cluster mongo mongod --replSet mongo-rs

docker run -d -p 27019:27017 --name m3 --net mongo-cluster mongo mongod --replSet mongo-rs

and setup a replica set:

docker exec -it m1 mongo

config = { "_id" : "mongo-rs", "members" : [ { "_id" : 0, "host" : "m1:27017" }, { "_id" : 1, "host" : "m2:27017" }, { "_id" : 2, "host" : "m3:27017" }] }

rs.initiate(config)

mongo-rs:PRIMARY>

> db.pets.insert({name : 'pet'})
WriteResult({ "nInserted" : 1 })

m1 is PRIMARY, m2 and m3 is SECONDARY

After insert a record to m1, I access to m2, m3 and see the recort inserted at m1 appear on m2, m3. It works

But when I try connect to mongodb with NodeJS, use mongoose:

mongoose.connect('mongodb://localhost:27018,localhost:27019,localhost:27020/tsng?replicaSet=mongo-rs', {
  autoIndex: false,
  reconnectTries: Number.MAX_VALUE,
  reconnectInterval: 500,
  autoReconnect: true,
  poolSize: 10,
  bufferMaxEntries: 0,
  useNewUrlParser: true,
  useFindAndModify: false,
})

And an error has been throwed:

failed to connect to server [m3:27017] on first connect [Error: getaddrinfo ENOTFOUND m3
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:69:26) {
  name: 'MongoNetworkError'
}]

And one more question, can I have an option to config if I connect to multiple mongodb like above, if one of mongodb is not start up or failed, NodeJS can still working on started mongodb ?

Upvotes: 2

Views: 170

Answers (1)

Noam Yizraeli
Noam Yizraeli

Reputation: 5444

MongoDB replicaSet member discovery works by connecting to one of the members listed in the mongodb connection string then finding out by the replica members hostname configured in the replicaSet (the host names you initiated the replicaSet with).

from MongoDB docs on the matter (under host[:port]):

For a replica set, specify the hostname(s) of the mongod instance(s) as listed in the replica set configuration.

That means the hostnames you give when you initiate the replicaSet are the ones you'll use to connect to it with.

My prefered solution is to create a docker-compose.yml file configuring the mongodb cluster and the nodejs application, thuse making it easier to scale up and down, change configuration in a timely manner and with an added bonus it creates a docker network which lets you use the container or service names as DNS records in the docker network. here's a nice example of how to create such a setup. But in general here's a quick snippet:

version: "3"
services:
  myawesomenodejsapplication:
    container_name: myawesomenodejscontainer
    image: my-awesome-nodejs-application-image
    restart: on-failure
    networks:
      default:
    depends_on:
      - mongo1
      - mongo2
      - mongo3
  mongo1:
    hostname: mongo1
    container_name: localmongo1
    image: mongo
    expose:
    - 27017
    ports:
      - 27017:27017
    restart: always
    entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]
  mongo2:
    hostname: mongo2
    container_name: localmongo2
    image: mongo
    expose:
    - 27017
    ports:
    - 27018:27017
    restart: always
    entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]
  mongo3:
    hostname: mongo3
    container_name: localmongo3
    image: mongo
    expose:
    - 27017
    ports:
    - 27019:27017
    restart: always
    entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]

and then to initialize the cluster with docker-compose you can (like specified in the example link added above):

docker-compose up -d
docker exec -it localmongo1 mongo

rs.initiate(
  {
    _id : 'rs0',
    members: [
      { _id : 0, host : "mongo1:27017" },
      { _id : 1, host : "mongo2:27017" },
      { _id : 2, host : "mongo3:27017", arbiterOnly: true }
    ]
  }
)

exit

And because we set up mongodb1-3 as the container hostnames we can use them to connect to the set.

Affcourse if you intend to one day move the cluster or change the configuration you'll need to change the set members hostnames accordingly

Upvotes: 1

Related Questions