From c020af4d65dfd62f828497c8a58102a1f067cca3 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Wed, 6 May 2020 12:17:30 +0200 Subject: [PATCH] WIP - MaJ mongodb --- HowtoMongoDB.md | 535 +++++++++++++++++++----------------------------- 1 file changed, 210 insertions(+), 325 deletions(-) diff --git a/HowtoMongoDB.md b/HowtoMongoDB.md index fe5fe310..362674df 100644 --- a/HowtoMongoDB.md +++ b/HowtoMongoDB.md @@ -1,5 +1,6 @@ --- title: Howto MongoDB +categories: databases --- **CETTE DOCUMENTATION EST EN COURS DE RÉVISION....** @@ -59,7 +60,7 @@ Tous les détails sont disponibles sur + MongoDB a deux modes de fonctionnement pour l'authentification : * Un mode sans aucune authentification * Un mode avec authentification -Info : activer l'authentification génère des logs à chaque requête d'authentification qu'il n'est pas possible de désactiver avant la version 2.8 : voir +### Mode sans aucune authentification -#### Mode sans aucune authentification +Il s'agit du mode par défaut. La configuration sans authentification se fait ainsi : ~~~ -noauth = true +security: + authorization: disabled ~~~ Dans ce mode, il n'y a besoin d'aucun login / mot de passe pour accéder à l'ensemble des dbs, données, etc. @@ -126,77 +126,152 @@ au port TCP de MongoDB. #### Mode avec authentification -ATTENTION, ce mode doit être correctement configuré (ce qui n'est pas le cas par défaut). +L'authentification avec MongoDB peut paraître surprenante à première vue. En effet chaque utilisateur est associée à une base pour l'authentification. Mais les privilèges de l'utilisateur peuvent aller au-delà de la base de données qui sert à l'authentification. +Aussi, un utilisateur, pour s'authentifier, a besoin de son login, de son mot de passe **et** du nom de sa base d'authentification. -La configuration doit donc être ainsi : +> **Note** : Il peut donc y avoir plusieurs utilisateurs *foo* avec des privilèges différent. Ce qui les distinguera sera la base d'authentification + +Par convention, on définiera donc un utilisateur d'administration (*mongoAdmin*) dans la base `admin` + +Pour activer l'authenfication dans les réglages du service MongoDB, il faut alors passer la directive `authorization` à enabled, dans ~~~ -auth = true +security: + authorization: enabled ~~~ -Mais surtout, il faut créer (au moins) un utilisateur "admin" : +Il n'est pas forcément nécessaire de créer un compte avec un rôle administrateur avant d'activer l'authentification. +En effet, en l'absence de comptes utilisateurs, mongodb va accepter les connexions *locales* sans authentification pour permettre notamment de créer un compte. ~~~ $ mongo > use admin -> db.addUser("mongoadmin", "PASS") -{ - "user" : "mongoadmin", - "readOnly" : false, - "pwd" : "3882eaa67064707a7a6ae872504f310d" + +> db.createUser( + { + user: "mongoAdmin", + pwd: "PASS", + roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] + } +) + +Successfully added user: { + "user" : "mongoAdmin", + "roles" : [ + { + "role" : "userAdminAnyDatabase", + "db" : "admin" + } + ] } + + > db.system.users.find() -{ "_id" : ObjectId("4e8e132c76a7c48c75393b81"), "user" : "mongoadmin", "readOnly" : false, "pwd" : "3882eaa67064707a7a6ae872504f310d" } +{ "_id" : "admin.mongoAdmin", "userId" : UUID("3d475ec9-b82c-4312-8ce6-399bcbe3ca7a"), "user" : "mongoAdmin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "lO6VBPnKD0dC5TwRcCJwZg==", "storedKey" : "AUUwnA6v/8LbSEUpDU5EXQmp9sY=", "serverKey" : "DjHukfkoW0QE5Zy/5plD9FLrsu8=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "fqRp+/wrOGTyk1hiTn4RoPQr4jWVlqw79GsD4g==", "storedKey" : "/aaz0CJHlFfFDD5bSBPOBCnipn07ezx+X0pHFABeOV0=", "serverKey" : "W6BOf07RoYytpgJc4KOoTTTID7qJ1iah9Wqwub9xjgE=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } ~~~ -C'est seulement une fois ce premier utilisateur "admin" créé que l'authentication est activée !! -Si il n'est pas créé, l'authentification reste inactive... +C'est seulement une fois ce premier utilisateur "mongoAdmin" créé que l'authentication est activée !! +Si aucun utilisateur n'est crée, l'authentification reste inactive. On peut ensuite se connecter à la base "admin" ainsi : ~~~ -$ mongo admin -u mongoadmin -p PASS +$ mongo admin -u mongoAdmin -p PASS ~~~ +> *Note*: Si on spécifie simplement l'argument `-p`, sans valeur, mongo demandera de saisir le mot de passe. Ainsi, il ne sera pas dans votre historique shell ! + Pour les accès aux base, les utilisateurs sont stockés dans la collection _system.users_ propre à chaque base. -Ainsi pour créer un utilisateur pour une base données : - -~~~ -> use mydb -> db.addUser("foo","PASS"); -~~~ - -Les utilisateurs (admin ou associés à une base de données) peuvent n'avoir qu'un accès read-only si -ils sont créés ainsi : - -~~~ -> db.addUser("foo","PASS",true); -~~~ - -Enfin, pour supprimer un utilisateur : - -~~~ -> use mydb -> db.removeUser("foo"); -~~~ - -### 3.4 - - ## Utilisation -En ligne de commande : +### Administration en cli + +Comme pour MySQL, on peut manipuler mongo en CLI en mode interactif avec la commande `mongo` + +``` +$ mongo admin -u mongoAdmin -p PASS +``` + +Ici, pour se connecter à la base locale admin. Comme la base d'authentification n'est pas spécifiée, ça sera la base à laquelle on se connecte (ici admin) qui servira pour l'authentificat + +> *Note*: Pour vous connecter à une base différente de celle d'authentification, on pourra spécifier le nom de cette base avec l'argument `--authenticationDatabase XXX` + +#### Créer un utilisateur ~~~ -$ mongo -MongoDB shell version: 1.4.4 -url: test -connecting to: test -type "help" for help +> use admin; + +> db.createUser( + { + "user" : "myApp", + "pwd" : "PASS", + roles: [ + { "role" : "dbOwner", "db" : "myApp" } + ] + } +) ~~~ -Voici les opérations de base : +#### Supprimer un utilisateur + +Supprimons l'utilisateur foo de la base admin : + +~~~ +> use admin + +> db.dropUser('foo') +true +~~~ + +#### Lister tous les utilisateurs + +~~~ +> use admin + +> db.system.users.find() +{ "_id" : "admin.mongoAdmin", "userId" : UUID("3d475ec9-b82c-4312-8ce6-399bcbe3ca7a"), "user" : "mongoAdmin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "lO6VBPnKD0dC5TwRcCJwZg==", "storedKey" : "AUUwnA6v/8LbSEUpDU5EXQmp9sY=", "serverKey" : "DjHukfkoW0QE5Zy/5plD9FLrsu8=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "fqRp+/wrOGTyk1hiTn4RoPQr4jWVlqw79GsD4g==", "storedKey" : "/aaz0CJHlFfFDD5bSBPOBCnipn07ezx+X0pHFABeOV0=", "serverKey" : "W6BOf07RoYytpgJc4KOoTTTID7qJ1iah9Wqwub9xjgE=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } +~~~ + +#### Lister les bases de données + +~~~ +> show dbs +admin 0.000GB +config 0.000GB +foo 0.000GB +local 0.000GB +~~~ + +#### Supprimer une base + +Pour supprimer la base foo : + +~~~ +> use foo +> db.runCommand( { dropDatabase: 1 } ) +{ + "dropped" : "foo", + "ok" : 1 +} + +~~~ + +#### Lister les collections d'une base + +~~~ +> use foo +switched to db foo + +> show collections +bar +baz +~~~ + +#### Autre exemples + + +Voici quelques opérations de base ~~~ > show dbs @@ -276,44 +351,59 @@ foreach ($res as $obj) { ## Sauvegarde -### 2.4 +Il existe plusieurs stratégies possibles pour faire de la sauvegarde comme détaillée dans la documentation de mongod : - +### Via snapshots du système de fichier + +Voir + +### Via mongodump + +`mongodump` permet de créer des sauvegardes dans des fichiers au format bson utilisables par la commande `mongorestore` + +> **Important**: `mongodump` sauvegarde uniquement les documents d'une base. Cela signifie qu'après leur re-injections, il y aura une phase de reconstructions des index de la base de donnée (qui sera plus ou moins longue en fonction de la quantitée de données et des performances de la machine) + +> **Note**: Si l'authentification est activée, il convient de créer un compte dédié à la sauvegarde. Il existe pour cela un rôle dédié pour les opérations de sauvegarde `backup` ~~~ -# mkdir /home/backup/mongodump -# cd /home/backup/mongodump -# mongodump +# mkdir -p /home/backup/mongodump/ +# mongodump --username mongoDump --password PASS --authenticationDatabase admin --output /home/backup/mongodump/ ~~~ -### 3.4 +Ainsi, mongo écrire la sauvegarde dans `/home/backup/mongodump/`, avec un dossier par base. -Il exise plus de possibilités de sauvegarde dans les versions récentes : - +Il est possible de générer un dump compressé avec l'option `--gzip`. Lors de l'injection de la sauvegarde avec `mongorestore` il faudra alors préciser à nouveau cet argument. ## Restauration +> **Note** : Si l'authentification est activée, il existe aussi un rôle dédié pour la restoration de données : `restore` + ~~~ cd /home/backup/mongodump/ # mongorestore --db dbname dbname mongorestore --db admin admin ~~~ +> **Note** : Si le dump est compressé, il faut ajouter l'option `--gzip` à la commande + ## Réplication avec replica set -La réplication avec "replica set" nécessite au moins 3 machines : en effet, il va y avoir une élection -du master vers lequel seront faites toutes les écritures. +La réplication avec "replica set" nécessite au moins 3 machines. En effet, la selection d'un noeud primaire où se produisent les +écritures se fait au travers d'un processus d'élection. Les noeuds secondaires sont seulement utilisables en lecture. + +> **Note**: Si pour du multiples raisons, on ne peut avoir que deux noeuds mongodb supportant des données. On peut alors, introduire dans le cluster, un noeud de type 'arbitre'. Celui-ci doit bien être situé sur une machine indépendante des deux autres noeuds mongodb. +il ne supportera aucune donnée dans son datadir local, mais participera a l'election du noeud primaire. ### En Version 3.2+ Si vos mongod ne sont pas sur un LAN il est recommandé de mettre en place du TLS avec Sinon on pourra utiliser un keyfile -*/!\ Le datadir doit être vierge.* +> **Attention** : Le datadir des noeuds à ajouter à un replica set doit être vierge.* -#### Avec keyfile +#### Avec keyfile & authentification -Créer le keyfile sur une machine et déployer sur les autres le même fichier. +Créer le keyfile sur une machine et le déployer sur les autres membres du replica set ~~~ # openssl rand -base64 755 > /etc/mongod.key @@ -326,245 +416,72 @@ Modifier la configuration : ~~~ security: keyFile: /etc/mongod.key + replication: replSetName: rs0 ~~~ -Redémarrer les mongod. +On va alors démarrer mongodb sur la machine qui sera initialement "primaire". +C'est via celle-ci que l'on va amorcer le cluster. ~~~ # systemctl restart mongod ~~~ -Se connecter et initialiser le RS. - +Se connecter pour créer un compte administrateur *mongoAdmin* avec les roles `userAdminAnyDatabase` et `clusterAdmin` ~~~ # mongo -> rs.initiate( - { - _id : "rs0", - members: [ - { _id : 0, host : "mongo1.example.net:27017" }, - { _id : 1, host : "mongo2.example.net:27017" }, - { _id : 2, host : "mongo3.example.net:27017" } - ] - } -) -~~~ -Se connecter au master (voir avec rs.Status()) et créer un utilisateur admin et clusterAdmin. - -~~~ -# mongo > use admin -use admin -db.createUser( - { - user: "myUserAdmin", - pwd: "abc123", - roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] - } -) -db.createUser( - { - "user" : "clusteradmin", - "pwd" : "abc123", - roles: [ { "role" : "clusterAdmin", "db" : "admin" } ] +> db.createUser( + { + user: "mongoAdmin", + pwd: "PASS", + roles: [ { role: "userAdminAnyDatabase", db: "admin" }, + { "role" : "clusterAdmin", "db" : "admin" } ] } ) + ~~~ +On peut alors modifier la configuration pour activer l'authentification, et redémarrer le mongodb primaire. +Et démarrer tous les autres membres + +~~~ +security: + keyFile: /etc/mongod.key + authorization: enabled +~~~ + +Sur le noeud primaire, on va amorcer le cluster : + +~~~ +# mongo -u mongoAdmin -p PASS + +> rs.initiate() +~~~ + +On peut ensuite, ajouter les membres seconaires du cluster : + + +``` +> rs.add("192.0.2.3") +``` + +Si on soutaite ajouter un membre de typer *arbitre* : + +``` +> rs.addArb("192.0.2.100") +``` + + Le Replica Set est maintenant en place. #### Avec X.509 TODO -### En version 1.8 - -Soit trois machines de test avec MongoDB 1.8.2 : mongo1 (PRIMARY), mongo2 (SECONDARY), mongo3 (SECONDARY) - -Activer le paramètre suivant dans /etc/mongodb.conf : - -~~~ -# in replica set configuration, specify the name of the replica set -replSet = foo -# Enable journaling (recommended for replica set) -journal = true -~~~ - -À ce stade, on ne peut rien écrire sur les serveurs : - -~~~ -> db.test.insert({"coin": "coin"}) -not master -> rs.status() -{ - "startupStatus" : 3, - "info" : "run rs.initiate(...) if not yet done for the set", - "errmsg" : "can't get local.system.replset config from self or any seed (EMPTYCONFIG)", - "ok" : 0 -} -~~~ - - -Réinitialiser les bases sur chaque machine (attention, opération destructrice !) : - -~~~ -/etc/init.d/mongodb stop && mv /var/lib/mongodb/* /tmp && /etc/init.d/mongodb start -~~~ - -### Sur mongo1 (PRIMARY) - -Il faut ensuite s'assurer que : -- les machines communiquent bien au niveau réseau en TCP/27017 -- que les machines n'ont pas de NAT (ou alors il faudra utiliser des DNS) - -Puis on initialise la réplication via le mongo shell : - -~~~ -> config = {_id: 'foo' , members: [ {_id: 0, host: '1.2.3.4:27017'},{_id: 1, host: '1.2.3.5:27017'},{_id: 2, host: '1.2.3.6:27017'}]} -> rs.initiate(config); - { - "info" : "Config now saved locally. Should come online in about a minute.", - "ok" : 1 -} -> rs.help() -~~~ - -On peut aussi le faire étape par étape - -~~~ -> rs.initiate() -{ - "info2" : "no configuration explicitly specified -- making one", - "info" : "Config now saved locally. Should come online in about a minute.", - "ok" : 1 -} -~~~ - -Ajout des 2 SECONDARY : - -~~~ -setname:PRIMARY> rs.add("mongo2") -{ "ok" : 1 } - -setname:PRIMARY> rs.add("mongo3") -{ "ok" : 1 } -~~~ - -Consultation de l'état de la réplication sur le master : - -~~~ -setname:PRIMARY> rs.status() -{ - "set" : "setname", - "date" : ISODate("2011-08-09T15:42:54Z"), - "myState" : 1, - "members" : [ - { - "_id" : 0, - "name" : "mongo1", - "health" : 1, - "state" : 1, - "stateStr" : "PRIMARY", - "optime" : { - "t" : 1312904495000, - "i" : 1 - }, - "optimeDate" : ISODate("2011-08-09T15:41:35Z"), - "self" : true - }, - { - "_id" : 1, - "name" : "mongo2", - "health" : 1, - "state" : 2, - "stateStr" : "SECONDARY", - "uptime" : 76, - "optime" : { - "t" : 1312904495000, - "i" : 1 - }, - "optimeDate" : ISODate("2011-08-09T15:41:35Z"), - "lastHeartbeat" : ISODate("2011-08-09T15:42:54Z") - }, - { - "_id" : 2, - "name" : "mongo3", - "health" : 1, - "state" : 2, - "stateStr" : "SECONDARY", - "uptime" : 70, - "optime" : { - "t" : 1312904495000, - "i" : 1 - }, - "optimeDate" : ISODate("2011-08-09T15:41:35Z"), - "lastHeartbeat" : ISODate("2011-08-09T15:42:54Z") - } - ], - "ok" : 1 -} -~~~ - -Sur un slave : - -~~~ -SECONDARY> db.printReplicationInfo() -this is a slave, printing slave replication info. -source: 92.243.5.219:27017 - syncedTo: Sun Jan 29 2012 22:34:07 GMT+0100 (CET) - = 5744 secs ago (1.6hrs) -source: stampzz-prod01.evolix.net:27017 - syncedTo: Mon Jan 30 2012 00:09:47 GMT+0100 (CET) - = 4 secs ago (0hrs) -SECONDARY> use local -switched to db local -SECONDARY> db.oplog.rs.stats() -{ - "ns" : "local.oplog.rs", - "count" : 9616448, - "size" : 1166277368, - "avgObjSize" : 121.27943373686418, - "storageSize" : 1320140800, - "numExtents" : 1, - "nindexes" : 0, - "lastExtentSize" : 1320140800, - "paddingFactor" : 1, - "flags" : 0, - "totalIndexSize" : 0, - "indexSizes" : { - - }, - "capped" : 1, - "max" : 2147483647, - "ok" : 1 -} -~~~ - -Création d'un enregistrement de test : - -~~~ -setname:PRIMARY> db.foo.save({a:1}) -setname:PRIMARY> -~~~ - -### Sur mongo2 ou mongo3 (SECONDARY) - -Autorise le SECONDARY à traiter des requêtes : - -~~~ -setname:SECONDARY> rs.slaveOk() -~~~ - -Vérification de la présence de l'enregistrement de test : - -~~~ -setname:SECONDARY> db.foo.find() -{ "_id" : ObjectId("4e41558da08ccc36090745be"), "a" : 1 } -~~~ ### Sortir un mongo de la réplication @@ -773,62 +690,27 @@ Le * "v" : 0 * signifie que l'index n'est pas à jour. Répéter l'opération pour toutes les collections ayant des indexes ! -## CAPPED +## Monitoring - +### Créer un accès -## Monitoring avec MMS - -MMS (MongoDB Monitoring Service) est une service fourni gratuitement par 10gen. -*Déprécié, maintenant c'est payant et ça s'apelle MongoDB Cloud Manager* - -### Installation - -Créer un compte sur mms.10gen.com, créer un groupe et télécharger l'archive (qui contient déjà la clé API du groupe). - -La décompresser dans un dossier (et donner les droits mongodb). +Si l'authentification est activée, il faut alors créer un compte. On peut utiliser le role `clusterMonitor` ~~~ -cd /opt -tar zxvf 10gen*.tar.gz -chown -R mongodb:mongodb mms-agent -~~~ - -Installer python-bson et python-pymongo (via backports). - -/etc/apt/preferences: - -~~~ -Package: python-pymongo -Pin: release a=squeeze-backports -Pin-Priority: 999 -~~~ - -Le lancer via le compte mongodb: - -sudo -u mongodb nohup python /opt/mms-agent/agent.py > /var/log/mongodb/agent.log 2>&1 & - - -## Monitoring avec Munin - -### Créer un accès - -~~~ -use admin -db.createUser( +> use admin +> db.createUser( { user: "monitoring", - pwd: "XXX", + pwd: "PASS", roles: [ "clusterMonitor" ] } ) ~~~ -### Plugin mongo-munin +### Munin : Plugin mongo-munin - ~~~ # git clone /tmp/mongo-munin # mkdir -p /usr/local/share/munin/plugins @@ -840,8 +722,11 @@ db.createUser( /etc/munin/plugin-conf.d/mongo - ~~~ [mongo_*] -env.MONGO_DB_URI mongodb://monitoring:XXX@localhost:27017/admin +env.MONGO_DB_URI mongodb://monitoring:PASS@localhost:27017/admin ~~~ + +### NRPE : check_mongo + +TODO