Introduction
Les équipes applicatives modernes s’appuient sur l’intégration continue et le déploiement continu (CI/CD) pour livrer des fonctionnalités rapidement et de manière fiable. Si le code applicatif retient souvent l’attention, la couche base de données est tout aussi critique. MongoDB, en tant que base de données documentaire populaire, peut être intégré aux pipelines CI/CD pour automatiser les mises à jour de schéma, les migrations de données et les changements de configuration. Cet article fournit un guide pratique pour automatiser les workflows MongoDB avec CI/CD, en couvrant les contrôles de déploiement sûrs, la validation, les stratégies de restauration et les échecs courants de pipeline. Nous passerons en revue des exemples concrets utilisant le shell MongoDB, les outils en ligne de commande et les scripts de pipeline. À la fin, vous disposerez d’une approche reproductible pour faire évoluer en toute sécurité vos schémas et données MongoDB dans le cadre de votre processus de livraison.
Inventaire des versions et de l’environnement
Avant d’automatiser toute opération MongoDB, établissez un inventaire clair des versions et des prérequis de l’environnement. Des environnements incohérents sont une cause majeure d’échecs de pipeline.
Version du serveur MongoDB : Connaissez la version majeure et mineure exacte. Certaines fonctionnalités, comme les transactions ou certains stades d’agrégation, ne sont disponibles que dans des versions spécifiques. Utilisez mongosh --version ou connectez-vous et exécutez db.version(). Exemple :
mongosh --version
# Sortie : 2.1.1
Outils MongoDB : Le shell mongosh et les outils de base de données (comme mongodump, mongorestore, mongoexport, mongoimport) doivent correspondre à la version du serveur si possible. Vérifiez avec des commandes comme mongodump --version.
Versions du pilote et de l’ORM : Si votre application utilise un ODM comme Mongoose, assurez-vous de la compatibilité avec la version du serveur MongoDB. Consultez les notes de version du pilote pour les versions de serveur prises en charge. Par exemple, Mongoose 7.x prend en charge le serveur MongoDB 4.4 et ultérieur.
Topologie : Déterminez si vous utilisez une instance autonome, un ensemble de réplicas ou un cluster fragmenté. De nombreuses opérations CI/CD, comme les changements de schéma, se comportent différemment selon la topologie. Pour la production, un ensemble de réplicas est le minimum recommandé pour la haute disponibilité. Un cluster fragmenté ajoute de la complexité : certaines opérations (comme $lookup entre fragments) peuvent être restreintes.
Authentification et rôles : Les scripts d’automatisation ont besoin d’utilisateurs de base de données appropriés. Créez un utilisateur CI/CD dédié avec des rôles à moindre privilège. Par exemple :
// Exécuter dans mongosh en tant qu’admin
use admin;
db.createUser({
user: "cicd_user",
pwd: "secure_password",
roles: [
{ role: "readWrite", db: "appdb" },
{ role: "dbAdmin", db: "appdb" }
]
});
// Sortie attendue : { ok: 1 }
Accès réseau : Les exécuteurs CI/CD doivent pouvoir atteindre l’instance MongoDB. Pour MongoDB hébergé dans le cloud (par exemple, Atlas), ajoutez les adresses IP des exécuteurs à la liste blanche ou utilisez le peering VPC. Si l’adresse IP de votre exécuteur change fréquemment (par exemple, les exécuteurs hébergés par GitHub), envisagez d’utiliser un exécuteur auto-hébergé avec une adresse IP statique ou une liste d’accès IP Atlas avec une plage CIDR couvrant votre parc d’exécuteurs.
Outils prérequis sur l’exécuteur : Assurez-vous que mongosh, mongodump, mongorestore et tout autre outil nécessaire sont installés. Pour un exécuteur basé sur Debian, vous pouvez les installer avec :
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -
echo "deb [ arch=amd64, arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
sudo apt-get update
sudo apt-get install -y mongodb-mongosh mongodb-database-tools
# Sortie attendue : paquets installés sans erreurs.
Séparation des environnements : Maintenez des bases de données séparées pour le développement, la préproduction et la production. Le pipeline CI/CD doit cibler d’abord la préproduction, puis la production avec une approbation explicite.
Chemin de configuration sûr
Lorsque vous ajoutez l’automatisation MongoDB à votre pipeline, adoptez un projet pilote étroit et mesurable plutôt qu’un changement global. Commencez par une seule collection ou un seul type de changement facile à inspecter et à annuler.
Approche pilote
Par exemple, automatisez l’ajout d’un nouvel index sur une collection non critique. Cette opération est réversible (suppression de l’index) et a un impact sur les performances observable. Choisissez une collection avec un trafic d’écriture modéré pour observer l’impact de la construction de l’index sans risquer la fonctionnalité de base. Commencez par une collection contenant moins de 100 000 documents pour que la construction de l’index soit rapide.
Gestion de la configuration
Stockez les chaînes de connexion et les identifiants MongoDB en toute sécurité dans le gestionnaire de secrets de votre système CI/CD, pas dans le dépôt. Utilisez des variables d’environnement dans vos scripts. Par exemple, dans GitLab CI :
variables:
MONGODB_URI: $MONGODB_URI_STAGING # stocké comme variable masquée
Ne codez jamais en dur les mots de passe dans les scripts. Si vous utilisez un fichier .env local pour le développement, assurez-vous qu’il est dans .gitignore.
Scripts de migration
Utilisez des scripts de migration versionnés, similaires aux migrations de base de données d’application. Chaque script doit être idempotent si possible, ou au moins suivre l’état appliqué. Une approche simple consiste à utiliser une collection migrations dans MongoDB pour enregistrer les migrations appliquées.
Exemple de script de migration (JavaScript pour mongosh) :
// migration_001_add_user_email_index.js
const dbName = 'appdb';
const collectionName = 'users';
const db = db.getSiblingDB(dbName);
// Vérifier si la migration a déjà été appliquée
const migrationRecord = db.migrations.findOne({ _id: '001_add_user_email_index' });
if (migrationRecord) {
print('Migration déjà appliquée. Ignorée.');
quit(0);
}
// Créer l’index
db.getCollection(collectionName).createIndex({ email: 1 }, { unique: true });
// Enregistrer la migration
db.migrations.insertOne({
_id: '001_add_user_email_index',
appliedAt: new Date(),
description: 'Ajouter un index unique sur email'
});
print('Migration 001 appliquée avec succès.');
Exécutez avec :
mongosh "mongodb://cicd_user:password@host:27017/appdb" --file migration_001_add_user_email_index.js
# Sortie attendue : Migration 001 appliquée avec succès.
Étapes du pipeline
Dans votre pipeline CI/CD, définissez des étapes telles que :
- Lint/Validation des scripts : Utilisez un linter ou un mode dry-run si disponible. Pour JavaScript, vous pouvez exécuter
node --checkpour détecter les erreurs de syntaxe. - Appliquer les migrations à la préproduction : Exécutez les scripts de migration sur la base de données de préproduction.
- Exécuter les tests d’intégration : Exécutez la suite de tests de l’application sur la base de données de préproduction mise à jour.
- Approbation manuelle : Exigez une approbation humaine avant la migration en production.
- Appliquer les migrations à la production : Exécutez les mêmes scripts sur la production.
- Tests de fumée : Vérifiez la santé de la production après la migration.
Un pipeline GitLab CI simplifié pour la préproduction :
étapes:
- validate
- migrate_staging
- test
validate_scripts:
étape: validate
script:
- find . -name 'migration_*.js' -exec node --check {} \;
migrate_staging:
étape: migrate_staging
script:
- mongosh "$MONGODB_URI_STAGING" --file migration_001_add_user_email_index.js
environnement:
nom: staging
test:
étape: test
script:
- npm test
Changements ciblés
Pour les changements de schéma comme l’ajout d’un champ, utilisez l’opérateur $set dans une mise à jour avec un filtre pour éviter d’écraser des documents. Incluez toujours une option multi: true si vous mettez à jour plusieurs documents. Exemple :
// Ajouter un champ 'status' aux utilisateurs actifs uniquement
db.users.updateMany(
{ status: { $exists: false }, isActive: true },
{ $set: { status: "active" } }
);
// Sortie attendue : { "acknowledged" : true, "matchedCount" : 123, "modifiedCount" : 123 }
Vérification et diagnostics
Après avoir exécuté l’automatisation MongoDB, vérifiez que les changements ont été appliqués correctement et diagnostiquez tout problème.
Vérifier l’état de la migration
Interrogez la collection migrations pour confirmer que la migration a été enregistrée.
// Dans mongosh
db.getSiblingDB('appdb').migrations.find().pretty();
// Sortie attendue : un document avec _id correspondant à l’ID de migration et un horodatage appliedAt.
Vérifier la création de l’index
Utilisez getIndexes() pour confirmer que l’index existe avec les bonnes options.
db.getSiblingDB('appdb').users.getIndexes();
// Sortie attendue : un tableau incluant le nouvel index, par exemple, { "v" : 2, "key" : { "email" : 1 }, "name" : "email_1", "unique" : true }.
Exécuter des tests de fumée de l’application
Exécutez un ensemble minimal de requêtes qui exercent le schéma ou les index modifiés. Par exemple, si vous avez ajouté un index unique sur email, tentez d’insérer un doublon et attendez-vous à une erreur.
// Dans mongosh
try {
db.users.insertOne({ email: "[email protected]", name: "Duplicate Test" });
print("Insertion en double a réussi de manière inattendue !");
} catch (e) {
print("Insertion en double correctement rejetée : " + e.message);
}
Diagnostics pour les problèmes courants
- Échecs de connexion : Vérifiez le réseau, le pare-feu et les identifiants. Utilisez
mongoshavec une journalisation verbeuse si nécessaire, par exemple,mongosh --verbose --host .... Testez la connectivité avecnc -zv hôte 27017. - Erreurs d’authentification : Vérifiez le rôle de l’utilisateur et la base de données. Rappelez-vous que MongoDB s’authentifie par rapport à la base de données
adminpour certains rôles. Assurez-vous que la chaîne de connexion inclut le bonauthSource. - Échecs de construction d’index : Vérifiez s’il existe des clés en double si l’index est unique. Utilisez
db.collection.find({ email: { $exists: true } }).limit(10)pour inspecter les données. Pour un index unique, les doublons provoquent une erreurDuplicateKey. - Contention de verrous : Pendant les opérations longues, surveillez
db.currentOp()etdb.serverStatus().locks. UntimeAcquiringMicrosélevé dansserverStatusindique une contention.
Surveillance pendant le déploiement
Utilisez les outils intégrés de MongoDB comme mongotop et mongostat pour observer les performances pendant la migration. Par exemple :
mongostat --host hôte:27017 -u cicd_user -p mot_de_passe --authenticationDatabase admin 5
# Sortie attendue : lignes avec des métriques comme insert, query, update, delete et le pourcentage verrouillé.
Modes d’échec et récupération
Malgré une planification minutieuse, des échecs peuvent survenir. Préparez-vous avec des stratégies de restauration et des contrôles de récupération.
Modes d’échec courants
- Erreurs de script : Le script de migration échoue en raison d’une erreur de syntaxe ou d’une condition inattendue.
- Application partielle : Certaines modifications ont été appliquées avant l’échec, laissant la base de données dans un état incohérent. Par exemple, une construction d’index peut être interrompue, laissant un index incomplet.
- Incompatibilité des données : De nouvelles hypothèses de schéma cassent le code applicatif existant. Par exemple, rendre obligatoire un champ manquant dans certains documents.
- Dégradation des performances : De nouveaux index ou transformations de données provoquent des requêtes lentes ou des contentions de verrous.
- Interruptions réseau : Le pipeline perd la connectivité en cours d’opération, provoquant des délais d’attente.
Stratégies de restauration
Pour les changements additifs (par exemple, index ou collection ajoutés) : La restauration est simple : supprimez l’index ou la collection.
db.users.dropIndex("email_1"); // supprime l’index
// ou db.getCollection('new_collection').drop();
Pour les migrations de données (par exemple, champ ajouté) : Vous pouvez le supprimer en utilisant $unset dans une mise à jour. Mais soyez prudent : si le nouveau code dépend du champ, le supprimer peut casser l’application. Coordonnez avec la restauration de l’application.
db.users.updateMany(
{ newField: { $exists: true } },
{ $unset: { newField: "" } }
);
Pour les changements cassants (par exemple, type de champ modifié ou champ supprimé) : Vous devrez peut-être restaurer à partir d’une sauvegarde. Effectuez une sauvegarde avant la migration en utilisant mongodump :
mongodump --host hôte:27017 --username cicd_user --password mot_de_passe --authenticationDatabase admin --db appdb --out /backups/appdb_$(date +%F)
# Sortie attendue : dump de appdb terminé
Étapes de récupération
- Arrêtez le pipeline et empêchez d’autres modifications.
- Évaluez l’état : interrogez la collection
migrationset inspectez les collections affectées. - Si possible, exécutez un script compensatoire pour annuler le changement. Par exemple :
// rollback_001_remove_email_index.js
const db = db.getSiblingDB('appdb');
db.users.dropIndex('email_1');
db.migrations.deleteOne({ _id: '001_add_user_email_index' });
print('Restauration terminée.');
- Si le changement ne peut pas être inversé en toute sécurité, restaurez à partir de la sauvegarde en utilisant
mongorestore:
mongorestore --host hôte:27017 --username cicd_user --password mot_de_passe --authenticationDatabase admin --db appdb /backups/appdb_AAAA-MM-JJ/appdb
# Sortie attendue : documents et index restaurés
- Relancez les tests de l’application pour confirmer la santé du système.
Mesures préventives
- Exécutez toujours les migrations dans un environnement de préproduction qui reflète la production.
- Utilisez des déploiements bleu-vert lorsque c’est possible. Par exemple, déployez la nouvelle version de l’application dans un environnement séparé qui utilise le nouveau schéma, puis basculez le trafic après vérification.
- Mettez en œuvre la gestion des changements de base de données avec des scripts versionnés.
- Incluez des reprises automatiques pour les erreurs réseau transitoires, mais soyez prudent avec les opérations non idempotentes. Enveloppez les opérations dans une boucle de reprise qui vérifie les codes d’erreur spécifiques.
Pièges courants et comment les éviter
Même les équipes expérimentées tombent dans des pièges lors de l’automatisation des changements MongoDB. Voici les pièges les plus courants et comment les éviter.
Piège 1 : Exécuter des changements de schéma sans sauvegarde
Pourquoi cela arrive : Les équipes supposent qu’un changement est sûr et sautent l’étape de sauvegarde pour gagner du temps.
Comment l’éviter : Effectuez toujours une sauvegarde avant toute migration, même si vous pensez que le changement est réversible. Automatisez la sauvegarde dans le pipeline avant l’étape de migration. Si une restauration est nécessaire, la sauvegarde est votre filet de sécurité.
Piège 2 : Ignorer l’impact de la construction d’index sur la production
Pourquoi cela arrive : Les développeurs testent les constructions d’index sur de petits ensembles de données et supposent que la production sera similaire.
Comment l’éviter : Pour les grandes collections, utilisez des constructions d’index en continu (disponibles dans MongoDB 4.2+ pour les ensembles de réplicas) ou créez des index pendant les fenêtres de faible trafic. Surveillez db.currentOp() pendant la construction. Envisagez d’utiliser l’option background: true (obsolète dans 4.2+ mais fonctionne toujours) si vous ne pouvez pas utiliser les constructions en continu.
Piège 3 : Coder en dur les identifiants dans les scripts de pipeline
Pourquoi cela arrive : Commodité pendant le développement ou méconnaissance de la gestion des secrets.
Comment l’éviter : Utilisez les variables secrètes de votre système CI/CD. Ne stockez jamais d’identifiants dans le dépôt. Pour les tests locaux, utilisez des variables d’environnement ou un fichier .env dans .gitignore.
Piège 4 : Ne pas gérer les échecs de migration partielle
Pourquoi cela arrive : Un script échoue à mi-chemin, laissant certains documents mis à jour et d’autres non, et il n’y a aucun enregistrement de ce qui a réussi.
Comment l’éviter : Rendez les scripts de migration idempotents. Utilisez la collection migrations pour suivre les étapes appliquées. Si un script n’est pas idempotent, divisez-le en étapes plus petites ou utilisez une transaction (si prise en charge) pour garantir l’atomicité.
Piège 5 : Négliger la compatibilité applicative lors des changements de schéma
Pourquoi cela arrive : Le schéma de la base de données est modifié sans coordination avec les changements de code applicatif.
Comment l’éviter : Utilisez le motif d’expansion et de contraction. D’abord, ajoutez de nouveaux champs (expansion), déployez un code applicatif qui peut gérer à la fois l’ancien et le nouveau schéma, puis supprimez les anciens champs (contraction) une fois que l’ancien code est retiré. Cela nécessite un versionnage minutieux des versions de l’application.
Piège 6 : Ne pas surveiller après la migration
Pourquoi cela arrive : Les équipes supposent que si la migration réussit, tout va bien, et passent à autre chose.
Comment l’éviter : Configurez des alertes de surveillance pour les métriques clés comme la latence des requêtes, les taux d’erreur et l’utilisation des ressources. Utilisez des outils comme les alertes MongoDB Atlas, Prometheus avec l’exportateur MongoDB ou New Relic. Examinez les performances après chaque migration.
Liste de contrôle des opérations
Utilisez cette liste de contrôle pour garantir des opérations CI/CD MongoDB reproductibles et sûres. Attribuez un responsable unique pour chaque étape afin d’assurer la responsabilité.
| Étape | Action | Responsable | Vérification | Fréquence |
|---|---|---|---|---|
| 1 | Inventorier les versions et la topologie | Ingénieur DevOps | mongosh --version, mongodump --version | Lors de chaque configuration du pipeline ou trimestriellement |
| 2 | Créer un utilisateur CI/CD dédié avec le moindre privilège | Administrateur de base de données | db.getUser("cicd_user") renvoie un document | Une fois, puis revu annuellement |
| 3 | Installer les outils requis sur l’exécuteur | Ingénieur DevOps | which mongosh et which mongodump | Lors de chaque provisionnement de l’exécuteur |
| 4 | Stocker les secrets en toute sécurité | Ingénieur en sécurité | Accès depuis les variables d’environnement du pipeline | Lors de chaque rotation des secrets |
| 5 | Écrire un script de migration idempotent et l’enregistrer dans la collection migrations | Développeur backend | Essai à sec sur la préproduction | Par migration |
| 6 | Exécuter la migration sur la préproduction | Responsable des versions | Vérifier la collection migrations et les index | Par version |
| 7 | Exécuter les tests d’intégration de l’application | Ingénieur QA | La suite de tests passe | Par version |
| 8 | Exiger une approbation manuelle pour la production | Responsable des versions | Porte d’approbation appliquée | Par déploiement en production |
| 9 | Sauvegarder la base de données de production | Administrateur de base de données | Le fichier de sauvegarde existe et sa taille > 0 | Avant chaque migration en production |
| 10 | Appliquer la migration à la production | Responsable des versions | L’enregistrement de migration apparaît en production | Par déploiement en production |
| 11 | Exécuter des tests de fumée | Ingénieur QA | Les requêtes réussissent, erreur de clé en double si attendue | Immédiatement après la migration |
| 12 | Surveiller les performances | SRE/DevOps | Pas de verrous excessifs ni de requêtes lentes | Pendant 24 à 48 heures après la migration |
| 13 | Documenter les problèmes et les résolutions | Responsable des versions | Mettre à jour le runbook | Après chaque migration |
Conclusion
L’automatisation des workflows MongoDB dans les pipelines CI/CD exige une planification minutieuse, un contrôle de version et une approche disciplinée des changements. En commençant par un projet pilote étroit, en utilisant des scripts de migration versionnés et en mettant en œuvre des procédures de vérification et de restauration robustes, vous pouvez intégrer en toute sécurité les changements de base de données dans votre processus de livraison. Les exemples pratiques fournis ici — utilisant des scripts mongosh, des outils en ligne de commande et des étapes de pipeline — vous donnent une base sur laquelle construire. N’oubliez pas de toujours tester en préproduction, d’exiger une approbation manuelle pour la production et de maintenir des sauvegardes. Avec ces pratiques, vous pouvez réaliser des déploiements MongoDB fiables et reproductibles.
Prochaines étapes
- Identifiez un changement de base de données à faible risque à automatiser en premier, comme l’ajout d’un index non unique sur une collection avec un faible trafic d’écriture.
- Créez un utilisateur CI/CD dédié et installez les outils sur votre exécuteur.
- Écrivez et testez un script de migration localement avant de l’intégrer au pipeline. Utilisez le script d’exemple comme modèle et adaptez-le à votre changement.
- Configurez la surveillance de vos instances MongoDB pour détecter tôt les problèmes de performance. Utilisez
mongostatou un outil de surveillance dédié. - Documentez votre propre liste de contrôle des opérations en fonction de votre environnement et de votre topologie, en attribuant des responsables et des fréquences de révision comme indiqué ci-dessus.