Introduction
This is a tutorial detailing how to configure a MongoDB replica set. If you are reading this, we can assume you know what a replica set, why is is necessary and how it works. Otherwise you can checkout the MongoDB documentation for replica sets and clusters.
In this tutorial, i will be using 3 Vagrant Ubuntu 12.04 boxes and MongoDB version 2.4.10. You should be comfortable spinning up vagrant boxes as this tutorial will not cover that. So let’s get started.
Spin up the three Vagrant boxes
Configure Vagrant VMs
I am assuming you have downloaded the ubuntu/precise64
12.04 box locally. So run the following commands to create vagrant boxes.
# Create a directory for each VM.
$ mkdir -p mongo01
$ mkdir -p mongo02
$ mkdir -p mongo03
# Create the Vagrant configuration files.
$ vagrant init ubuntu/precise64 --output mongo01/Vagrantfile
$ vagrant init ubuntu/precise64 --output mongo02/Vagrantfile
$ vagrant init ubuntu/precise64 --output mongo03/Vagrantfile
Next thing is to edit the Vagrantfile for each VM to have a specific hostname and IP address. Open each Vagrantfile and look for the lines that start with config.vm.network
, uncomment it and assign it any IP address you want and add a line for the hostname as indicated below.
# The IPs and the names are up to you.
# mongo01
config.vm.hostname = "mongo01"
config.vm.network private_network, ip: "192.168.33.1"
# mongo02
config.vm.hostname = "mongo02"
config.vm.network private_network, ip: "192.168.33.2"
# mongo03
config.vm.hostname = "mongo03"
config.vm.network private_network, ip: "192.168.33.3"
Find VMs by hostname or DNS
Now start the VMs with vagrant up
and ssh
into each with vagrant ssh
. Now to avoid referring to each VM by the IP address, let’s make sure we can refer to it by hostname or DNS by adding the IP addresses to the /etc/hosts
files. Open this file in each VM and
add the following lines.
192.169.33.1 mongo01
192.169.33.2 mongo02
192.169.33.3 mongo03
Save the file. ping
the VMs to ensure that you can reach one from the other. You can run ping mongo02
from the mongo01
VM. When you are certain the machines can find each other, we can now set up the replica set.
MongoDB Replica Set
Installing MongoDB on each VM
Run the following commands to install MongoDB 2.4.10. Do same for the other VMs.
# import the MongoDB public GPG Key
$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
# Create a /etc/apt/sources.list.d/mongodb.list file
$ echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
# reload your repository
$ sudo apt-get update
# Install MongoDB 2.4.10
$ sudo apt-get install mongodb-10gen=2.4.10
Edit configuration file.
Now we need to make some changes to the configuration file. Open /etc/mongodb.conf
and ensure that the following statements are uncommented. Add the ones that are not available like the line beginning with keyFile
.
# Supports Authentication
auth = true
dbpath=/var/lib/mongodb
logpath=/var/log/mongodb/mongod.log
logappend=true
# KeyFile for authenticating VMs in the replice set
keyFile=/var/lib/mongodb/keyFile
# Name of the repliceset. Set it to whatever you want. Must be the same for
# all the VMs in the repliceset.
replSet=demo
The replica set will use the keyFile
to authenticate the nodes in the set. Therefore any machine that will be part of this replica set must have a keyfile. We will now create the key file for one VM. As usual, do same for the other VMs in the set.
$ echo -n "MyReplicaSetKey" | md5sum|grep -o "[0-9a-z]\+" > keyFile
Now we need to change the ownership and permission modes of the file; as well as moving it to the path specified in the configuration file.
$ sudo cp keyFile /var/lib/mongodb
$ sudo chown mongodb:nogroup /var/lib/mongodb/keyFile
$ sudo chmod 400 /var/lib/mongodb/keyFile
Next step, we need to create users in the DB for authentication and authorization. We need to first comment out the line beginning with auth
. Because if authentication is enabled, we cannot even login to the DB since no user has been created yet.
Restart the mongodb service to ensure that the new configuration takes hold.
$ sudo service mongodb restart
Create Super Admin
Here we will create an admin accounts; The admin will have thr following roles: userAdminAnyDatabase
, clusterAdmin
, readWriteAnyDatabase
, dbAdminAnyDatabase
. This will allow the admin to create other users, manage the replica sets etc.
Choose any of the VMs as the primary node and connect to the MongoDB service running on it. The host and port are optional, unless your primary node exist on another machine.
$ mongo [--host localhost --port 27017]
This should show the MongoDB shell prompt. Run the following commands to create the user.
# change to the admin database
> use admin
# create a superuser with username and password as "admin" and can
# administer any database.
> db.addUser({
user: "admin", pwd: "admin",
roles: [
"readWriteAnyDatabase"
"userAdminAnyDatabase",
"clusterAdmin",
"dbAdminAnyDatabase"
]
})
Exit the shell. Go to the configuration file and uncomment the line beginning with auth
(remember we commented it out before creating the users) and restart the MongoDB service. Make sure the other nodes have the same configuration as well. They should have auth
enabled, have the same replSet
name as the others and the keyFile
path should be same. Restart the other MongoDB services as well.
Add nodes to the replica set
Enter the mongodb shell again and authenticate with the username and password as “admin”.
$ mongo
> use admin
> db.auth("admin", "admin")
1 # if successful and 0 otherwise
Then run the following commands to initiate the replica set and add nodes.
# Initiate replica set
> use admin
> rs.initiate()
# Verify the configuration
> rs.conf()
# Add mongo02 as a member or the replica set
> rs.add("mongo02:27017")
# Add mongo03 as a member or the replica set
> rs.add("mongo03:27017")
Check the status of the replica set by running rs.status()
which should return something similar to
> rs.status()
{
"set" : "demo",
"date" : ISODate("2014-10-28T23:12:29Z"),
"myState" : 1,
"members" : [
{
"_id" : 0,
"name" : "mongo01:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"optime" : {
"t" : 1414522392000,
"i" : 1
},
"optimeDate" : ISODate("2014-10-28T18:53:12Z"),
"self" : true
},
{
"_id" : 1,
"name" : "mongo02:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 15754,
"optime" : {
"t" : 1414522392000,
"i" : 1
},
"optimeDate" : ISODate("2014-10-28T18:53:12Z"),
"lastHeartbeat" : ISODate("2014-10-28T23:12:29Z"),
"pingMs" : 0
},
{
"_id" : 2,
"name" : "mongo03:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 7953,
"optime" : {
"t" : 1414522392000,
"i" : 1
},
"optimeDate" : ISODate("2014-10-28T18:53:12Z"),
"lastHeartbeat" : ISODate("2014-10-28T23:12:27Z"),
"pingMs" : 0
}
],
"ok" : 1
}
Add regular users to specific databases
At this point, our replica set has been created. We can create a database and add a user to that database like so.
# create a database called books
> use books
# Insert a record into the "novels" collection
> db.novels.insert({"title": "The Arrival"})
# add user with read and write access to the "books" database
> db.addUser({
user: "bob", pwd: "bob",
roles: ["readWrite"]
})
Now the next time we try to access the books
database, we have to authenticate. When we reconnect to the shell, the prompt will be the same as before. We can authenticate as the super admin and add users as well as manage the cluster set. When we authenticate, the shell prompt changes.
> use admin
> db.auth("fred", "fred")
1
demo:PRIMARY>
demo
is the name used for the replica set and the PRIMARY
indicate that this a primary node and the others will be SECONDARY
nodes. We can now insert, update and delete in the PRIMARY
node and it will be replicated in the SECONDARY
nodes.