This will guide you through setting up a replica set in a docker environment using.
- Docker Compose
- MongoDB Replica Sets
- Mongoose
- Mongoose Transactions
Thanks to https://gist.github.com/asoorm for helping with their docker-compose file!
This will guide you through setting up a replica set in a docker environment using.
Thanks to https://gist.github.com/asoorm for helping with their docker-compose file!
| mongo-setup: | |
| container_name: mongo-setup | |
| image: mongo | |
| restart: on-failure | |
| networks: | |
| default: | |
| volumes: | |
| - ./scripts:/scripts | |
| entrypoint: [ "/scripts/setup.sh" ] # Make sure this file exists (see below for the setup.sh) | |
| 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", "--journal", "--dbpath", "/data/db", "--enableMajorityReadConcern", "false" ] | |
| volumes: | |
| - <VOLUME-DIR>/mongo/data1/db:/data/db # This is where your volume will persist. e.g. VOLUME-DIR = ./volumes/mongodb | |
| - <VOLUME-DIR>/mongo/data1/configdb:/data/configdb | |
| mongo2: | |
| hostname: mongo2 | |
| container_name: localmongo2 | |
| image: mongo | |
| expose: | |
| - 27017 | |
| ports: | |
| - 27018:27017 | |
| restart: always | |
| entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0", "--journal", "--dbpath", "/data/db", "--enableMajorityReadConcern", "false" ] | |
| volumes: | |
| - <VOLUME-DIR>/mongo/data2/db:/data/db # Note the data2, it must be different to the original set. | |
| - <VOLUME-DIR>/mongo/data2/configdb:/data/configdb | |
| mongo3: | |
| hostname: mongo3 | |
| container_name: localmongo3 | |
| image: mongo | |
| expose: | |
| - 27017 | |
| ports: | |
| - 27019:27017 | |
| restart: always | |
| entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0", "--journal", "--dbpath", "/data/db", "--enableMajorityReadConcern", "false" ] | |
| volumes: | |
| - <VOLUME-DIR>/mongo/data3/db:/data/db | |
| - <VOLUME-DIR>/mongo/data3/configdb:/data/configdb |
| # NOTE: This is the simplest way of achieving a replicaset in mongodb with Docker. | |
| # However if you would like a more automated approach, please see the setup.sh file and the docker-compose file which includes this startup script. | |
| # run this after setting up the docker-compose This will instantiate the replica set. | |
| # The id and hostname's can be tailored to your liking, however they MUST match the docker-compose file 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 |
| // If on a linux server, use the hostname provided by the docker compose file | |
| // e.g. HOSTNAME = mongo1, mongo2, mongo3 | |
| // If on MacOS add the following to your /etc/hosts file. | |
| // 127.0.0.1 mongo1 | |
| // 127.0.0.1 mongo2 | |
| // 127.0.0.1 mongo3 | |
| // And use localhost as the HOSTNAME | |
| mongoose.connect('mongodb://<HOSTNAME>:27017,<HOSTNAME>:27018,<HOSTNAME>:27019/<DBNAME>', { | |
| useNewUrlParser : true, | |
| useFindAndModify: false, // optional | |
| useCreateIndex : true, | |
| replicaSet : 'rs0', // We use this from the entrypoint in the docker-compose file | |
| }) |
| #!/bin/bash | |
| #MONGODB1=`ping -c 1 mongo1 | head -1 | cut -d "(" -f 2 | cut -d ")" -f 1` | |
| #MONGODB2=`ping -c 1 mongo2 | head -1 | cut -d "(" -f 2 | cut -d ")" -f 1` | |
| #MONGODB3=`ping -c 1 mongo3 | head -1 | cut -d "(" -f 2 | cut -d ")" -f 1` | |
| MONGODB1=mongo1 | |
| MONGODB2=mongo2 | |
| MONGODB3=mongo3 | |
| echo "**********************************************" ${MONGODB1} | |
| echo "Waiting for startup.." | |
| until curl http://${MONGODB1}:27017/serverStatus\?text\=1 2>&1 | grep uptime | head -1; do | |
| printf '.' | |
| sleep 1 | |
| done | |
| # echo curl http://${MONGODB1}:28017/serverStatus\?text\=1 2>&1 | grep uptime | head -1 | |
| # echo "Started.." | |
| echo SETUP.sh time now: `date +"%T" ` | |
| mongo --host ${MONGODB1}:27017 <<EOF | |
| var cfg = { | |
| "_id": "rs0", | |
| "protocolVersion": 1, | |
| "version": 1, | |
| "members": [ | |
| { | |
| "_id": 0, | |
| "host": "${MONGODB1}:27017", | |
| "priority": 2 | |
| }, | |
| { | |
| "_id": 1, | |
| "host": "${MONGODB2}:27017", | |
| "priority": 0 | |
| }, | |
| { | |
| "_id": 2, | |
| "host": "${MONGODB3}:27017", | |
| "priority": 0 | |
| } | |
| ],settings: {chainingAllowed: true} | |
| }; | |
| rs.initiate(cfg, { force: true }); | |
| rs.reconfig(cfg, { force: true }); | |
| rs.slaveOk(); | |
| db.getMongo().setReadPref('nearest'); | |
| db.getMongo().setSlaveOk(); | |
| EOF |
| async function transaction() { | |
| // Start the transaction. | |
| const session = await ModelA.startSession(); | |
| session.startTransaction(); | |
| try { | |
| const options = { session }; | |
| // Try and perform operation on Model. | |
| const a = await ModelA.create([{ ...args }], options); | |
| // If the first operation succeeds this next one will get called. | |
| await ModelB.create([{ ...args }], options); | |
| // If all succeeded with no errors, commit and end the session. | |
| await session.commitTransaction(); | |
| session.endSession(); | |
| return a; | |
| } catch (e) { | |
| // If any error occured, the whole transaction fails and throws error. | |
| // Undos changes that may have happened. | |
| await session.abortTransaction(); | |
| session.endSession(); | |
| throw e; | |
| } | |
| } |