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 => role.role) .filter(Boolean); usersStr .trim() .split(';') .map(s => s.split(':')) .forEach(user => { 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 => { 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 toPremium_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 namedmongodb-cn
based on themongo: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) namedmongodb-pvc
for MongoDB data storage.mongo-config
: A ConfigMap volume referencingmongodb-configmap
and itsmongo.conf
file.mongodb-scripts
: A ConfigMap volume referencingmongodb-configmap
and itsensure-users.js
script.nlweb-dev
: A secret volume referencingmongodb-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 toNone
, which means the service is only accessible internally within the cluster.selector
: Selects pods with the labelapp: 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.