How to Install MongoDB on Vultr Kubernetes Engine (VKE)

Updated on November 21, 2023
How to Install MongoDB on Vultr Kubernetes Engine (VKE) header image

Introduction

MongoDB is an open-source database program. Classified as a NoSQL database program, the data stored in MongoDB is in JSON-like format. Instead of tables and rows, it stores data in collections of documents. Each collection contains related documents, and each document is a JSON-like object. The data model of MongoDB provides the flexibility in storing data with an optional schema.

The MongoDB Kubernetes Operator is an extension for Kubernetes. It allows deployment and management of MongoDB server on a Kubernetes cluster. It supports the deployment of replica sets in which a group of MongoDB servers stores the same data providing redundancy and high availability for production usage.

This guide walks you through the deployment of a MongoDB replica set on Vultr Kubernetes Engine (VKE) using the MongoDB Kubernetes Operator, securing the deployment with a TLS certificate generated using cert-manager, and deploying Vultr Load Balancers for external access.

Prerequisites

On the management workstation:

You'll perform the rest of the steps in this guide from your management workstation.

Install the MongoDB Kubernetes Operator

The MongoDB Kubernetes Operator is a custom resource definition and a controller that simplifies the MongoDB server's deployment and management. This section explains the steps to install the custom resource definition, the role bindings, and the operator.

Clone the MongoDB Kubernetes Operator repository.

# git clone https://github.com/mongodb/mongodb-kubernetes-operator.git

Switch to the repository directory.

# cd mongodb-kubernetes-operator

Install the custom resource definition.

# kubectl apply -f config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml

The above command installs the MongoDBCommunity resource type in the cluster. This resource allows the deployment and scaling of the MongoDB replica set. You use this resource for defining the configuration of the MongoDB replica set.

Create a new namespace.

# kubectl create namespace mongodb

A namespace isolates the resources related to a single application in the cluster. The above command creates a new namespace named mongodb that you use in the next steps to contain all the resources related to the MongoDB replica set.

Install the necessary roles and role bindings.

# kubectl apply -k config/rbac -n mongodb

The above command installs a specific set of permissions required by the MongoDB Kubernetes Operator to interact with the resources in the cluster. The -n flag specifies the namespace to apply the changes.

Install the MongoDB Kubernetes Operator.

# kubectl apply -f config/manager/manager.yaml -n mongodb

The above command installs the MongoDB Kubernetes Operator in the cluster. It creates a new pod in the mongodb namespace and watches for state changes related to the MongoDBCommunity resource type.

Verify the installation.

# kubectl get pods -n mongodb

Output.

NAME                                           READY   STATUS    RESTARTS   AGE
mongodb-kubernetes-operator-648bf8cc59-mc5sm   1/1     Running   0          10s

Install the cert-manager Add-On

The cert-manager add-on for Kubernetes provides custom resource definitions that allow issuing TLS certificates. It installs three custom resources in the cluster: Issuer, ClusterIssuer, and Certificate. The Certificate resource requires an issuer parent resource, and it generates a Kubernetes secret which contains a pair of the TLS certificate and the private key.

Install the cert-manager add-on.

# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yaml

The above command installs all the Kubernetes resources provided by the cert-manager add-on in the cluster.

Create a new configuration directory.

# mkdir ~/mongodb-replica-set

Switch to the configuration directory.

# cd ~/mongodb-replica-set

This guide uses a self-signed TLS certificate to secure the MongoDB replica set. A valid TLS certificate requires a certificate authority signature. To sign the TLS certificate for the MongoDB replica set, you create an issuer that generates a self-signed certificate authority.

Using a text editor, create a new file named certificate.yaml.

# nano certificate.yaml

Add the following contents to the file.

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: mongodb-ca-issuer
spec:
  selfSigned: {}

---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: mongodb-ca-cert
spec:
  isCA: true
  commonName: mongodb-ca-cert
  secretName: mongodb-ca-cert-key-pair
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: mongodb-ca-issuer
    kind: Issuer

---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: mongodb-issuer
spec:
  ca:
    secretName: mongodb-ca-cert-key-pair

---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: mongodb-cert
spec:
  commonName: '*.mongodb-svc.mongodb.svc.cluster.local'
  secretName: mongodb-cert-key-pair
  dnsNames:
  - '*.mongodb-svc.mongodb.svc.cluster.local'
  - 'mongodb-0.example.com'
  - 'mongodb-1.example.com'
  - 'mongodb-2.example.com'
  issuerRef:
    name: mongodb-issuer
    kind: Issuer

The above configuration creates four resources: the mongodb-ca-issuer Issuer resource allows the creation of the mongodb-ca-cert Certificate resource, which is a self-signed certificate authority. It uses the self-signed certificate authority to create the mongodb-issuer Issuer resource, which allows creating the mongodb-cert Certificate resource, which you use to secure the MongoDB replica set.

