Deploy MongoDB on Kubernetes (AKS)

Deploy MongoDB on Kubernetes

Deploy MongoDB on Kubernetes (AKS)

MongoDB is a popular NoSQL database system known for its flexibility and scalability. Deploying MongoDB on Azure Kubernetes Service (AKS) allows you to harness the power of Kubernetes for managing your MongoDB instances. In this blog post, we will explore a set of Kubernetes manifests that define a MongoDB deployment on AKS, breaking down each component to help you understand the setup.

Let’s create Kubernetes manifests  files to deploy mongodb on Kubernetes 

1. Add Label And Taint To The Node To deploy MongoDB on Kubernetes

Assign a label to the node designated for MongoDB deployment, which will be utilized in the future to allocate pods to that particular node.

Labels are a way to add metadata to resources, which can be used for grouping, filtering, and selecting resources.

Add label using kubectl label

kubectl label nodes <node> <key>=<value>
kubectl label nodes <node-name> database=mongodb

Adding taints to nodes in a Kubernetes cluster allows you to control how workloads are scheduled and distributed, helping you optimize your cluster for specific use cases and requirements.

Add taint using kubectl taint

kubectl taint nodes <node-name> <key>=<value>:<effect>
kubectl taint nodes <node-name> database=mongodb:NoSchedule

2. ConfigMap (mongodb-configmap.yaml)

Create a ConfigMap for MongoDB Configuration: The next step is to create a ConfigMap to store MongoDB configuration and user setup scripts.

Save the following YAML in a file, e.g., mongodb-configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mongodb-configmap
data:
  mongo.conf: |
    storage:
      dbPath: /data/db
  ensure-users.js: |
    const targetDbStr = 'dev';
    const rootUser = cat('/etc/nlweb-dev/admin/MONGO_ROOT_USERNAME');
    const rootPass = cat('/etc/nlweb-dev/admin/MONGO_ROOT_PASSWORD');
    const usersStr = cat('/etc/nlweb-dev/MONGO_USERS_LIST');
    const adminDb = db.getSiblingDB('admin');
    adminDb.auth(rootUser, rootPass);
    print('Successfully authenticated admin user');
    const targetDb = db.getSiblingDB(targetDbStr);
    const customRoles = adminDb
      .getRoles({rolesInfo: 1, showBuiltinRoles: false})
      .map(role =&gt; role.role)
      .filter(Boolean);
    usersStr
      .trim()
      .split(';')
      .map(s =&gt; s.split(':'))
      .forEach(user =&gt; {
        const username = user[0];
        const rolesStr = user[1];
        const password = user[2];
        if (!rolesStr || !password) {
          return;
        }
        const roles = rolesStr.split(',');
        const userDoc = {
          user: username,
          pwd: password,
        };
        userDoc.roles = roles.map(role =&gt; {
          if (!~customRoles.indexOf(role)) {
            return role;
          }
          return {role: role, db: 'admin'};
        });
        try {
          targetDb.createUser(userDoc);
        } catch (err) {
          if (!~err.message.toLowerCase().indexOf('duplicate')) {
            throw err;
          }
        }
      });

The ConfigMap allows you to store configuration data separately from your Pods. In this case, it stores two important configuration files:

mongo.conf

This file configures MongoDB’s storage settings. It specifies the path to the database files (dbPath) as /data/db.

ensure-users.js

This script is used to ensure the creation of MongoDB users. It reads user and role information from various files and creates users in the dev database. It also handles user roles and permissions.

3. StorageClass (azure-disk-storageclass.yaml)

Create a StorageClass for Azure Disks: You need a StorageClass to define the storage options for MongoDB.

Save the following YAML in a file, e.g., azure-disk-storageclass.yaml:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: azure-disk-storageclass
provisioner: kubernetes.io/azure-disk
parameters:
  skuName: Premium_ZRS
allowVolumeExpansion: true
 

The StorageClass is used to define the type of storage for your Persistent Volume Claims (PVCs). In this case, it defines a storage class named azure-disk-storageclass with specific parameters:

  • provisioner: Specifies the provisioner for Azure Disk storage.
  • skuName: Sets the SKU name to Premium_ZRS, indicating premium redundancy storage.
  • allowVolumeExpansion: Allows for volume expansion, providing flexibility as data storage needs grow.

