In this post, we’ll walk through deploying a highly available MongoDB replica set on Kubernetes using StatefulSet
, headless service
, and RBAC
. We'll also cover how to initialize the replica set, troubleshoot DNS issues, and configure user authentication using Kubernetes secrets.
🔐 Step 1: Creating a Kubernetes Secret for MongoDB Credentials
Before deploying MongoDB, you should securely store the root credentials using a Kubernetes secret:
kubectl -n databases create secret generic mongo-secret \
--from-literal=mongo-user=123\
--from-literal=mongo-password=321
👤 Step 2: Define a ServiceAccount
MongoDB pods need access to service discovery. We'll create a service account in the same namespace:
apiVersion: v1
kind: ServiceAccount
metadata:
name: mongo
namespace: databases
⚙️ Step 3: Role Binding for DNS Resolution
Allow the service account to resolve pod and service endpoints via a ClusterRoleBinding
:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:serviceaccount:databases:mongo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: read-pod-service-endpoint
subjects:
- kind: ServiceAccount
name: mongo
namespace: databases
🌐 Step 4: Define a Headless Service
Headless services enable direct pod-to-pod communication, which MongoDB requires for replication:
apiVersion: v1
kind: Service
metadata:
name: mongo
labels:
name: mongo
spec:
selector:
app: mongo
ports:
- protocol: TCP
port: 27017
targetPort: 27017
clusterIP: None
📦 Step 5: Deploy MongoDB with StatefulSet
Here's a complete StatefulSet manifest for deploying a 3-node MongoDB replica set:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongo
labels:
app: mongo
spec:
serviceName: "mongo"
replicas: 3
selector:
matchLabels:
app: mongo
template:
metadata:
labels:
app: mongo
spec:
nodeSelector:
node.longhorn.io/create-default-disk: "true"
serviceAccountName: mongo
automountServiceAccountToken: true
containers:
- name: mongodb
image: mongo:5.0
command: ["mongod", "--replSet=rs0", "--bind_ip=0.0.0.0"]
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_ROOT_USERNAME
valueFrom:
secretKeyRef:
name: mongo-secret
key: mongo-user
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mongo-secret
key: mongo-password
volumeMounts:
- name: mongo-persistent-storage
mountPath: /data/db
- name: mongo-sidecar
image: morphy/k8s-mongo-sidecar
env:
- name: KUBERNETES_POD_LABELS
value: "role=mongo,environment=test"
- name: KUBERNETES_SERVICE_NAME
value: "mongo"
volumeClaimTemplates:
- metadata:
name: mongo-persistent-storage
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
🧠 Step 6: Initialize the Replica Set
Once the pods are up and running, initialize the replica set:
kubectl exec -it mongo-0 -n databases -- mongo
Then run:
rs.initiate({
_id: "rs0",
version: 1,
members: [
{ _id: 0, host: "mongo-0.mongo.databases.svc.cluster.local:27017" },
{ _id: 1, host: "mongo-1.mongo.databases.svc.cluster.local:27017" },
{ _id: 2, host: "mongo-2.mongo.databases.svc.cluster.local:27017" }
]
})
Verify with:
rs.status()
🧪 Step 7: Verify Replication
use testDB
db.testCollection.insert({ name: "Replication Test" })
db.testCollection.find({})
👮 Step 8: Create Admin User (Workaround)
Until you integrate authentication with secrets fully, manually create a user:
use admin
db.createUser({
user: "123",
pwd: "321",
roles: [
{ role: "readWrite", db: "Alhumdillah" },
{ role: "dbAdmin", db: "Alhumdillah" }
]
})
🧭 Step 9: Troubleshooting DNS
To resolve headless service DNS issues, deploy a debugging pod:
apiVersion: v1
kind: Pod
metadata:
name: dnsutils
namespace: default
spec:
containers:
- name: dnsutils
image: registry.k8s.io/e2e-test-images/agnhost:2.39
imagePullPolicy: IfNotPresent
restartPolicy: Always
Then run:
kubectl exec -i -t dnsutils -- nslookup mongo-2.mongo.databases.svc.cluster.local
You should get multiple IPs for each pod.
🧪 Step 10: Test External Connection
mongo "mongodb://<user>:<password>@mongo-0,mongo-1,mongo-2.mongo.databases.svc.cluster.local/Alhumdillah?replicaSet=rs0&authSource=admin"
Example:
mongo "mongodb://123:321@mongo-0.mongo.databases.svc.cluster.local:27017,mongo-1.mongo.databases.svc.cluster.local:27017,mongo-2.mongo.databases.svc.cluster.local:27017/Alhumdillah?replicaSet=rs0&authSource=admin"
🔁 Step 11: Reconfigure Replica Set (If Needed)
If your replica set was initialized with incorrect hosts (e.g., different namespaces), you must reconfigure it:
- Fetch current config:
cfg = rs.conf();
- Modify config:
cfg.version = 2;
cfg.members = [
{ _id: 0, host: "mongo-0.mongo.databases.svc.cluster.local:27017" },
{ _id: 1, host: "mongo-1.mongo.databases.svc.cluster.local:27017" },
{ _id: 2, host: "mongo-2.mongo.databases.svc.cluster.local:27017" }
];
- Apply:
rs.reconfig(cfg);
⚠️ Important: Never re-initiate an already initialized replica set. Use
rs.reconfig()
instead.
Next Steps :
1. Using Longhorn for Persistent Storage
Longhorn is a lightweight, distributed block storage system designed for Kubernetes. It provides resilient, high-availability volumes — critical for databases like MongoDB.
In our StatefulSet, we’re assuming Longhorn is already installed in your cluster. To ensure MongoDB pods use Longhorn volumes:
Enable a default disk on the node (if not already created):
kubectl label node <your-node-name> node.longhorn.io/create-default-disk=true
Verify Longhorn volumes:
After deploying MongoDB, check the Longhorn UI (http://:) or run:
kubectl get pv
Confirm replication settings:
In Longhorn settings, ensure each volume has at least 2 replicas for HA.
✅ Longhorn ensures that if a node or disk fails, your MongoDB data remains intact across replicas.
2. Backup and disaster recovery
The last thing you want to encounter when running highly scalable, highly available databases is data loss. You might want to consider kasten10
helm install k10 kasten/k10 --namespace kasten-io --create-namespace
✅ Conclusion
You’ve now deployed a robust, secure, and scalable MongoDB replica set on Kubernetes using best practices including:
- Kubernetes Secrets
- StatefulSets with persistent storage
- RBAC and DNS debugging
- Authentication and replica set configuration
- High Availability
This setup is production-grade and extensible—ideal for running databases like MongoDB in a cloud-native stack.
Top comments (0)