Mettre en place un cluster MongoDB Replica Set à 3 nœuds avec Docker Compose
17 juillet 2024 · 8 min read · Read in English
Sommaire
Introduction
Dans cet article, je te guide à travers la mise en place d'un cluster MongoDB replica set à 3 nœuds avec Docker Compose. Ce guide suppose que tu es familier avec les concepts Docker de base — Docker Compose, volumes, réseaux, healthchecks — ainsi qu'avec les concepts MongoDB comme les replica sets. Si tu es prêt, on plonge dedans !
C'est quoi un replica set MongoDB ?
Un replica set MongoDB est un groupe d'instances MongoDB qui hébergent le même jeu de données. Dans un replica set, un nœud est le nœud primary qui reçoit toutes les opérations d'écriture. Tous les autres nœuds, appelés secondary, appliquent les opérations du primary pour avoir le même jeu de données.
Les replica sets MongoDB offrent redondance et haute disponibilité, en gardant la base opérationnelle même si un ou plusieurs nœuds tombent. Ils répliquent les données sur plusieurs nœuds pour garantir intégrité et disponibilité.
Pourquoi utiliser un replica set MongoDB ?
1- Haute disponibilité : si le nœud primary tombe, un secondary peut être élu comme nouveau primary, ce qui garantit que la base reste disponible.
2- Redondance des données : les données sont répliquées sur plusieurs nœuds, garantissant leur intégrité et leur disponibilité.
3- Scalabilité en lecture : les nœuds secondary peuvent servir les opérations de lecture, distribuant la charge de lecture sur plusieurs nœuds.
4- Failover automatique : si le nœud primary tombe, un secondary est automatiquement élu comme nouveau primary.
Pour aller plus loin sur la réplication MongoDB, consulte la doc officielle sur les replica sets.
Mettre en place un cluster MongoDB Replica Set à 3 nœuds avec Docker Compose
Prérequis
Dans ce guide, on utilise Docker Compose pour mettre en place un cluster MongoDB replica set à 3 nœuds. Avant de commencer, assure-toi d'avoir Docker et Docker Compose installés sur ta machine. Si ce n'est pas le cas, télécharge-les depuis le site officiel Docker.
Tu auras peut-être aussi besoin d'une compréhension de base de MongoDB et des commandes mongo shell. Si tu débutes avec MongoDB, consulte la doc officielle sur les opérations CRUD MongoDB.
Étape 1 : créer un fichier Docker Compose
Commence par créer un fichier docker-compose.yml dans un nouveau dossier. Ce fichier
définira les services pour les conteneurs MongoDB. On va créer :
- trois services :
mongo1,mongo2etmongo3 - un réseau appelé
mongo-cluster - trois volumes :
mongo1-data,mongo2-dataetmongo3-data
C'est parti :
networks:
mongo-cluster:
driver: bridge
volumes:
mongo1_data:
mongo1_config:
mongo2_data:
mongo2_config:
mongo3_data:
mongo3_config:
services:
mongo1:
container_name: mongo1
image: 'mongo:8.2-noble'
hostname: mongo1
command: ["--config", "/etc/mongod.conf"]
volumes:
- mongo1_data:/data/db
- mongo1_config:/data/configdb
- '$PWD/scripts/mongo/rs_keyfile:/etc/mongodb/keyfile:ro'
- '$PWD/scripts/mongo/mongod.conf:/etc/mongod.conf:ro'
networks:
- mongo-cluster
environment:
MONGO_INITDB_ROOT_USERNAME: '${MONGO_ADMIN_USER:-admin}'
MONGO_INITDB_ROOT_PASSWORD: '${MONGO_ADMIN_PASSWD:-veryStringPassword}'
MONGO_INITDB_DATABASE: '${DB_NAME:-test}'
healthcheck:
test: ["CMD", "mongosh", "--quiet", "--eval", "try { rs.status().ok } catch(e) { rs.initiate().ok }"]
timeout: 5m
interval: 10s
retries: 5
start_period: 12s
mongo2:
container_name: mongo2
image: 'mongo:8.2-noble'
hostname: mongo2
volumes:
- mongo2_data:/data/db
- mongo2_config:/data/configdb
- '$PWD/scripts/mongo/rs_keyfile:/etc/mongodb/keyfile:ro'
- '$PWD/scripts/mongo/mongod.conf:/etc/mongod.conf:ro'
networks:
- mongo-cluster
environment:
MONGO_INITDB_ROOT_USERNAME: '${MONGO_ADMIN_USER:-admin}'
MONGO_INITDB_ROOT_PASSWORD: '${MONGO_ADMIN_PASSWD:-veryStringPassword}'
mongo3:
container_name: mongo3
image: 'mongo:8.2-noble'
hostname: mongo3
volumes:
- mongo3_data:/data/db
- mongo3_config:/data/configdb
- '$PWD/scripts/mongo/rs_keyfile:/etc/mongodb/keyfile:ro'
- '$PWD/scripts/mongo/mongod.conf:/etc/mongod.conf:ro'
networks:
- mongo-cluster
environment:
MONGO_INITDB_ROOT_USERNAME: '${MONGO_ADMIN_USER:-admin}'
MONGO_INITDB_ROOT_PASSWORD: '${MONGO_ADMIN_PASSWD:-veryStringPassword}'
mongo-init:
container_name: mongo-init
image: docker.io/mongo:8.2-noble
restart: no
entrypoint: ["/bin/bash", "/init.sh"]
networks:
- mongo-cluster
depends_on:
- mongo1
- mongo2
- mongo3
volumes:
- $PWD/scripts/mongo/init.js:/init.js
- $PWD/scripts/mongo/init.sh:/init.sh
environment:
MONGO_ROOT_USERNAME: '${MONGO_ADMIN_USER:-admin}'
MONGO_ROOT_PASSWORD: '${MONGO_ADMIN_PASSWD:-veryStringPassword}'
DB_USERNAME: '${DB_USERNAME:-myuser}'
DB_PASSWORD: '${DB_PASSWORD:-mypassword}'
Décortiquons le fichier docker-compose.yml :
- On définit un réseau
mongo-clusterqui sera utilisé par tous les conteneurs MongoDB. Cela garantit que les conteneurs peuvent communiquer entre eux via les hostnamesmongo1,mongo2etmongo3. - On définit trois volumes :
mongo1_data,mongo2_dataetmongo3_datapour persister les données de chaque conteneur MongoDB. - On définit trois services :
mongo1,mongo2etmongo3. Chaque service lance un conteneur MongoDB avec l'imagemongo:8.2-noble. On spécifie l'option--replSetpour définir le nom du replica set àrs0. On spécifie également l'option--bind_ippour lier le conteneur aux hostnamesmongo1,mongo2etmongo3. On monte les volumes pour persister les données et le keyfile pour l'authentification. On expose les ports27017,27018et27019pour les conteneurs MongoDB. On définit un healthcheck pour le servicemongo1pour vérifier le statut du replica set et l'initialiser s'il ne l'est pas encore. Après réussite du healthcheck, le replica set est initialisé avec le nœud primarymongo1et les secondarymongo2etmongo3. - On définit les variables d'environnement
MONGO_INITDB_ROOT_USERNAME,MONGO_INITDB_ROOT_PASSWORD,MONGO_INITDB_DATABASE,DB_USERNAMEetDB_PASSWORDpour chaque service pour configurer l'authentification MongoDB. On utilise l'interpolation pour garantir l'usage des valeurs par défaut si les variables d'environnement ne sont pas définies.
Étape 2 : créer un keyfile pour l'authentification
MongoDB utilise des keyfiles pour l'authentification interne entre les membres du replica set. Dans certains scénarios où aucun credentials n'est défini, on n'en a pas besoin. Mais pour les besoins de ce guide, il faut créer un keyfile et le monter dans les conteneurs MongoDB, puisqu'on utilise l'authentification.
Pour créer un keyfile, lance la commande suivante :
openssl rand -base64 756 > scripts/mongo/rs_keyfile && chmod 400 scripts/mongo/rs_keyfile
Cette commande génère une clé aléatoire de 756 octets et la sauvegarde dans le fichier
scripts/mongo/rs_keyfile. On définit ensuite les permissions du fichier à 400 pour
s'assurer que seul le propriétaire mongodb:mongodb peut lire et écrire le fichier. Tu peux
en apprendre plus sur les keyfiles dans la
doc MongoDB.
Note : le keyfile sert à l'authentification interne entre les membres du replica set. Il est important de garder le keyfile sécurisé et de ne pas l'exposer à des utilisateurs non autorisés.
Étape 3 : scripts d'initialisation
Initialisation MongoDB
Comme mentionné plus tôt, on va configurer une base de données initiale, un nom d'utilisateur
et un mot de passe pour le replica set MongoDB. Pour ce faire, on utilise un script
d'initialisation qui sera exécuté au démarrage du conteneur MongoDB. Crée maintenant un
fichier init.js dans le dossier scripts/mongo avec le contenu suivant :
db = db.getSiblingDB('admin');
try {
var rsConf = {
_id: 'okydookReplSet',
members: [
{ _id: 0, host: 'mongo1:27017', priority: 2 },
{ _id: 1, host: 'mongo2:27017' },
{ _id: 2, host: 'mongo3:27017' }
]
};
// Check if replica set is already initialized
var isInitialized = false;
try {
var status = rs.status();
if (status.ok === 1) {
isInitialized = true;
print("ReplicaSet already initiated");
}
} catch(e) {
// rs.status() throws error if not initialized yet
print("ReplicaSet not yet initiated, proceeding with initiation...");
}
if (!isInitialized) {
rs.initiate(rsConf);
print("ReplicaSet initiated successfully");
// Wait for replica set to be ready
sleep(20000);
}
} catch(e) {
print("Failed to initiate replica set: " + e.message);
throw e;
}
Décortiquons le fichier init.js :
- On se connecte à la base spécifiée par la variable
MONGO_INITDB_DATABASE. - On crée un utilisateur spécifié par les variables
DB_USERNAMEetDB_PASSWORDavec le rôlereadWritesur la base. - On définit le write concern à
majorityavec un timeout de5000millisecondes. Cela garantit que l'opération d'écriture est acquittée par la majorité des membres du replica set.
Ce script s'exécute au démarrage du conteneur MongoDB, créant la base et l'utilisateur initiaux pour le replica set. Note que la partie scriptée n'est pas obligatoire et que tu pourrais utiliser des valeurs en dur. Cependant, selon la section III du 12-factor app, il vaut mieux utiliser les variables d'environnement pour stocker les secrets ou tout ce qui peut varier entre les déploiements.
Process de connexion au replicaset
#!/bin/bash
echo "Waiting for MongoDB to be ready..."
sleep 15
# Test connection
until mongosh --host mongo1:27017 -u "${MONGO_ROOT_USERNAME}" -p "${MONGO_ROOT_PASSWORD}" --authenticationDatabase admin --eval "db.adminCommand('ping')" > /dev/null 2>&1; do
echo "Waiting for MongoDB connection..."
sleep 5
done
echo "MongoDB is ready, initializing replica set..."
mongosh --host mongo1:27017 \
-u "${MONGO_ROOT_USERNAME}" \
-p "${MONGO_ROOT_PASSWORD}" \
--authenticationDatabase admin \
--eval "
var MONGO_DB_USER='${MONGO_DB_USER}';
var MONGO_DB_PASSWORD='${MONGO_DB_PASSWORD}';
" \
--file /init.js
if [ $? -eq 0 ]; then
echo "Initialization completed successfully"
else
echo "Initialization failed"
exit 1
fi
Étape 4 : démarrer le cluster MongoDB Replica Set
Maintenant que tout est en place, on peut démarrer le cluster MongoDB replica set avec Docker Compose en exécutant la commande suivante :
docker-compose up -d
Note : le flag
-dlance les conteneurs en mode détaché, ce qui signifie qu'ils tournent en arrière-plan.
Étape 5 : vérifier le replica set MongoDB
Pour vérifier que le replica set MongoDB tourne correctement, tu peux utiliser le shell
mongo pour te connecter au nœud primary et vérifier le statut du replica set. Lance la
commande suivante pour te connecter au primary :
docker exec -it mongo_rs0 mongosh -u admin -p veryStringPassword --authenticationDatabase admin
Note : remplace
veryStringPasswordpar le mot de passe que tu as défini pour la variableMONGO_INITDB_ROOT_PASSWORD. Si tu n'en as pas défini, utiliseveryStringPassword.
Une fois connecté, lance la commande suivante pour vérifier le statut du replica set :
rs.status()
Tu devrais voir le statut du replica set avec le nœud primary mongo1 et les secondary
mongo2 et mongo3. La sortie devrait ressembler à :
members: [
{
_id: 0,
name: 'mongo1:27017',
health: 1,
state: 1,
stateStr: 'PRIMARY',
uptime: 478,
electionTime: Timestamp({ t: 1721354075, i: 1 }),
electionDate: ISODate('2024-07-19T01:54:35.000Z'),
...
},
{
_id: 1,
name: 'mongo2:27018',
health: 1,
state: 2,
stateStr: 'SECONDARY',
uptime: 471,
syncSourceHost: 'mongo1:27017',
...
},
{
_id: 2,
name: 'mongo3:27019',
health: 1,
state: 2,
stateStr: 'SECONDARY',
uptime: 471,
syncSourceHost: 'mongo1:27017',
...
}
],
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1721354536, i: 1 }),
signature: {
hash: Binary.createFromBase64('8KKPt/SmHkhGZDH299+yq6j5i04=', 0),
keyId: Long('7393159456961331205')
}
},
Note : c'est une sortie tronquée, et elle peut varier selon la version de MongoDB utilisée.
Bonus : ajouter Mongo-Express pour une administration web
Ajoutons un outil d'administration web pour MongoDB en utilisant mongo-express. Pour ajouter
mongo-express au fichier Docker Compose, ajoute la définition de service suivante :
mongo-express:
container_name: mongo-express
image: 'mongo-express:latest'
ports:
- '8081:8081'
networks:
- mongo-cluster
environment:
ME_CONFIG_BASICAUTH: false
ME_CONFIG_MONGODB_ENABLE_ADMIN: false
ME_CONFIG_MONGODB_ADMINUSERNAME: '${MONGO_ADMIN_USER:-admin}'
ME_CONFIG_MONGODB_ADMINPASSWORD: '${MONGO_ADMIN_PASSWD:-veryStrongPassword}'
ME_CONFIG_MONGODB_URL: >-
mongodb://${DB_USERNAME:-myuser}:${DB_PASSWORD:-veryStringPassword}@mongo1:27017,mongo2:27018,mongo3:27019/${DB_NAME}?replicaSet=rs0
depends_on:
mongo1:
condition: service_healthy
Note : le service
mongo-expressdépend du servicemongo1healthy. Cela garantit que le replica set est en marche avant de démarrer le servicemongo-express.
Tu peux accéder à mongo-express à http://localhost:8081 dans ton navigateur, et avoir
quelque chose comme :
Note : pour connecter ton application au replica set MongoDB, tu peux utiliser la chaîne de connexion
mongodb://${DB_USERNAME}:${DB_PASSWORD}@mongo1:27017,mongo2:27018,mongo3:27019/${DB_NAME}?replicaSet=rs0. Pense aussi à remplacerDB_USERNAME,DB_PASSWORDetDB_NAMEpar les credentials de ton application en définissant les variables d'environnement dans le fichier.env.
Si tout est bien configuré, tu devrais avoir quelque chose comme ceci dans ton Docker Desktop :
Et voilà, tu as un cluster MongoDB replica set avec un outil d'administration web !
Conclusion
Dans cet article, je t'ai guidé à travers la mise en place d'un cluster MongoDB replica set à
3 nœuds avec Docker Compose. On a couvert les bases des replica sets MongoDB, les prérequis
pour mettre en place un replica set, et les étapes pour créer un fichier Docker Compose qui le
configure. Je t'ai aussi montré comment vérifier le replica set et ajouter un outil
d'administration web avec mongo-express. J'espère que ce guide t'aidera à démarrer avec les
replica sets MongoDB et Docker Compose.
Dans un futur article, je parlerai de quelque chose de plus important : comment sauvegarder et restaurer une base MongoDB dans un environnement conteneurisé. Tu as peut-être entendu que les conteneurs Docker sont éphémères, donc il est important d'avoir une stratégie de backup en place pour éviter la perte de données. Reste à l'écoute !
Si tu as des questions ou des retours, n'hésite pas à me contacter. Bon code !
Références
S'abonner aux prochains articles
Recevez les nouveaux articles par e-mail. Pas de spam, désinscription à tout moment.
Related posts
Sauvegarder et restaurer MongoDB dans un environnement Docker
Comment créer une sauvegarde complète d'une base MongoDB qui tourne dans un conteneur Docker et restaurer la sauvegarde dans un nouveau conteneur MongoDB.
July 18, 2024
Déployer une API Express.js avec Docker
Comment déployer une API REST Express.js avec Docker, avec un focus sur les performances MongoDB, les builds Docker multi-stage, Jest pour les tests, et Nginx comme reverse proxy.
April 11, 2024