WIP - MaJ mongodb

This commit is contained in:
Ludovic Poujol 2020-05-06 12:17:30 +02:00
parent 731ed94686
commit c020af4d65

View file

@ -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 <https://docs.mongodb.com/v3.6/tutorial/i
### Paquets mongodb.org 3.6+
Les paquets fournis par mongodb.org n'ont pas de logrotate !
Les paquets fournis par mongodb.org n'ont pas de configuration pour logrotate !
On peut simplement ajouter cette configuration dans `/etc/logrotate.d/mongod`
~~~
@ -95,29 +96,28 @@ Il y a tout un chapitre (pas toujours très clair) sur la maière de gérer la r
## Configuration
### 3.4
La configuration de MongoDB se trouve dans le fichier `/etc/mongod.conf` qui est un fichier format au yaml.
Il n'y a pas d'autres fichiers de configuration
La configuration de MongoDB se trouve dans le fichier `/etc/mongod.conf` et le format a changé.
## Authentification
### 2.4
<https://docs.mongodb.com/v2.4/core/security-introduction/>
<https://docs.mongodb.com/manual/core/authentication/>
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 <https://jira.mongodb.org/browse/SERVER-5952>
### 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
<https://docs.mongodb.com/manual/security/>
## 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 : <https://docs.mongodb.com/manual/core/backups/>
<https://docs.mongodb.com/v2.4/core/backups/>
### Via snapshots du système de fichier
Voir <https://docs.mongodb.com/manual/tutorial/backup-with-filesystem-snapshots/>
### 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 :
<https://docs.mongodb.com/manual/core/backups/>
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 <https://docs.mongodb.com/manual/tutorial/configure-x509-member-authentication/.>
Sinon on pourra utiliser un keyfile <https://docs.mongodb.com/manual/tutorial/deploy-replica-set-with-keyfile-access-control/>
*/!\ 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
<http://www.mongodb.org/display/DOCS/Capped+Collections>
### 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
<https://github.com/comerford/mongo-munin>
~~~
# git clone <https://github.com/comerford/mongo-munin.git> /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