4. Secret (mongodb-secret.yaml)

Create a Secret for MongoDB Credentials: A Secret is used to store sensitive data like MongoDB usernames and passwords.

Save the following YAML in a file, e.g., mongodb-secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: mongodb-secret
type: Opaque
data:
  MONGO_ROOT_USERNAME: YWRtaW4=
  MONGO_ROOT_PASSWORD: cGFzc3dvcmQ=
  MONGO_USERNAME: ZGV2
  MONGO_PASSWORD: cGFzc3dvcmQ=
  MONGO_USERS_LIST: ZGV2OmRiQWRtaW4scmVhZFdyaXRlOnBhc3N3b3Jk
 

The Secret resource securely stores sensitive data, such as usernames and passwords. In this case, it stores several MongoDB-related credentials:

data: This section is where the actual key-value pairs are defined. The keys are the names of the data entries, and the values are base64-encoded. In this manifest, the following key-value pairs are defined:

  • MONGO_ROOT_USERNAME: YWRtaW4=: This entry defines the MongoDB root username. The username is “admin,” and it is base64-encoded as “YWRtaW4=”.

  • MONGO_ROOT_PASSWORD: cGFzc3dvcmQ=: This entry defines the MongoDB root password. The password is “password,” and it is base64-encoded as “cGFzc3dvcmQ=”.

  • MONGO_USERNAME: ZGV2: This entry defines a MongoDB username. The username is “dev,” and it is base64-encoded as “ZGV2.”

  • MONGO_PASSWORD: cGFzc3dvcmQ=: This entry defines a MongoDB password. The password is “password,” and it is base64-encoded as “cGFzc3dvcmQ=”.

  • MONGO_USERS_LIST: ZGV2OmRiQWRtaW4scmVhZFdyaXRlOnBhc3N3b3Jk: This is a list of MongoDB users and their associated information, with each part of the list base64-encoded. It  follows a pattern where user information is separated by colons and different users are separated by semicolons. For example, it represents user data like “dev:dbAdmin,readWrite:password” for a user named “dev.”

5. StatefulSet (mongodb-statefulset.yaml)

Create a StatefulSet for MongoDB Deployment: The StatefulSet defines the MongoDB deployment with specified resources, volumes, and init containers for user setup.

Save the following YAML in a file, e.g., mongodb-statefulset.yaml:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongodb
spec:
  replicas: 1
  serviceName: mongodb-service
  selector:
    matchLabels:
      app: database
  template:
    metadata:
      labels:
        app: database
        selector: mongodb-service
    spec:
      containers:
        - name: mongodb-cn
          image: mongo:4.4
          resources:
            requests:
              memory: "8Gi"
              cpu: "4000m"
            limits:
              memory: "32Gi"
              cpu: "7800m"
          env:
            - name: MONGO_INITDB_ROOT_USERNAME_FILE
              value: /etc/nlweb-dev/admin/MONGO_ROOT_USERNAME
            - name: MONGO_INITDB_ROOT_PASSWORD_FILE
              value: /etc/nlweb-dev/admin/MONGO_ROOT_PASSWORD
          ports:
            - containerPort: 27017
          volumeMounts:
          - name: nlweb-dev
            mountPath: /etc/nlweb-dev
            readOnly: true
          - name: mongodb-scripts
            mountPath: /docker-entrypoint-initdb.d
            readOnly: true
          - name: mongo-config
            mountPath: /config
            readOnly: true
          - name: mongo-data
            mountPath: /data/db
      volumes:
        - name: mongo-data
          persistentVolumeClaim:
            claimName: mongodb-pvc
        - name: mongo-config
          configMap:
            name: mongodb-configmap
            items: 
            - key: mongo.conf
              path: mongo.conf
        - name: mongodb-scripts
          configMap:
            name: mongodb-configmap
            items:
            - key: ensure-users.js
              path: ensure-users.js
        - name: nlweb-dev
          secret:
            secretName: mongodb-secret
            items:
            - key: MONGO_ROOT_USERNAME
              path: admin/MONGO_ROOT_USERNAME
              mode: 0444
            - key: MONGO_ROOT_PASSWORD
              path: admin/MONGO_ROOT_PASSWORD
              mode: 0444
            - key: MONGO_USERNAME
              path: MONGO_USERNAME
              mode: 0444
            - key: MONGO_PASSWORD
              path: MONGO_PASSWORD
              mode: 0444
            - key: MONGO_USERS_LIST
              path: MONGO_USERS_LIST
              mode: 0444
      tolerations:
      - key: "database"
        operator: "Equal"
        value: mongodb
        effect: "NoSchedule"
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: database
                    operator: In
                    values:
                      - mongodb
  volumeClaimTemplates:
    - metadata:
        name: mongo-data
      spec:
        storageClassName: "azure-disk-storageclass"
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 400Gi

