Setup


https://www.mongodb.com/docs/manual/installation/
https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/
https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-red-hat/
https://hub.docker.com/_/mongo
https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set/
https://www.mongodb.com/docs/manual/tutorial/enforce-keyfile-access-control-in-existing-replica-set/
https://github.com/mongodb/helm-charts
https://github.com/percona/percona-helm-charts
https://github.com/bitnami/charts/tree/main/bitnami/mongodb

1. Linux VM With systemd#

install#

example:
    Ubuntu 24.04
    MongoDB Community 8.0
    systemd service: mongod

note:
    production should follow the exact official repository for your OS version
    do not install random mongodb packages from old distro repo
sudo apt-get update
sudo apt-get install -y gnupg curl

curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc \
  | sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor

echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" \
  | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list

sudo apt-get update
sudo apt-get install -y mongodb-org

directories#

sudo mkdir -p /var/lib/mongo /var/log/mongodb /etc/mongodb/tls
sudo chown -R mongodb:mongodb /var/lib/mongo /var/log/mongodb
sudo chmod 0755 /var/lib/mongo /var/log/mongodb

config#

# /etc/mongod.conf
storage:
  dbPath: /var/lib/mongo
  journal:
    enabled: true

systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true

net:
  port: 27017
  bindIp: 127.0.0.1,10.0.1.10

processManagement:
  timeZoneInfo: /usr/share/zoneinfo

security:
  authorization: enabled
  keyFile: /etc/mongodb/keyfile

replication:
  replSetName: rs0

operationProfiling:
  slowOpThresholdMs: 100

keyfile#

openssl rand -base64 756 | sudo tee /etc/mongodb/keyfile > /dev/null
sudo chown mongodb:mongodb /etc/mongodb/keyfile
sudo chmod 0400 /etc/mongodb/keyfile
keyfile notes:
    same content on every replica set member
    owner should be mongodb
    permission should be strict
    rotate with a planned maintenance procedure

systemd#

sudo systemctl daemon-reload
sudo systemctl enable mongod
sudo systemctl start mongod
sudo systemctl status mongod
journalctl -u mongod -f
tail -f /var/log/mongodb/mongod.log

initialize replica set#

mongosh

rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "mongo-1.example.internal:27017" },
    { _id: 1, host: "mongo-2.example.internal:27017" },
    { _id: 2, host: "mongo-3.example.internal:27017" }
  ]
})

create admin user#

use admin

db.createUser({
  user: "root_admin",
  pwd: passwordPrompt(),
  roles: [
    { role: "root", db: "admin" }
  ]
})

create application user#

use admin

db.createUser({
  user: "order_app",
  pwd: passwordPrompt(),
  roles: [
    { role: "readWrite", db: "order" }
  ]
})

firewall#

allow:
    app subnet -> mongo nodes tcp/27017
    mongo nodes -> mongo nodes tcp/27017
    bastion/admin subnet -> mongo nodes tcp/27017, if required

deny:
    public internet -> tcp/27017

2. Docker#

standalone for local dev#

docker network create mongo-net

docker run -d \
  --name mongo \
  --network mongo-net \
  -p 27017:27017 \
  -e MONGO_INITDB_ROOT_USERNAME=root \
  -e MONGO_INITDB_ROOT_PASSWORD=change-me \
  -v mongo-data:/data/db \
  mongo:8
mongosh "mongodb://root:change-me@localhost:27017/admin"

docker compose replica set#

services:
  mongo-1:
    image: mongo:8
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--keyFile", "/etc/mongo/keyfile"]
    ports:
      - "27017:27017"
    volumes:
      - mongo-1-data:/data/db
      - ./keyfile:/etc/mongo/keyfile:ro

  mongo-2:
    image: mongo:8
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--keyFile", "/etc/mongo/keyfile"]
    ports:
      - "27018:27017"
    volumes:
      - mongo-2-data:/data/db
      - ./keyfile:/etc/mongo/keyfile:ro

  mongo-3:
    image: mongo:8
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--keyFile", "/etc/mongo/keyfile"]
    ports:
      - "27019:27017"
    volumes:
      - mongo-3-data:/data/db
      - ./keyfile:/etc/mongo/keyfile:ro

volumes:
  mongo-1-data:
  mongo-2-data:
  mongo-3-data:
openssl rand -base64 756 > keyfile
chmod 0400 keyfile

