Introduction
MongoDB n'est pas seulement une base de données que l'on installe puis que l'on oublie. En production, c'est un système distribué complexe avec ses propres mécanismes internes, son architecture et ses modes de défaillance. Si vous le traitez comme une boîte noire, vous serez finalement surpris — généralement à 3 heures du matin lors d'un incident.
Ce guide s'adresse aux développeurs, aux ingénieurs DevOps et aux équipes de startups qui doivent exploiter MongoDB en toute sécurité. Il couvre des concepts avancés tels que l'inventaire des versions, les modifications de configuration, les diagnostics, la reprise après incident et les opérations quotidiennes. Chaque section comprend des commandes concrètes, les résultats attendus et les chemins de récupération. L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés plutôt que des secrets, vérifier les résultats et documenter la marche à suivre pour revenir en arrière.
Nous utiliserons mongosh, le shell MongoDB, pour tous les exemples. Les commandes sont spécifiques à la version ; vérifiez toujours la version installée au préalable.
Inventaire des versions et de l'environnement
Avant de toucher à tout déploiement MongoDB, vous devez savoir exactement ce que vous exécutez et comment il est configuré. C'est la base d'opérations sûres. Un inventaire des versions permet d'éviter les pilotes incompatibles, les fonctionnalités non prises en charge et les mises à niveau incompatibles.
Identifier la version installée
Exécutez cette commande en lecture seule dans mongosh :
db.version()
Résultat attendu (exemple) :
'6.0.5'
Notez la version exacte. Les versions de MongoDB suivent un schéma majeure.mineure.corrective. Les versions mineures peuvent introduire des changements de comportement ; testez donc toujours avec votre correctif spécifique.
Vérifiez également les informations de build, qui incluent le moteur de stockage (par exemple wiredTiger) et d'autres détails :
db.runCommand({ buildInfo: 1 })
Extrait du résultat attendu :
{
version: '6.0.5',
gitVersion: '...',
modules: [],
allocator: 'tcmalloc',
javascriptEngine: 'mozjs',
sysInfo: 'deprecated',
versionArray: [ 6, 0, 5, 0 ],
openssl: { running: 'OpenSSL 1.1.1f 31 Mar 2020', compiled: 'OpenSSL 1.1.1f 31 Mar 2020' },
buildEnvironment: { ... },
bits: 64,
debug: false,
maxBsonObjectSize: 16777216,
storageEngines: [ 'devnull', 'ephemeralForTest', 'wiredTiger' ]
}
Notez maxBsonObjectSize (16 Mo par défaut). Cela compte lors de la conception de documents pour ne pas dépasser la limite.
Vérifier la topologie du déploiement
Déterminez si vous exécutez une instance autonome, un ensemble de réplicas ou un cluster partitionné :
rs.status()
Sur un serveur autonome, cela renvoie une erreur comme not running with --replSet. Sur un ensemble de réplicas, cela montre les états des membres. Capturez la topologie car de nombreuses opérations (par exemple, les transactions, les flux de changement) nécessitent un ensemble de réplicas.
Lister les bases de données et les collections
Observation en lecture seule :
show dbs
show collections
Ces commandes vous aident à comprendre le paysage de données avant d'apporter des modifications.
Capturer la configuration actuelle
Pour les ensembles de réplicas et les clusters partitionnés, capturez la configuration actuelle :
rs.conf()
Résultat attendu (extrait) :
{
_id: 'myReplicaSet',
version: 5,
term: 3,
members: [
{ _id: 0, host: 'mongodb0.example.net:27017', priority: 1 },
{ _id: 1, host: 'mongodb1.example.net:27017', priority: 1 },
{ _id: 2, host: 'mongodb2.example.net:27017', priority: 0, hidden: true }
],
settings: { ... }
}
Stockez ceci dans un endroit sécurisé. C'est votre référence de restauration si une reconfiguration tourne mal.
Prérequis pour des modifications sûres
- Accès en lecture seule pour l'observation.
- Accès en écriture uniquement pour les modifications prévues.
- Une sauvegarde des fichiers de configuration ou de la base de données avant toute intervention.
- Un plan de récupération documenté et testé.
Ne stockez jamais de véritables informations d'identification, jetons ou clés privées dans des scripts ou des articles. Utilisez des variables d'environnement ou une gestion des secrets.
Chemin de configuration sécurisé
La modification de la configuration de MongoDB doit suivre un chemin strict : observer, planifier, modifier un élément, vérifier et être prêt à revenir en arrière. Cette section couvre les modifications de configuration courantes avec des exemples.
Étude de cas : Activer l'authentification
MongoDB n'active pas le contrôle d'accès par défaut dans les anciens tutoriels, mais c'est essentiel en production. Voici le chemin sûr.
Prérequis
- MongoDB 6.0+ installé.
- Accès au shell du serveur.
- Aucun compte utilisateur existant (installation fraîche) ou capacité à créer le premier administrateur.
Étape 1 : Observer l'état actuel
Exécutez :
db.runCommand({ connectionStatus: 1 })
Résultat attendu (extrait) :
{
authInfo: { authenticatedUsers: [], authenticatedUserRoles: [] },
ok: 1
}
Un tableau authenticatedUsers vide signifie que vous êtes connecté sans authentification.
Étape 2 : Planifier le changement
Vous allez créer un administrateur utilisateur dans la base de données admin, puis redémarrer MongoDB avec --auth activé.
Étape 3 : Créer l'utilisateur administrateur
Dans mongosh, sans authentification :
use admin
db.createUser({
user: "adminUser",
pwd: "ChangeMe123!", // Remplacez par un mot de passe fort, idéalement depuis un gestionnaire de secrets
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
})
Résultat attendu :
{ ok: 1 }
Étape 4 : Activer l'authentification dans la configuration
Modifiez le fichier de configuration MongoDB (par exemple, /etc/mongod.conf) et ajoutez :
security:
authorization: enabled
Étape 5 : Redémarrer MongoDB
Utilisez votre système d'initialisation (par exemple, systemctl restart mongod).
Étape 6 : Vérifier que l'authentification est appliquée
Connectez-vous sans informations d'identification :
mongosh --eval "db.runCommand({ connectionStatus: 1 })"
Le résultat attendu doit montrer aucun utilisateur authentifié et éventuellement une erreur pour les opérations nécessitant une authentification.
Connectez-vous ensuite avec les informations d'identification :
mongosh -u adminUser -p 'ChangeMe123!' --authenticationDatabase admin --eval "db.runCommand({ connectionStatus: 1 })"
Résultat attendu (extrait) :
{
authInfo: {
authenticatedUsers: [ { user: 'adminUser', db: 'admin' } ],
authenticatedUserRoles: [ { role: 'userAdminAnyDatabase', db: 'admin' } ]
},
ok: 1
}
Chemin de restauration
Si l'authentification pose problème (par exemple, impossible de se connecter), rétablissez le paramètre security.authorization à disabled et redémarrez. Ensuite, dépannez.
Étude de cas : Ajuster la préoccupation d'écriture (write concern)
La préoccupation d'écriture contrôle l'accusé de réception des écritures. La modifier peut avoir un impact sur la durabilité et les performances.
Observer la préoccupation d'écriture actuelle
db.getWriteConcern()
Résultat attendu (exemple) :
{ w: 'majority', wtimeout: 0 }
Modifier la préoccupation d'écriture pour une session
db.getMongo().setWriteConcern({ w: "majority", wtimeout: 5000 })
Vérifier
db.getWriteConcern()
Résultat attendu :
{ w: 'majority', wtimeout: 5000 }
Rayon d'impact
w: 1renvoie après l'accusé de réception du primaire ; plus rapide mais moins durable.w: "majority"exige l'accusé de réception de la majorité des membres de l'ensemble de réplicas ; durabilité plus forte mais potentiellement plus lente.wtimeoutspécifie combien de temps attendre l'accusé de réception.
Récupération
Si les écritures expirent, vérifiez la santé de l'ensemble de réplicas et le réseau. Vous devrez peut-être revenir temporairement à w: 1.
Vérification et diagnostic
Après toute modification, vous devez vérifier le résultat. Les diagnostics vous aident à détecter les problèmes avant qu'ils ne deviennent des incidents.
Commandes de diagnostic courantes
État du serveur
db.serverStatus()
Cela renvoie des métriques détaillées. Concentrez-vous sur :
connections: actuelles, disponibles et totales créées.opcounters: nombre d'opérations par seconde.mem: utilisation de la mémoire.network: octets entrants/sortants.locks: temps d'acquisition des verrous.wiredTiger: détails du cache et de la concurrence.
Exemple d'extrait :
{
connections: { current: 15, available: 51185, totalCreated: 120 },
opcounters: { insert: 1000, query: 5000, update: 200, delete: 50, getmore: 100, command: 3000 },
mem: { bits: 64, resident: 500, virtual: 1200, supported: true },
network: { bytesIn: 1000000, bytesOut: 500000, numRequests: 10000 }
}
Opérations en cours
Pour voir ce qui s'exécute actuellement :
db.currentOp()
Filtrez les opérations de longue durée :
db.currentOp({ "secs_running": { $gt: 10 } })
Cela aide à identifier les requêtes lentes ou les commandes bloquées.
Profilage
Activez le profilage pour capturer les requêtes lentes :
db.setProfilingLevel(1, { slowms: 100 })
Cela enregistre les opérations de plus de 100 millisecondes dans la collection system.profile.
Affichez les données de profilage :
db.system.profile.find().sort({ ts: -1 }).limit(5).pretty()
État de l'ensemble de réplicas
rs.status()
Vérifiez health, stateStr (par exemple, PRIMARY, SECONDARY) et lastHeartbeat pour chaque membre.
État du cluster partitionné
sh.status()
Affiche les partitions, les chunks et l'état de l'équilibreur.
Interpréter les signaux de défaillance
- Nombre élevé de
currentOp: possible contention de verrous ou opérations lentes. - Augmentation de
connections.current: fuite de connexions dans l'application. - Évictions du cache
wiredTiger.cacheen augmentation : pression sur le cache ; envisagez d'ajouter de la RAM ou d'optimiser les requêtes. stateStrd'un membre de l'ensemble de réplicas =RECOVERING: le membre rattrape son retard, peut-être en raison d'un important retard de réplication.- Pic de
numRequestssans opcounters correspondants : possible analyse malveillante ou client mal configuré.
Exemple : Diagnostiquer une requête lente
- Activez le profilage :
db.setProfilingLevel(1, { slowms: 50 }). - Attendez que les requêtes lentes apparaissent.
- Interrogez
system.profile:
db.system.profile.find({ millis: { $gt: 50 } }).sort({ millis: -1 }).limit(1).pretty()
Résultat attendu (extrait) :
{
op: 'query',
ns: 'mydb.orders',
command: {
find: 'orders',
filter: { customer_id: 'C123' },
...
},
keysExamined: 0,
docsExamined: 500000,
nreturned: 10,
millis: 800,
planSummary: 'COLLSCAN'
}
COLLSCAN signifie un balayage de collection : aucun index n'a été utilisé. Corrigez en créant un index sur customer_id.
Modes de défaillance et récupération
MongoDB peut échouer de diverses manières. Comprendre les modes de défaillance courants et avoir des plans de récupération est crucial.
Mode de défaillance : Panne du nœud primaire (ensemble de réplicas)
Symptôme : Les applications reçoivent des erreurs de connexion ou les écritures échouent.
Observation : rs.status() montre le primaire comme stateStr: 'UNKNOWN' ou manquant. Les membres secondaires sont sains mais ne peuvent pas élire un primaire car ils n'ont pas la majorité.
Récupération : Si le primaire est en panne et que la majorité des membres est toujours disponible, une élection devrait se produire automatiquement. Vérifiez avec rs.status() qu'un nouveau primaire est élu. Sinon, vérifiez les partitions réseau et les configurations des membres. Vous devrez peut-être forcer une reconfiguration si la majorité est perdue (à utiliser avec une extrême prudence).
Exemple de reconfiguration forcée (uniquement si nécessaire) :
cfg = rs.conf()
// Supprimer le membre injoignable des membres votants
cfg.members = cfg.members.filter(m => m.host !== 'down-node:27017')
cfg.version += 1
rs.reconfig(cfg, { force: true })
Vérification : rs.status() doit montrer un nouveau primaire et les membres restants en bonne santé.
Mode de défaillance : Retard de réplication
Symptôme : Les membres secondaires sont en retard sur le primaire, provoquant des lectures de données obsolètes.
Observation : rs.printReplicationInfo() et rs.printSecondaryReplicationInfo() montrent le retard en secondes.
Récupération : Identifiez la cause : latence réseau, charge d'écriture élevée, matériel secondaire insuffisant ou opérations de longue durée sur le secondaire. Optimisez les écritures, ajoutez de la capacité ou réduisez la charge de lecture sur le secondaire.
Vérification : Le retard diminue en dessous du seuil acceptable (par exemple, <2 secondes pour votre cas d'utilisation).
Mode de défaillance : Disque plein
Symptôme : Les écritures échouent avec QuotaExceeded ou No space left on device.
Observation : Vérifiez l'utilisation du disque : df -h sur le serveur.
Récupération : Libérez de l'espace en supprimant les anciennes sauvegardes, les journaux ou en déplaçant les fichiers de données vers un disque plus grand. Pour un soulagement immédiat, envisagez de réduire l'oplog s'il est volumineux (mais comprenez les implications). À long terme : surveillez l'utilisation du disque et définissez des alertes.
Vérification : Les écritures réussissent et l'utilisation du disque est en dessous du seuil.
Mode de défaillance : Problèmes d'authentification
Symptôme : Les applications ne peuvent pas se connecter avec des erreurs Authentication failed.
Observation : Vérifiez les comptes utilisateurs et les rôles : db.getUsers() et db.getRoles().
Récupération : Si le mot de passe de l'utilisateur est perdu, réinitialisez-le. Si le mécanisme d'authentification est incorrect (par exemple, SCRAM vs x.509), corrigez la chaîne de connexion. Assurez-vous que la base de données d'authentification est spécifiée.
Exemple de réinitialisation de mot de passe :
db.changeUserPassword("appUser", "NewStrongPass123!")
Vérification : Testez la connexion avec le nouveau mot de passe.
Meilleures pratiques pour la récupération
- Ayez toujours des sauvegardes récentes et testez les procédures de restauration.
- Utilisez régulièrement
mongodumpetmongorestore. - Documentez les procédures de récupération.
- Simulez des défaillances en environnement de test pour pratiquer la récupération.
Liste de contrôle des opérations
Une liste de contrôle opérationnelle quotidienne garantit une surveillance cohérente et une détection rapide des problèmes. Voici une liste concrète avec des commandes et des résultats attendus.
Liste de contrôle quotidienne
| Élément | Comment vérifier | Résultat attendu | En cas d'échec |
|---|---|---|---|
| Santé de l'ensemble de réplicas | rs.status() | Tous les membres health: 1, un PRIMARY | Enquêter sur l'état du membre, vérifier les journaux |
| Retard de réplication | rs.printSecondaryReplicationInfo() | Retard inférieur au seuil (par exemple, 5 secondes) | Mettre à l'échelle le secondaire, optimiser les écritures |
| Utilisation du disque | df -h sur le répertoire de données | Utilisation inférieure à 80 % | Nettoyer, étendre le stockage |
| Nombre de connexions | db.serverStatus().connections.current | Inférieur au maximum configuré (par exemple, 70 % de maxIncomingConnections) | Vérifier les fuites de connexion de l'application, mettre à l'échelle horizontalement |
| Requêtes lentes | Interroger system.profile pour les requêtes >100 ms | Pas de nouvelles requêtes lentes | Optimiser les index, réécrire les requêtes |
| Taille de l'oplog | rs.printReplicationInfo() | Fenêtre temporelle de l'oplog >24 heures | Augmenter la taille de l'oplog si nécessaire |
| Journaux d'erreurs | Vérifier le fichier journal MongoDB pour les lignes E | Pas de nouvelles erreurs | Enquêter et résoudre la cause racine |
Tâches de maintenance hebdomadaires
- Examiner les index :
db.collection.getIndexes()pour les index inutilisés ou redondants. - Vérifier le stockage fragmenté (compactage WiredTiger) :
db.runCommand({ compact: 'collectionName' })(attention : bloque les opérations). - Vérification des sauvegardes : restaurer la dernière sauvegarde sur une instance de test.
- Examiner la sécurité : rôles des utilisateurs, paramètres d'authentification.
Revue mensuelle
- Évaluer les tendances de performance : utiliser des instantanés
mongostatetmongotop. - Planifier la capacité en fonction de la croissance des données.
- Tester les procédures de reprise après sinistre.
Responsable unique désigné
Pour chaque décision majeure dans les opérations (par exemple, activer l'authentification, modifier la préoccupation d'écriture, effectuer la maintenance), désignez un responsable unique. Par exemple :
- Changement d'authentification : Priya Shah, administratrice de base de données. À revoir si l'audit de sécurité l'exige.
- Ajustement de la préoccupation d'écriture : Tom Chen, ingénieur backend principal. Revue trimestrielle.
- Vérification des sauvegardes : Maria Gomez, ingénieure DevOps. Vérification mensuelle.
Cela évite la dilution des responsabilités et garantit que quelqu'un surveille toujours.
Pièges courants et comment les éviter
En travaillant avec MongoDB, les équipes commettent souvent des erreurs qui entraînent des temps d'arrêt ou des pertes de données. Voici les pièges les plus courants et comment les éviter ou s'en remettre.
1. Exécuter sans authentification sur des interfaces publiques
Pourquoi cela arrive : Configuration par défaut ou installation rapide pour le développement, puis déploiement en production sans durcissement.
Impact : La base de données est ouverte à tous, entraînant un vol de données ou un ransomware.
Comment éviter : Activez toujours l'authentification avant d'exposer MongoDB à tout réseau. Utilisez security.authorization: enabled et créez des utilisateurs avec le moindre privilège.
Récupération : Si découvert, activez immédiatement l'authentification et faites pivoter les informations d'identification. Auditez les journaux pour tout accès non autorisé.
2. Ignorer le retard de réplication
Pourquoi cela arrive : Le retard n'est pas surveillé ou les alertes ne sont pas configurées.
Impact : Les lectures secondaires renvoient des données obsolètes, et le basculement peut entraîner une perte de données si le retard est élevé.
Comment éviter : Surveillez le retard en continu avec des outils comme Prometheus + exportateur MongoDB. Définissez des alertes lorsque le retard dépasse le seuil.
Récupération : Enquêtez sur la cause : réseau, modèles d'écriture, charge sur le secondaire. Optimisez ou mettez à l'échelle.
3. Ne pas tester les sauvegardes
Pourquoi cela arrive : On suppose que les sauvegardes fonctionnent parce qu'elles s'exécutent.
Impact : En cas de sinistre, la restauration de la sauvegarde échoue, provoquant une perte de données permanente.
Comment éviter : Restaurez régulièrement les sauvegardes dans un environnement de test et vérifiez l'intégrité des données. Automatisez ce processus.
Récupération : Si la sauvegarde est corrompue, utilisez la récupération ponctuelle à partir de l'oplog si disponible. Sinon, tentez des outils de récupération. La prévention est la clé.
4. Surcharger le primaire avec des opérations de lecture
Pourquoi cela arrive : Les lectures de l'application vont au primaire car la chaîne de connexion n'est pas configurée pour les lectures secondaires.
Impact : Les performances du primaire se dégradent, affectant les écritures et provoquant des défaillances en cascade.
Comment éviter : Utilisez readPreference=secondaryPreferred dans la chaîne de connexion pour répartir les lectures.
Récupération : Modifiez la chaîne de connexion et redéployez l'application. Surveillez le CPU du primaire et les connexions.
5. Mal configurer la préoccupation d'écriture
Pourquoi cela arrive : La préoccupation d'écriture par défaut peut être w:1, et les développeurs pensent que les données sont écrites en toute sécurité alors qu'elles ne le sont pas.
Impact : Perte de données si le primaire tombe en panne avant la réplication.
Comment éviter : Utilisez w: "majority" pour les écritures critiques. Testez les scénarios de basculement.
Récupération : En cas de perte de données, restaurez à partir de la sauvegarde ou de l'oplog si possible.
6. Ne pas mettre à niveau de manière contrôlée
Pourquoi cela arrive : Mise à niveau sans tester la compatibilité ni lire les notes de version.
Impact : Incompatibilité des pilotes, fonctionnalités obsolètes, changements de comportement inattendus.
Comment éviter : Testez les mises à niveau dans un environnement de test avec les mêmes données et charge de travail. Suivez le chemin de mise à niveau de MongoDB (on ne peut pas sauter de versions majeures).
Récupération : Revenez à la version précédente si possible, et corrigez les problèmes avant de réessayer.
Conclusion
Les opérations avancées de MongoDB exigent une approche systématique : connaître sa version et sa topologie, modifier la configuration avec précaution, vérifier avec des diagnostics, se préparer aux défaillances et suivre une liste de contrôle opérationnelle quotidienne. Chaque recommandation de ce guide est spécifique à la version et observable, avec des chemins de récupération explicites.
Comme prochaine étape, commencez par une vérification à faible risque : exécutez db.version(), rs.status() et db.serverStatus() pour établir une base de référence. Documentez l'état actuel, puis mettez en place une surveillance du retard de réplication et des requêtes lentes. Attribuez un responsable unique pour chaque domaine opérationnel majeur.
Rappelez-vous : un flux de travail fiable rend les défaillances visibles, protège les valeurs sensibles, limite les modifications à la ressource prévue et définit la vérification de la récupération avant qu'un incident ne force la décision. En appliquant ces concepts avancés, vous pouvez exploiter MongoDB en toute confiance.