The StatefulSet manages a set of stateful pods, which is suitable for databases like MongoDB. Let’s dive into its configuration:

  • replicas: Specifies the desired number of replicas (1 in this case).
  • serviceName: Assigns the service name for this StatefulSet (mongodb-service).
  • selector: Defines labels for selecting pods that belong to this StatefulSet.

Pod Template

The StatefulSet’s pod template specifies the configuration for individual MongoDB pods:

  • containers: Contains a single container named mongodb-cn based on the mongo:4.4 Docker image.
  • resources: Defines CPU and memory resource requests and limits for the container.
  • env: Sets environment variables for MongoDB, including the root user’s username and password.
  • ports: Exposes port 27017 for MongoDB connections.

VolumeMounts

The volumeMounts section defines where and how volumes are mounted in the container. The MongoDB container mounts several volumes:

  • /etc/nlweb-dev: A secret volume to store credentials securely.
  • /docker-entrypoint-initdb.d: A ConfigMap volume for MongoDB initialization scripts.
  • /config: A ConfigMap volume for MongoDB configuration.
  • /data/db: A volume for MongoDB data files.

Volumes

The volumes section lists the volumes defined in the pod template:

  • mongo-data: A Persistent Volume Claim (PVC) named mongodb-pvc for MongoDB data storage.
  • mongo-config: A ConfigMap volume referencing mongodb-configmap and its mongo.conf file.
  • mongodb-scripts: A ConfigMap volume referencing mongodb-configmap and its ensure-users.js script.
  • nlweb-dev: A secret volume referencing mongodb-secret and its various keys.

Tolerations and Affinity

The tolerations and affinity sections define node tolerations and affinities for pod scheduling, ensuring that pods are scheduled appropriately.

6. Service (mongodb-service.yaml)

The Service is responsible for making MongoDB accessible within the cluster.

Save the following YAML in a file, e.g., mongodb-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
  labels:
    app: database
spec:
  clusterIP: None
  selector:
    app: database
 

The Service resource defines how external clients can access the MongoDB deployment. Let’s examine its configuration:

  • clusterIP: The cluster IP is set to None, which means the service is only accessible internally within the cluster.
  • selector: Selects pods with the label app: database for routing traffic to MongoDB pods.

6. Apply all the above manifests with Kustomize

Create a kustomization.yaml file, And in the resources section, mentioned all above manifest files 

vim  kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - mongodb-configmap.yaml
  - mongodb-secret.yaml
  - mongodb-service.yaml
  - azure-disk-storageclass.yaml
  - mongodb-statefulset.yaml

Save the file and execute the MongoDB deployment using the command below:

kubectl apply -k .

You can use kubectl to verify if the pod is in the “Ready” state. To do so, execute the following command:

kubectl get pod

In summary, these Kubernetes manifests define a robust MongoDB deployment on AKS, with careful attention to configuration, security, and scalability. This setup allows you to efficiently manage MongoDB in a Kubernetes environment, making it a scalable and flexible solution for your data storage needs.

Nitin Kumar

Nitin Kumar is a skilled DevOps Engineer with a strong passion for the finance domain. Specializing in automating processes and improving software delivery. With expertise in cloud technologies and CI/CD pipelines, he is adept at driving efficiency and scalability in complex IT environments.