# mongodb Deployment on kubernetes QUELLE: https://phoenixnap.com/kb/kubernetes-mongodb ## Introduction MongoDB is a general-purpose, document-based NoSQL database program. As with other non-relational database management systems, MongoDB focuses on scalability and the speed of queries. Kubernetes synergizes with MongoDB to create highly scalable and portable database deployments. These deployments are useful for working with a large amount of data and high loads. This tutorial will teach you how to deploy MongoDB on Kubernetes. The guide includes steps to run a standalone MongoDB instance and a replica set. ## How to run MongoDB on Kubernetes. ### Requirements A Kubernetes cluster with kubectl. \ Administrative access to your system. \ >Note: MongoDB is part of the MEAN stack, a popular open-source software stack for web application development. Read about the differences between MEAN and LAMP stack. ## Deploy a Standalone MongoDB Instance MongoDB can be deployed on Kubernetes as a standalone instance. This deployment is not adequate for production use, but it is suitable for testing and some aspects of development. Follow the steps below to deploy a standalone MongoDB instance. ### Step 1: Label the Node Label the node that will be used for MongoDB deployment. The label is used later to assign pods to a specific node. To do so: 1. List the nodes on your cluster: ```bash kubectl get nodes ``` 2. Choose the deployment node from the list in the command output. 3. Use kubectl to label the node with a key-value pair. ```bash #kubectl label nodes = kubectl label nodes vmcon-node2.his.de size=large ``` The output confirms that the label was added successfully. ### Step 2: Create a StorageClass A StorageClass helps pods provision persistent volume claims on the node. To create a StorageClass: 1. Use a text editor to create a YAML file to store the storage class configuration. ```bash nano StorageClass.yaml ``` 2. Specify your storage class configuration in the file. The example below defines the mongodb-storageclass: ```yaml kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: mongodb-storageclass provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer allowVolumeExpansion: true ``` 3. Save the changes and exit the editor. >Note: To make the process easier, store all the files in this tutorial in a single directory. ### Step 3: Create Persistent Storage Provision storage for the MongoDB deployment by creating a persistent volume and a persistent volume claim: 1. Create a YAML file for persistent volume configuration. ```bash nano PersistentVolume.yaml ``` 2. In the file, allocate storage that belongs to the storage class defined in the previous step. Specify the node that will be used in pod deployment in the nodeAffinity section. The node is identified using the label created in Step 1. ```yaml apiVersion: v1 kind: PersistentVolume metadata: name: mongodb-pv spec: capacity: storage: 2Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: mongodb-storageclass local: path: /mnt/data nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: size operator: In values: - large ``` 3. Create another YAML for the configuration of the persistent volume claim: ```bash nano PersistentVolumeClaim.yaml ``` 4. Define the claim named mongodb-pvc and instruct Kubernetes to claim volumes belonging to mongodb-storageclass. ```yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: mongodb-pvc spec: storageClassName: mongodb-storageclass accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 1Gi ``` ### Step 4: Create a ConfigMap The ConfigMap file stores non-encrypted configuration information used by pods. 1. Create a YAML file to store deployment configuration: ```bash nano ConfigMap.yaml ``` 2. Use the file to store information about system paths, users, and roles. The following is an example of a ConfigMap file: ```yaml apiVersion: v1 kind: ConfigMap metadata: name: mongodb-configmap data: mongo.conf: | storage: dbPath: /data/db ensure-users.js: | const targetDbStr = 'test'; const rootUser = cat('/etc/k8-test/admin/MONGO_ROOT_USERNAME'); const rootPass = cat('/etc/k8-test/admin/MONGO_ROOT_PASSWORD'); const usersStr = cat('/etc/k8-test/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; } } }); ``` ### Step 5: Create a StatefulSet A StatefulSet is a Kubernetes controller used to deploy stateful apps. Stateful app pods require unique identities because they communicate with other pods. To Create a StatefulSet: 1. Use a text editor to create a YAML file: ```bash nano StatefulSet.yaml ``` 2. Insert deployment information in the file, including the MongoDB Docker image to be used. The file also references the previously created ConfigMap and PersistentVolumeClaim: ```yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: mongodb-test spec: serviceName: mongodb-test replicas: 1 selector: matchLabels: app: database template: metadata: labels: app: database selector: mongodb-test spec: containers: - name: mongodb-test image: mongo:4.0.8 env: - name: MONGO_INITDB_ROOT_USERNAME_FILE value: /etc/k8-test/admin/MONGO_ROOT_USERNAME - name: MONGO_INITDB_ROOT_PASSWORD_FILE value: /etc/k8-test/admin/MONGO_ROOT_PASSWORD volumeMounts: - name: k8-test mountPath: /etc/k8-test readOnly: true - name: mongodb-scripts mountPath: /docker-entrypoint-initdb.d readOnly: true - name: mongodb-configmap mountPath: /config readOnly: true - name: mongodb-data mountPath: /data/db nodeSelector: size: large volumes: - name: k8-test 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 - name: mongodb-scripts configMap: name: mongodb-configmap items: - key: ensure-users.js path: ensure-users.js - name: mongodb-configmap configMap: name: mongodb-configmap items: - key: mongo.conf path: mongo.conf - name: mongodb-data persistentVolumeClaim: claimName: mongodb-pvc ``` ### Step 6: Create a Secret The Secret object is used to store sensitive information about the deployment. 1. Create a Secret YAML with your text editor. ```bash nano Secret.yaml ``` 2. Provide information for accessing the MongoDB database. ```yaml apiVersion: v1 kind: Secret metadata: name: mongodb-secret type: Opaque data: MONGO_ROOT_USERNAME: YWRtaW4K MONGO_ROOT_PASSWORD: cGFzc3dvcmQK MONGO_USERNAME: dGVzdAo= MONGO_PASSWORD: cGFzc3dvcmQK MONGO_USERS_LIST: dGVzdDpkYkFkbWluLHJlYWRXcml0ZTpwYXNzd29yZAo= ``` 3. Save the changes and exit. ### Step 7: Create a MongoDB Service To create a MongoDB Service: 1. Create a headless service object. ```bash nano Service.yaml ``` Headless service allows users to connect to pods directly. 2. Add the service name and definition in the YAML file. ```yaml apiVersion: v1 kind: Service metadata: name: mongodb-test labels: app: database spec: clusterIP: None selector: app: database ``` 3. Save changes and exit the file. ### Step 8: Apply the MongoDB Configuration with Kustomize Use Kustomize to apply the MongoDB configuration files easily: 1. Create a kustomization.yaml file: ```bash nano kustomization.yaml ``` 2. In the resources section, list all the YAML files created in the previous steps: ```yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ConfigMap.yaml - PersistentVolumeClaim.yaml - PersistentVolume.yaml - Secret.yaml - Service.yaml - StatefulSet.yaml - StorageClass.yaml ``` Save the file in the same directory as the other files. 3. Deploy MongoDB with the following command: ```bash kubectl apply -k . ``` Applying the MongoDB configuration using Kustomize. 4. Use kubectl to check if the pod is ready. ```bash kubectl get pod ``` When the pod shows 1/1 in the READY column, proceed to the next step. ### Step 9: Connect to MongoDB Standalone Instance 1. Connect to the MongoDB pod by using the following kubectl command: ```bash kubectl exec -it mongodb-test-0 -- sh ``` 2. When the # prompt appears, type: ```bash mongo ``` MongoDB shell loads. 3. Switch to the test database: ```bash use test ``` 4. Authenticate with the following command: ```bash db.auth('test','password') ``` Number 1 in the output confirms the successful authentication. >Note: Read how MongoDB compares against Cassandra, another popular NoSQL solution. ## Deploy a ReplicaSet Deploying MongoDB as a ReplicaSet ensures that the specified number of pods are running at any given time. ReplicaSet deployments are recommended for production environments. ### Step 1: Set up Role-Based Access Control (RBAC) Enabling role-based access control is one of the Kubernetes security best practices. RBAC ensures that no user has more permissions than need. To set up RBAC: 1. Create a YAML file with a text editor. ```bash nano rbac.yaml ``` 2. Provide access rules for your MongoDB deployment. The example below shows an RBAC YAML file: ```yaml apiVersion: v1 kind: ServiceAccount metadata: name: mongo-account namespace: default --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: mongo-role rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["*"] - apiGroups: [""] resources: ["deployments"] verbs: ["list", "watch"] - apiGroups: [""] resources: ["services"] verbs: ["*"] - apiGroups: [""] resources: ["pods"] verbs: ["get","list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: mongo_role_binding subjects: - kind: ServiceAccount name: mongo-account namespace: default roleRef: kind: ClusterRole name: mongo-role apiGroup: rbac.authorization.k8s.io ``` 3. Save the file and apply it with kubectl: ```bash kubectl apply -f rbac.yaml ``` ### Step 2: Create a StatefulSet Deployment 1. Create a StatefulSet deployment YAML: ```bash nano StatefulSet.yaml ``` 2. Specify the number of replicas in the file, the MongoDB Docker image to be used, and provide a volume claim template for dynamic volume provision: ```yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: mongodb-replica namespace: default spec: serviceName: mongo replicas: 2 selector: matchLabels: app: mongo template: metadata: labels: app: mongo selector: mongo spec: terminationGracePeriodSeconds: 30 serviceAccount: mongo-account containers: - name: mongodb image: docker.io/mongo:4.2 env: command: ["/bin/sh"] args: ["-c", "mongod --replSet=rs0 --bind_ip_all"] resources: limits: cpu: 1 memory: 1500Mi requests: cpu: 1 memory: 1000Mi ports: - name: mongo-port containerPort: 27017 volumeMounts: - name: mongo-data mountPath: /data/db volumeClaimTemplates: - metadata: name: mongo-data spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi ``` 3. Save the file and use kubectl apply to create a deployment: ```bash kubectl apply -f StatefulSet.yaml ``` ### Step 3: Create a Headless Service To create a headless service: 1. Create a service YAML file: ```bash nano Service.yaml ``` 2. Define a service that enables direct communication with pods: ```yaml apiVersion: v1 kind: Service metadata: name: mongo namespace: default labels: name: mongo spec: ports: - port: 27017 targetPort: 27017 clusterIP: None selector: app: mongo ``` 3. Apply the YAML with kubectl. ```bash kubectl apply -f Service.yaml ``` ### Step 4: Set up Replication Host To set up pod replication: 1. Enter the pod using kubectl exec: ```bash kubectl exec -it mongodb-replica-0 -n default -- mongo ``` The MongoDB shell welcome message appears. 2. Initiate the replication by typing the following command at the MongoDB shell prompt: ```bash rs.initiate() ``` The "ok" : 1 line shows that the initiation was successful. 3. Define the variable called cfg. The variable executes rs.conf(). ```bash var cfg = rs.conf() ``` 4. Use the variable to add the primary server to the configuration: ```bash cfg.members[0].host="mongodb-replica-0.mongo:27017" ``` The output shows the name of the primary server. 5. Confirm the configuration by executing the following command: ```bash rs.reconfig(cfg) ``` The "ok" : 1 line confirms the configuration was successful. 6. Use the rs.add() command to add another pod to the configuration. ```bash rs.add("mongodb-replica-1.mongo:27017") ``` The output shows the replica was added. 7. Check the status of the system by typing: ```bash rs.status() ``` The "members" section should show two replicas. The primary replica is listed at the top of the output. >Note: Bare Metal Cloud offers instances designed to support high-performance NoSQL databases such as MongoDB. The instances offer performance and isolation necessary for demanding workloads.