Un cluster de MongoDB usando docker-machine

En esta ocasión vamos a crear un cluster de MongoDB con 3 notos, activaremos la autenticación y persistencia de los datos en el siste de archivos local y por último insertaremos un registro en el nodo principal y lo leeremos en uno de los nosos secundarios.

Lo primero que tenemos que tener son 3 máquinas, puede ver nuestro artículo Administrando hosts con docker-machine para ver como crear esas máquinas en local.

Inicamos veririfcando que tenemos las máquinas ejecutándose:

docker-machine ls
NAME              ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER    ERRORS
machine1          -        virtualbox   Running   tcp://192.168.99.101:2376           v1.11.1   
machine2          -        virtualbox   Running   tcp://192.168.99.102:2376           v1.11.1   
machine3          *        virtualbox   Running   tcp://192.168.99.103:2376           v1.11.1   

Crearemos un archivo clave que será usado en todos los nodos.
Tendremos que acceder a una de las máquinas y crear el archivo:

$ docker-machine ssh machine1
$ mkdir /home/core -p
$ cd /home/core
$ openssl rand -base64 741 > mongodb-keyfile
$ chmod 600 mongodb-keyfile
$ sudo chown 999 mongodb-keyfile

Ahora copiaremos en los otros 2 servidores en la misma ubicación:

$ docker-machine scp -r machine1:/home/core machine2:/home/
$ docker-machine scp -r machine1:/home/core machine3:/home/

Ahora debemos cambiar de propietario a los 3 archivos al id de usuario 999 porque dentro del contenedor del MongoDB es el único que tiene acceso al keyfile:

$ docker-machine ssh machine1 sudo chown 999 /home/core/mongodb-keyfile
$ docker-machine ssh machine2 sudo chown 999 /home/core/mongodb-keyfile
$ docker-machine ssh machine3 sudo chown 999 /home/core/mongodb-keyfile

En la primera máquina vamos a ejecutar el contenedor de MongoDB sin autenticación:

$ eval $(docker-machine env machine1)
$ docker run --name mongo -v /home/core/mongo-files/data:/data/db -v /home/core/mongo-files:/opt/keyfile --hostname=2machine1.example.com" -p 27017:27017 -d mongo:2.6.5 --smallfiles

Para crear el usuario admin, nos conectaremos al contenedor y en shell:

$ docker exec -it mongo /bin/bash

Crearemos un usuario admin.

$ mongo
Which will start the mongo shell.
MongoDB shell version: 2.6.5
connecting to: test
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
>

Cambiamos al usuario admin:

> use admin

Crear el nuevo usuario para la base de datos admin:

> db.createUser( {
 user: "siteUserAdmin",
 pwd: "password",
 roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
 });

Debería ver un mensaje de confirmación:

Successfully added user: {
"user" : "siteUserAdmin",
"roles" : [
         {
              "role" : "userAdminAnyDatabase",
              "db" : "admin"
         }
      ]
}

Creamos el usuario root:

> db.createUser( {
     user: "siteRootAdmin",
     pwd: "password",
     roles: [ { role: "root", db: "admin" } ]
 });

El mensaje de creación sería algo así:

Successfully added user: {
            "user" : "siteRootAdmin",
                  "roles" : [
            {
            "role" : "root",
                  "db" : "admin"
            }
        ]
}

Utilizaremos estos usuarios más adeante para usar el log. Ahora salimos del shell de mongo y de docker:

> exit
bye
$ exit

Detemos el contenedor de mongo

$ docker stop mongo

Ahora ejecutamos otra vez la instancia de mongo pero ahora indicandole el keyfile (seguimos en la máquina 1):

$ docker rm mongo
$ docker run --name mongo -v /home/core/mongo-files/data:/data/db -v /home/core:/opt/keyfile --hostname="machine1.example.com" --add-host machine1.example.com:$(docker-machine ip machine1) --add-host machine2.example.com:$(docker-machine ip machine2) --add-host machine3.example.com:$(docker-machine ip machine3) -p 27017:27017 -d mongo:2.6.5 --smallfiles --keyFile /opt/keyfile/mongodb-keyfile --replSet "rs0"

Nota que agregamos 3 –add-host por cada una de las máquinas.

Nos conectaremos al contenedor de mongo, nos autenticaremos e iniciaremos la réplica:

$ docker exec -it mongo /bin/bash
root@machine1:/# mongo
MongoDB shell version: 2.6.5
> 

Cambiamos al usuario admin:

> use admin

Ahora debemos autenticarnos con la contraseña password con la que le creamos:

> db.auth("siteRootAdmin", "password");
1

Inicializamos la réplica:

> rs.initiate()
{
         "info2" : "no configuration explicitly specified -- making one",
         "me" : "machine1.example.com:27017",
         "info" : "Config now saved locally.  Should come online in about a minute.",
         "ok" : 1
}
>

Revisamos la configuración:

> rs0:PRIMARY> rs.conf()
{
        "_id" : "rs0",
        "version" : 1,r
        "members" : [
              {
                  "_id" : 0,
                  "host" : "machine1.example.com:27017"
              }
        ]
}