docker compose up -d
mongosh "mongodb://localhost:27017"

rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "mongo-1:27017" },
    { _id: 1, host: "mongo-2:27017" },
    { _id: 2, host: "mongo-3:27017" }
  ]
})
docker notes:
    good for local dev / lab
    production needs persistent volume, backup, monitoring, TLS, resource limits
    container memory limit should match WiredTiger cache configuration

3. K8S With Helm#

option#

MongoDB official helm-charts repo:
    includes community-operator chart
    community charts are not officially supported by MongoDB
    good for lab / learning

Percona Operator for MongoDB:
    open-source operator
    production-oriented HA / backup / TLS / users
    recommended for self-managed OSS production if your team accepts Percona stack

Bitnami MongoDB chart:
    simple Helm chart
    supports standalone / replicaset
    good for quick setup
    production needs careful values review

percona operator#

helm repo add percona https://percona.github.io/percona-helm-charts/
helm repo update

kubectl create namespace mongodb

helm install psmdb-operator percona/psmdb-operator \
  --namespace mongodb
helm install psmdb-db percona/psmdb-db \
  --namespace mongodb \
  --set finalizers.deletePvc=false \
  --set replsets.rs0.size=3 \
  --set replsets.rs0.volumeSpec.persistentVolumeClaim.resources.requests.storage=100Gi
check:
    kubectl -n mongodb get pods
    kubectl -n mongodb get psmdb
    kubectl -n mongodb get pvc

bitnami replicaset#

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

kubectl create namespace mongodb

helm install mongodb bitnami/mongodb \
  --namespace mongodb \
  --set architecture=replicaset \
  --set replicaCount=3 \
  --set auth.enabled=true \
  --set auth.rootPassword='change-me' \
  --set auth.replicaSetKey='change-me-replica-key' \
  --set persistence.enabled=true \
  --set persistence.size=100Gi
production values should include:
    resource requests / limits
    storageClass
    pod anti-affinity
    TLS
    backup
    monitoring exporter
    network policy
    secret management

network policy#

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: mongodb-allow-app
  namespace: mongodb
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: mongodb
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: app
      ports:
        - protocol: TCP
          port: 27017

4. High Availability#

replica set#

recommended:
    3 data-bearing nodes across different AZs
    odd number of voting members
    majority writeConcern for critical write
    app connection string includes all nodes and replicaSet name

example:
    mongo-1: primary or secondary
    mongo-2: primary or secondary
    mongo-3: primary or secondary

connection string:
    mongodb://order_app:<password>@mongo-1:27017,mongo-2:27017,mongo-3:27017/order?replicaSet=rs0&authSource=admin
election:
    primary unavailable -> secondaries elect new primary
    writes fail during short election window
    application driver must retry retryable writes
    tune timeout and retry policy

arbiter#

arbiter:
    votes in election
    does not store data
    cannot become primary

use only when:
    cost is constrained
    two data-bearing nodes are unavoidable

avoid when:
    you need strong durability across AZs
    writeConcern majority should represent data-bearing majority

hidden / delayed secondary#

hidden secondary:
    not visible to application read preference
    useful for backup / analytics / reporting

delayed secondary:
    intentionally lags
    can help recover from accidental delete / bad write
    not a replacement for real backup

sharded cluster HA#

sharded cluster components:
    shard replica sets
    config server replica set
    mongos routers

HA requirements:
    each shard is a replica set
    config servers run as replica set
    multiple mongos behind app / service discovery
    distribute pods / VMs across AZs

use sharding when:
    one replica set cannot handle data size or throughput
    shard key has been carefully tested

backup and restore#

HA is not backup:
    replica set protects node failure
    backup protects data corruption / accidental delete / ransomware / bad deploy

must have:
    scheduled backup
    tested restore
    offsite copy
    documented RPO / RTO

5. Operations#

rolling restart#

order:
    restart secondary first
    wait until healthy and caught up
    step down primary
    restart old primary
    verify new primary and replication lag
rs.status()
rs.stepDown()

upgrade#

upgrade checklist:
    read official release notes
    check driver compatibility
    backup before upgrade
    upgrade secondaries first
    step down primary
    upgrade old primary
    only change featureCompatibilityVersion after rollback window

maintenance commands#

db.adminCommand({ ping: 1 })
rs.status()
rs.printReplicationInfo()
rs.printSecondaryReplicationInfo()
db.serverStatus()
db.currentOp()