The commonName and the dnsName attributes in the mongodb-cert Certificate resource contain the certificate's hostnames. The commonName attribute is a wildcard followed by the syntax of the hostname used by the MongoDB Kubernetes Operator to provision the servers locally. The syntax of the hostname is as follows:

<metadata.name>-<member-number>.<metadata.name>-svc.<namespace>.svc.cluster.local

The <metadata.name> is the name of the MongoDBCommunity resource. In the next steps, you build the configuration for the MongoDB replica set using mongodb as the metadata name and the number of MongoDB replica set members you want to spawn in the cluster.

Replace and add a list of additional hostnames for external access in the dnsName attribute according to the number of members you want to spawn. You use these additional hostnames as replica set horizons in the next steps.

Apply the configuration.

# kubectl apply -f certificate.yaml -n mongodb

Verify the certificate state.

# kubectl get certificate -n mongodb

Output.

NAME              READY   SECRET                     AGE
mongodb-ca-cert   True    mongodb-ca-cert-key-pair   11s
mongodb-cert      True    mongodb-cert-key-pair      10s

Deploy MongoDB Replica Set

A MongoDB replica set is a group of two or more instances of the MongoDB server that store the same data to enable redundancy and high availability for production usage. The MongoDB Kubernetes Operator enables you to deploy a MongoDB replica set on your VKE cluster using a single declarative configuration file instead of deploying and configuring multiple servers. This section explains the configuration and deployment of a MongoDB replica set using the MongoDB Kubernetes Operator.

Create a new file named replica-set.yaml.

# nano replica-set.yaml

Add the following contents to the file.

apiVersion: v1
kind: Secret
metadata:
  name: demo-admin-password
type: Opaque
stringData:
  password: 'your_password'

---
apiVersion: mongodbcommunity.mongodb.com/v1
kind: MongoDBCommunity
metadata:
  name: mongodb
spec:
  members: 3
  type: ReplicaSet
  version: "5.0.5"
  replicaSetHorizons:
  - horizon: mongodb-0.example.com:27017
  - horizon: mongodb-1.example.com:27017
  - horizon: mongodb-2.example.com:27017
  security:
    authentication:
      modes: ["SCRAM"]
    tls:
      enabled: true
      certificateKeySecretRef:
        name: mongodb-cert-key-pair
      caCertificateSecretRef:
        name: mongodb-cert-key-pair
  users:
    - name: demo-admin
      db: admin
      passwordSecretRef:
        name: demo-admin-password
      roles:
        - name: clusterAdmin
          db: admin
        - name: userAdminAnyDatabase
          db: admin
      scramCredentialsSecretName: my-scram
  statefulSet:
      spec:
        volumeClaimTemplates:
          - metadata:
              name: data-volume
            spec:
              accessModes: ["ReadWriteOnce"]
              storageClassName: vultr-block-storage
              resources:
                requests:
                  storage: 20Gi
          - metadata:
              name: logs-volume
            spec:
              accessModes: ["ReadWriteOnce"]
              storageClassName: vultr-block-storage-hdd
              resources:
                requests:
                  storage: 40Gi

The above configuration creates a MongoDBCommunity resource in the cluster and a Kubernetes secret containing a password for the administrator user. When you apply the configuration, the MongoDB Kubernetes Operator creates a Kubernetes StatefulSet to provision the MongoDB replica set. Each replica set member is a pod with two containers: a container for the mongod process binary and a container for the MongoDB agent, which handles the provisioning of the mongod process. Each pod consists of 2 volumes: a volume for storing the database and a volume for storing logs.

The following are the highlights of the configuration:

  • metadata.name - The name of the MongoDBCommunity resource, used as prefix of related resources.

  • spec.version - The version of MongoDB community server installed in the replica set.

  • spec.members - The number of replica set members.

  • spec.replicaSetHorizons - The DNS hostnames used for external access. They should match the number of replica set members. Ensure that the TLS certificate includes these hostnames.

  • spec.security.tls - Enable TLS security and define the Kubernetes secret created by cert-manager containing the TLS certificate key-pair.

  • spec.users - The name of the administrator user, the Kubernetes secret referring to the administrator user's password, and the name of the collection for storing authentication information.

  • spec.statefulSet.spec.volumeClaimTemplates - The storage class and the storage size for volumes created for each member in the replica set. The above configuration uses the storage classes defined by Vultr Container Storage Interface (CSI) to provision Vultr Block Storage for each volume. Refer to the Vultr Container Storage Interface documentation for more information.

If you want to set non-default values for the Kubernetes StatefulSet deployed by the MongoDB Kubernetes Operator, you can use the spec.statefulSet attribute. It provides direct access to the Kubernetes Staefulset configuration. Refer to the configuration samples for more information.

Apply the configuration.

# kubectl apply -f replica-set.yaml -n mongodb

Follow the replica set deployment progress.

# watch -n 0.1 kubectl get pods -n mongodb

It takes around 5 to 10 minutes to finish the deployment.

Output.

Every 0.1s: kubectl get pods -n mongodb

NAME                                           READY   STATUS    RESTARTS   AGE
mongodb-0                                      2/2     Running   0          3m6s
mongodb-1                                      2/2     Running   0          102s
mongodb-2                                      2/2     Running   0          55s
mongodb-kubernetes-operator-648bf8cc59-mc5sm   1/1     Running   0          10m

Verify the deployment.

# kubectl get mongodbcommunity -n mongodb

Output.

NAME      PHASE     VERSION
mongodb   Running   5.0.5

If the deployment stops making any progress, you can use the following commands to troubleshoot and find the issue causing the delay.

# kubectl describe mongodbcommunity mongo -n mongodb
# kubectl describe pod mongo-0 -n mongodb
# kubectl get pvc -n mongodb
# kubectl get pv -n mongodb

The following are the issues you might face during the deployment of the replica set:

  • Not having enough CPU.
  • Not having enough Memory.
  • Vultr Block Storage limit exceeded.

Ensure that your VKE cluster has enough resources available and you do not exceed the total number of Vultr Block Storage volumes limit.

Access MongoDB Shell

You can fetch the connection string and the credentials to connect to the MongoDB replica set inside the cluster with the credentials stored by the MongoDB Kubernetes Operator in the Kubernetes secrets.

This is the syntax for the name of the Kubernetes secrets resource that contains the credentials:

<metadata.name>-<auth-db>-<username>

Fetch the connection string.

# kubectl get secret mongodb-admin-demo-admin -n mongodb -o json

The above command returns JSON response with BASE64 encoded values.

Install the jq package.

# apt install jq

The above package lets you decode the BASE64 values in the JSON response.

Fetch the usable connection string.

# kubectl get secret mongodb-admin-demo-admin -n mongodb -o json | jq -r '.data | with_entries(.value |= @base64d)'

Output.

{
  "connectionString.standard": "mongodb://demo-admin:your_password@mongodb-0.mongodb-svc.mongodb.svc.cluster.local:27017,mongodb-1.mongodb-svc.mongodb.svc.cluster.local:27017,mongodb-2.mongodb-svc.mongodb.svc.cluster.local:27017/admin?ssl=true",
  "connectionString.standardSrv": "mongodb+srv://demo-admin:your_password@mongodb-svc.mongodb.svc.cluster.local/admin?ssl=true",
  "password": "your_password",
  "username": "demo-admin"
}

You use the connectionString.standardSrv value and the TLS certificate to connect to the MongoDB replica set inside the cluster.

Enter the mongod container.

# kubectl exec -it mongodb-0 -c mongod -n mongodb -- /bin/bash

Connect to the MongoDB replica set using mongosh.

$ mongosh --tls --tlsCAFile /var/lib/tls/ca/*.pem --tlsCertificateKeyFile /var/lib/tls/server/*.pem "mongodb+srv://demo-admin:your_password@mongodb-svc.mongodb.svc.cluster.local/admin?ssl=true"

Fetch all databases.

mongodb [primary] admin> show dbs

Output.

admin   176 kB
config  172 kB
local   545 kB

Exit the mongosh session.

mongodb [primary] admin> quit()

Exit the mongod container.

$ exit

Fetch the TLS Certificate

You secured the MongoDB replica set deployed in the cluster using the TLS certificate key pair. You need that certificate and the private key to connect to the MongoDB replica set. Every pod provisioned by the MongoDB Kubernetes Operator contains the certificate and the private key in /var/lib/tls in the mongod container.

You can manually enter the mongod container of the first pod using kubectl exec -it mongodb-0 -c mongod -n mongodb -- /bin/bash to copy and paste the certificate and the private key files or use the following shortcuts to fetch them.

Fetch the certificate file.

# kubectl exec mongodb-0 -c mongod -n mongodb -- /bin/bash -c "cat /var/lib/tls/ca/*.pem" > crt.pem

The above command creates a file named crt.pem in the working directory containing the certificate contents.

Fetch the private key file.

# kubectl exec mongodb-0 -c mongod -n mongodb -- /bin/bash -c "cat /var/lib/tls/server/*.pem" > key.pem

The above command creates a file named key.pem in the working directory containing the private key contents.

Set Up External Access

The Vultr Cloud Controller Manager provides the ability to provision Vultr Load Balancer with Kubernetes. It binds the LoadBalancer service type with the Vultr Load Balancer service. When you create a new LoadBalancer service, the Vultr Cloud Controller Manager provisions a new Vultr Load Balancer in your account and configures it according to the object specifications and the annotations. This section explains how to set up external access for the MongoDB replica using load balancers and DNS records.

Create a new file named external-access.yaml.

# nano external-access.yaml

Add the following contents to the file.

apiVersion: v1
kind: Service
metadata:
  name: mongodb-lb-0
  namespace: mongodb
  annotations:
    service.beta.kubernetes.io/vultr-loadbalancer-protocol: "tcp"
spec:
  type: LoadBalancer
  ports:
  - name: mongodb
    port: 27017
    protocol: TCP
  selector:
    app: mongodb-svc
    statefulset.kubernetes.io/pod-name: mongodb-0

---
apiVersion: v1
kind: Service
metadata:
  name: mongodb-lb-1
  namespace: mongodb
  annotations:
    service.beta.kubernetes.io/vultr-loadbalancer-protocol: "tcp"
spec:
  type: LoadBalancer
  ports:
  - name: mongodb
    port: 27017
    protocol: TCP
  selector:
    app: mongodb-svc
    statefulset.kubernetes.io/pod-name: mongodb-1

---
apiVersion: v1
kind: Service
metadata:
  name: mongodb-lb-2
  namespace: mongodb
  annotations:
    service.beta.kubernetes.io/vultr-loadbalancer-protocol: "tcp"
spec:
  type: LoadBalancer
  ports:
  - name: mongodb
    port: 27017
    protocol: TCP
  selector:
    app: mongodb-svc
    statefulset.kubernetes.io/pod-name: mongodb-2

The above configuration creates three LoadBalancer service objects in the cluster. You can adjust the number of load balancers according to the number of members in the replica set. Each LoadBalancer service object provisions a Vultr Load Balancer, which forwards TCP traffic on port 27017 (default MongoDB port) to individual members in the replica set.

Apply the configuration.

# kubectl apply -f external-access.yaml -n mongodb

Follow the load balancer deployment progress.

# watch -n 0.1 kubectl get service -n mongodb

It takes around 5 minutes to finish the deployment.

Output.

NAME              TYPE           CLUSTER-IP       EXTERNAL-IP       PORT(S)           AGE
mongodb-arb-svc   ClusterIP      None             <none>            27017/TCP         155m
mongodb-lb-0      LoadBalancer   10.110.133.138   104.207.153.207   27017:31808/TCP   2m7s
mongodb-lb-1      LoadBalancer   10.98.170.249    45.32.70.189      27017:32151/TCP   2m7s
mongodb-lb-2      LoadBalancer   10.97.161.16     66.42.101.239     27017:30036/TCP   2m7s
mongodb-svc       ClusterIP      None             <none>            27017/TCP         155m

Configure the following DNS records in your domain to set up the A records and the Service (SRV) records for each load balancer.

|table|100| |thead| |tr| |th|20|Type| |th|40|Name| |th|40|Content| |tbody| |tr| |td|A| |td|mongodb-0.example.com| |td|LB-0-IP| |tr| |td|A| |td|mongodb-1.example.com| |td|LB-1-IP| |tr| |td|A| |td|mongodb-2.example.com| |td|LB-2-IP| |tr| |td|SRV| |td|_mongodb._tcp.mongodb.example.com| |td|0 50 27017 mongodb-0.example.com| |tr| |td|SRV| |td|_mongodb._tcp.mongodb.example.com| |td|0 50 27017 mongodb-1.example.com| |tr| |td|SRV| |td|_mongodb._tcp.mongodb.example.com| |td|0 50 27017 mongodb-2.example.com|

Verify DNS records.

# nslookup mongodb-0.example.com
# nslookup mongodb-1.example.com
# nslookup mongodb-2.example.com
# nslookup -q=SRV _mongodb._tcp.mongodb.example.com

The following is the connection string for external access.

mongodb+srv://demo-admin:your_password@mongodb.example.com/admin

You must pass the TLS certificate fetched in the previous section along with the connection string.

Verify the connection using the MongoDB Shell tool on your local system.

mongosh --tls --tlsCAFile /path/to/certificate/file --tlsCertificateKeyFile /path/to/private_key/file "mongodb+srv://demo-admin:your_password@mongodb.example.com/admin"

Output.

Current Mongosh Log ID: 62a71d81196f9e1982eefd7a
Connecting to:          mongodb+srv://<credentials>@mongodb.example.com/admin?appName=mongosh+1.3.1
Using MongoDB:          5.0.5
Using Mongosh:          1.3.1

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

mongodb [primary] admin>

Conclusion

You deployed a MongoDB replica set on a Vultr Kubernetes Engine (VKE) cluster, which stores data on the Vultr Block Storage service using the MongoDB Kubernetes Operator. You secured the replica set using a TLS certificate created using the cert-manager add-on. You used the Vultr Load Balancer service for setting up external access to the MongoDB replica set.

More Information