Ahora ejecutaremos 2 contenedores más, uno en cada una de las otras dos máquinas:

$ eval $(docker-machine env machine2)
$ docker run --name mongo -v /home/core/mongo-files/data:/data/db -v /home/core:/opt/keyfile --hostname="machine2.example.com" --add-host machine1.example.com:$(docker-machine ip machine1) --add-host machine2.example.com:$(docker-machine ip machine2) --add-host machine3.example.com:$(docker-machine ip machine3) -p 27017:27017 -d mongo:2.6.5 --smallfiles --keyFile /opt/keyfile/mongodb-keyfile --replSet "rs0"


$ eval $(docker-machine env machine3)
$ docker run --name mongo -v /home/core/mongo-files/data:/data/db -v /home/core:/opt/keyfile --hostname="machine3.example.com" --add-host machine1.example.com:$(docker-machine ip machine1) --add-host machine2.example.com:$(docker-machine ip machine2) --add-host machine3.example.com:$(docker-machine ip machine3) -p 27017:27017 -d mongo:2.6.5 --smallfiles --keyFile /opt/keyfile/mongodb-keyfile --replSet "rs0"

Debemos añadir los otros 2 nodos dentro de la réplica. Regresamos a la machine y en el mongo shell el prompt habrá cambiado a rs0:PRIMARY>. Esto quiere decir que es el nodo primario para la réplica rs0.

$ eval $(docker-machine env machine1)
$ docker exec -ti mongo /bin/bash
root@machine1:/# mongo                                                                                                                      
MongoDB shell version: 2.6.5
connecting to: test
rs0:PRIMARY> 

rs0:PRIMARY> use admin
rs0:PRIMARY> db.auth("siteRootAdmin", "password");
1
rs0:PRIMARY> rs.add("machine2.example.com")
{ "ok" : 1 }
rs0:PRIMARY> rs.add("machine3.example.com")
{ "ok" : 1 }

Puede ver el estado de los servicios usando rs.status()

rs0:PRIMARY> rs.status()
{
    "set" : "rs0",
    "date" : ISODate("2016-05-27T18:50:14Z"),
    "myState" : 1,
    "members" : [
        {
            "_id" : 0,
            "name" : "machine1.example.com:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 10392,
            "optime" : Timestamp(1464374856, 1),
            "optimeDate" : ISODate("2016-05-27T18:47:36Z"),
            "electionTime" : Timestamp(1464364704, 2),
            "electionDate" : ISODate("2016-05-27T15:58:24Z"),
            "self" : true
        },
        {
            "_id" : 1,
            "name" : "machine2.example.com:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 161,
            "optime" : Timestamp(1464374856, 1),
            "optimeDate" : ISODate("2016-05-27T18:47:36Z"),
            "lastHeartbeat" : ISODate("2016-05-27T18:50:13Z"),
            "lastHeartbeatRecv" : ISODate("2016-05-27T18:50:14Z"),
            "pingMs" : 0,
            "syncingTo" : "machine1.example.com:27017"
        },
        {
            "_id" : 2,
            "name" : "machine3.example.com:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 158,
            "optime" : Timestamp(1464374856, 1),
            "optimeDate" : ISODate("2016-05-27T18:47:36Z"),
            "lastHeartbeat" : ISODate("2016-05-27T18:50:14Z"),
            "lastHeartbeatRecv" : ISODate("2016-05-27T18:50:13Z"),
            "pingMs" : 0,
            "syncingTo" : "machine1.example.com:27017"
        }
    ],
    "ok" : 1
}

Vamos a insertar un registro para luego leerlo en los otros nodos. Primero lo insertamos:

$ eval $(docker-machine env machine1)
$ docker exec -ti mongo /bin/bash
$ mongo
.
.
.
rs0:PRIMARY> db.auth("siteRootAdmin", "password");
1
rs0:PRIMARY> db.products.insert( { item: "card", qty: 15 } )
WriteResult({ "nInserted" : 1 })
rs0:PRIMARY> db.products.find()
{ "_id" : ObjectId("57489fd2ae8da148587ce2ba"), "item" : "card", "qty" : 15 }
rs0:PRIMARY> exit

Ahora lo leemos el valor en la machine2:

$ eval $(docker-machine env machine2)
$ docker exec -ti mongo /bin/bash
$ mongo
.
.
.
rs0:SECONDARY> db.auth("siteRootAdmin", "password");
1
rs0:SECONDARY> db.auth("siteRootAdmin", "password");
1
rs0:SECONDARY> rs.slaveOk()
rs0:SECONDARY> { "_id" : ObjectId("57489fd2ae8da148587ce2ba"), "item" : "card", "qty" : 15 }
rs0:SECONDARY> exit

Eso es todo, hemos creado un cluster en 3 máquinas con un contenedor MongoDB y lo hemos probado creando un registro en la máquina principal y leyendo en la secundaria.

Leave a comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *