Đây là bài thực hành cấu hình MongoDB Replica Set (Bộ bản sao) bằng Docker Compose, tự động chạy lệnh rs.initiate() và liên kết với giao diện quản lý (mongo-express).

Các thành phần chính

  • mongo1, mongo2, mongo3: 3 node MongoDB cấu thành nên Replica Set.
  • mongo-express: Công cụ quản trị MongoDB dựa trên giao diện web.
  • replica-init: Một container chạy một lần để thực hiện khởi tạo cụm (cluster).

Cấu trúc thư mục

├── docker-compose.yml
├── .env
├── secrets/
│   └── mongo.key        # file khóa xác thực cho replica set
├── mongo-init/
│   └── init-replica.sh  # script tự động khởi tạo cluster
└── mongo-express/
    ├── Dockerfile       # bao gồm tính năng wait-for
    └── wait-for.sh

Ví dụ file .env

snippet
MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=example

ME_CONFIG_MONGODB_ADMINUSERNAME=root
ME_CONFIG_MONGODB_ADMINPASSWORD=example
ME_CONFIG_BASICAUTH_USERNAME=admin
ME_CONFIG_BASICAUTH_PASSWORD=admin

MONGODB_URI=mongodb://root:example@mongo1:27017/?replicaSet=rs0

secrets/mongo.key

# Cách tạo
openssl rand -base64 756 > secrets/mongo.key
chmod 400 secrets/mongo.key

docker-compose.yml

version: "3.9"

services:
  mongo1:
    image: mongo:6.0
    container_name: mongo1
    ports:
      - "27017:27017"
    volumes:
      - ./data/mongo1:/data/db
      - ./secrets/mongo.key:/etc/mongo.key:ro
    environment:
      - MONGO_INITDB_ROOT_USERNAME=
      - MONGO_INITDB_ROOT_PASSWORD=
    command: ["--replSet", "rs0", "--auth", "--keyFile", "/etc/mongo.key"]
    networks:
      - sample-app

  mongo2:
    image: mongo:6.0
    container_name: mongo2
    ports:
      - "27018:27017"
    volumes:
      - ./data/mongo2:/data/db
      - ./secrets/mongo.key:/etc/mongo.key:ro
    environment:
      - MONGO_INITDB_ROOT_USERNAME=
      - MONGO_INITDB_ROOT_PASSWORD=
    command: ["--replSet", "rs0", "--auth", "--keyFile", "/etc/mongo.key"]
    networks:
      - sample-app

  mongo3:
    image: mongo:6.0
    container_name: mongo3
    ports:
      - "27019:27017"
    volumes:
      - ./data/mongo3:/data/db
      - ./secrets/mongo.key:/etc/mongo.key:ro
    environment:
      - MONGO_INITDB_ROOT_USERNAME=
      - MONGO_INITDB_ROOT_PASSWORD=
    command: ["--replSet", "rs0", "--auth", "--keyFile", "/etc/mongo.key"]
    networks:
      - sample-app

  replica-init:
    image: mongo:6.0
    container_name: mongo-init
    depends_on:
      - mongo1
    volumes:
      - ./scripts/init-replica.sh:/init-replica.sh:ro
    entrypoint: [ "/bin/bash", "/init-replica.sh" ]
    networks:
      - sample-app

  mongo-express:
    image: mongo-express:1.0.0-alpha.4
    container_name: mongo-express
    restart: always # Khởi động lại nếu kết nối tới mongo1 thất bại
    ports:
      - "38081:8081"
    environment:
      - ME_CONFIG_MONGODB_URL=
      - ME_CONFIG_MONGODB_ADMINUSERNAME=
      - ME_CONFIG_MONGODB_ADMINPASSWORD=
      - ME_CONFIG_BASICAUTH_USERNAME=
      - ME_CONFIG_BASICAUTH_PASSWORD=
    depends_on:
      - mongo1
    networks:
      - sample-app

networks:
  sample-app:
    driver: bridge

Script tự động khởi tạo Cluster

mongo-init/init-replica.sh
#!/bin/bash

echo "[replica-init] Đang chờ MongoDB sẵn sàng..."

until mongosh --host mongo1 --username root --password example --authenticationDatabase admin --eval "db.adminCommand('ping')" >/dev/null 2>&1; do
  sleep 2
done

echo "[replica-init] Đã kết nối. Đang kiểm tra trạng thái replica set..."

# Kiểm tra xem đã khởi tạo chưa
IS_INITIALIZED=$(mongosh --host mongo1 --username root --password example --authenticationDatabase admin --quiet --eval "try { rs.status().ok } catch(e) { 0 }")

if [[ "$IS_INITIALIZED" == "1" ]]; then
  echo "[replica-init] Replica set đã được khởi tạo. Bỏ qua."
else
  echo "[replica-init] Đang khởi tạo replica set..."
  mongosh --host mongo1 --username root --password example --authenticationDatabase admin <<EOF
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "mongo1:27017" },
    { _id: 1, host: "mongo2:27017" },
    { _id: 2, host: "mongo3:27017" }
  ]
})
EOF
  echo "[replica-init] Đã khởi tạo replica set thành công."
fi

Chạy hệ thống

docker compose up -d

Thông tin truy cập

  • MongoDB URI: mongodb://root:example@localhost:27017/?replicaSet=rs0
  • Mongo Express: http://localhost:38081
  • Đăng nhập: admin / admin

Mẹo nhỏ kết thúc

  • Sử dụng lệnh rs.status() để kiểm tra xem các node Primary/Secondary đã được phân bổ đúng chưa.
  • Nếu giữ lại Docker volume, cấu hình sẽ được duy trì ngay cả khi khởi động lại.
  • mongo-express được đặt restart: always để tự động thử lại nếu ban đầu chưa kết nối được tới DB.
Nguồn bài viết ryukato.github.io