Deploy MongoDB Replica Set on K8s
Tags: kubernetes, mongodb, replicaset, deploy
Published: 2024-06-03 15:18:23

So, I set a new k8s cluster on DigitalOcean recently, and I want to share the way I deploy my MongoDB Replica Set on the k8s cluster. Let’s start it.

## Storage Class
I use Longhorn instead of the default do-block-storage provided by DigitalOcean as the default. I set up the longhorn using the helm chart. Since I use Rancher to manage my cluster, I install Longhorn from the App menu and choose Longhorn with the default value. super simple!

## Cluster IP Service
To create a statefulset, we will need to provide the serviceName so, let’s create a ClusterIP service for our MongoDB. The `mongodb-clusterip.yaml` file looks like this.

```yaml
apiVersion: v1
kind: Service
metadata:
  annotations:
    field.cattle.io/description: MongoDB Cluster IP
  name: mongodb-clusterip
  namespace: default
spec:
  ports:
    - name: mongo
      port: 27017
      protocol: TCP
      targetPort: 27017
  selector:
    app: mongodb
  type: ClusterIP
```

Then execute the kubectl apply command
`kubectl apply -f mongodb-clusterip.yaml`

## Secret
We will save the mongodb root user and mongodb root password in the Secret, so we need to create a new Secret for our MongoDB.

The `mongodb-secret.yaml` file looks like this

```yaml
apiVersion: v1
data:
  password: base6StringVersionOfpassword
  user: base6StringVersionOfuser
kind: Secret
metadata:
  name: mongodb-secret
  namespace: default
```

Then execute the kubectl apply command
`kubectl apply -f mongodb-secret.yaml`

## StatefulSet
Now the last thing that we need to execute is the statefulset for our MongoDB. The mongodb-statefulset.yaml file looks like this

```yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongodb
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mongodb
  serviceName: mongodb-clusterip
  template:
    metadata:
      namespace: default
      labels:
        app: mongodb
    spec:
      containers:
        - args:
            - '--dbpath'
            - /data/db
          command:
            - mongod
            - '--bind_ip_all'
            - '--replSet'
            - rs0
          env:
            - name: MONGO_INITDB_ROOT_USERNAME
              valueFrom:
                secretKeyRef:
                  key: user
                  name: mongodb-secret
            - name: MONGO_INITDB_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: password
                  name: mongodb-secret
          image: mongo:6.0.11
          imagePullPolicy: IfNotPresent
          name: mongodb-c
          volumeMounts:
            - mountPath: /data/db
              name: mongodb-pvc
  volumeClaimTemplates:
    - apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: mongodb-pvc
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 8Gi
        storageClassName: longhorn
```

Then execute the kubectl apply command
`kubectl apply -f mongodb-statefulset.yaml`

you can change the replica number with your own. I use 2 here.

After a few minutes, you should see the statefulset created. You can see it in your Rancher or using the `kubectl get` command.

Let’s make sure that the Mongodb is running using kubectl exec command below.

`kubectl --namespace=default exec -ti mongodb-0 -- mongosh`
Then you should get the mongosh prompt opened. For the second replica, you can do the same by changing the `mongodb-0` with `mongodb-1` instead.

## Configure Replica Set
To configure MongoDB replica set. First we need to open the `mongodb-0` (first pod of the MongoDb) using above command.

Then we use the `rs.initiate()` command as below

```
rs.initiate(
 {
  _id: "rs0",
  members: [
   { _id: 0, host: "mongodb-0.mongodb-clusterip.default.svc.cluster.local:27017" },
   { _id: 1, host: "mongodb-1.mongodb-clusterip.default.svc.cluster.local:27017" }
  ]
 }
)
```

if you notice that the pattern is `<pod>.<service>.<namespace>.svc.cluster.local:port`

Then try to add some data to the test db using the query
`db.test.insertOne({ testFromMaster: "true" })`

Now, exit from the master replica and open the mongosh in the secondary replica using the same command

`kubectl --namespace=default exec -ti mongodb-1 -- mongosh`
You will notice that the prompt is displaying the secondary. To start reading the data changes from the primary replica, we need to run the command

`db.getMongo().setReadPref("primaryPreferred")`

Then we can test to query the test data that we create before using the query

`db.test.find({})`

Now, you should see the secondary also has the test data.

That’s it. hopefully, you found this useful. Cheers.