简体   繁体   中英

mongodb replica set connection in Docker container

I have created a mongodb replica set in 3 virtualbox vms, manasger1, worker1, worker2. each replica set has it's own containers. The replica set works fine and I can login to the servers:

docker exec -it mongoNode1 bash -c 'mongo -u $MONGO_USER_ADMIN -p $MONGO_PASS_ADMIN --authenticationDatabase "admin"'
MongoDB shell version v3.6.4
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.4
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
    http://docs.mongodb.org/
Questions? Try the support group
    http://groups.google.com/group/mongodb-user
rs1:PRIMARY> use medmart_db
switched to db medmart_db
rs1:PRIMARY> db.providers.findObe()
2018-05-14T17:46:38.844+0000 E QUERY    [thread1] TypeError: db.providers.findObe is not a function :
@(shell):1:1
rs1:PRIMARY> db.providers.findOne()
{
    "_id" : ObjectId("56ddb50c230e405eafaf7781"),
    "provider_id" : 6829973073,

When I run my nodejs application it connects to the replica set. The problem is that when I create a container for my application I get the following exception, my container stops, and I can no longer connect to the replica set PRIMARY, but instead to the secondary.

(node:16) UnhandledPromiseRejectionWarning: MongoNetworkError: failed to connect to server [worker2:27017] on first connect [MongoNetworkError: connection 5 to worker2:27017 timed out]
     at Pool.<anonymous> (/home/nupp/app/node_modules/mongoose/node_modules/mongodb-core/lib/topologies/server.js:505:11)
     at Pool.emit (events.js:182:13)
     at Connection.<anonymous> (/home/nupp/app/node_modules/mongoose/node_modules/mongodb-core/lib/connection/pool.js:329:12)
     at Object.onceWrapper (events.js:273:13)
     at Connection.emit (events.js:182:13)
     at Socket.<anonymous> (/home/nupp/app/node_modules/mongoose/node_modules/mongodb-core/lib/connection/connection.js:256:10)
     at Object.onceWrapper (events.js:273:13)
     at Socket.emit (events.js:182:13)
     at Socket._onTimeout (net.js:447:8)
     at ontimeout (timers.js:427:11)
     at tryOnTimeout (timers.js:289:5)
     at listOnTimeout (timers.js:252:5)
     at Timer.processTimers (timers.js:212:10)
 (node:16) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
 (node:16) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

I opened an issue ticket with mongoose for help but their solution doesn't work (they asked that I change from ip address to domain name but I still get the same error).

My connection module is:

'use strict';
const mongoose = require('mongoose');
const getURL = (options) => {
    const url = options.servers.reduce((accumulator, current) => {
        accumulator += current+',';
        return accumulator;
    },`mongodb://${options.user}:${options.pass}@`);    
    return `${url.substr(0,url.length-1)}/${options.db}?replicaSet=${options.repl}&authSource=admin`;
}
const connect = (config, mediator) => {
    mediator.once('boot.ready', () => {
        const options = {
            native_parser: true,
            poolSize: 5,
            user: config.user,
            pass: config.pass,
            promiseLibrary: global.Promise,
            autoIndex: false, 
            reconnectTries: 30, 
            reconnectInterval: 500, 
            bufferMaxEntries: 0,
            connectWithNoPrimary: true ,
            readPreference: 'ReadPreference.SECONDARY_PREFERRED',
        };              
        mongoose.connect(getURL(config), options);
        mongoose.connection.on('error', (err) => {  
            mediator.emit('db.error', err);
        });
        mongoose.connection.on('connected', () => {
            mediator.emit('db.ready', mongoose);
        });
    });
};
module.exports = Object.assign({},{connect});

My config file is:

'use strict';
const serverConfig = {
    port: 3000, 
};
const dbConfig = {
  db: 'xxxxxxx',
  user: 'xxxxxx',
  pass: 'xxxxxxx',
  repl: 'rs1',
  servers: (process.env.DB_SERVERS) ? process.env.DB_SERVERS.split(' ') : ['192.168.99.100:27017','192.168.99.101:27017','192.168.99.102:27017'],
};
module.exports = Object.assign({},{dbConfig, serverConfig});

So there are a couple of steps to resolving this issue. First and foremost is the fact that hosts file on the virtualBox machines must be updated to have the ip addresses of mongodb domains. To do that:

> docker-machine ssh manager1
docker@manager1:~$ sudo vi /etc/hosts
#add the following
192.168.99.100 manager1
192.168.99.101 worker1
192.168.99.102 worker2

Repeat for worker1 and worker2. If by adding the following you are good, then skip the second part. Next, if you get the following error:

Error: ERROR::providers-service::model::ProviderModel::getProviderById: TypeError: Cannot read property 'wireProtocolHandler' of null
     at cb (/home/nupp/app/src/model/ProviderModel.js:182:13)
     at /home/nupp/app/node_modules/mongoose/lib/model.js:4161:16
     at Immediate.Query.base.findOne.call (/home/nupp/app/node_modules/mongoose/lib/query.js:1529:14)
     at Immediate.<anonymous> (/home/nupp/app/node_modules/mquery/lib/utils.js:119:16)
     at runCallback (timers.js:696:18)
     at tryOnImmediate (timers.js:667:5)
     at processImmediate (timers.js:649:5)

Remove any options to mongoose.connect. Here's how mine looks now:

mediator.once('boot.ready', () => {
        const options = {};         
        mongoose.connect(getURL(config), options);
        mongoose.connection.on('error', (err) => {  
            mediator.emit('db.error', err);
        });
        mongoose.connection.on('connected', () => { 
            mediator.emit('db.ready', mongoose);
        });
    });

Hope my solution can help someone else. Took me a few long days to finally figure this out.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM