Hello again from the Red Hat Storage Architect team. In this series, I will show various ways to deploy MongoDB on Red Hat OpenShift Container Platform using Red Hat OpenShift Container Storage as the persistent storage layer that will provide stability, resilience and performance to MongoDB. All the demos and examples are based on OpenShift Container Platform v3.11.98 and OpenShift Container Storage v3.11.2.

It is not in our scope to explain how to install OpenShift Container Platform and OpenShift Container Storage so please refer to the documentation for these activities:

Product Documentation for OpenShift Container Platform 3.11

Product Documentation for OpenShift Container Storage 3.11

The series will start with a very simple method of setting up a MongoDB pod on OpenShift Container Platform using OpenShift Container Storage for persistent storage and then a detailed how to:

  • Use the Yahoo Cloud Serving Benchmark (YCSB) to gauge the performance of MongoDB on OpenShift Container Platform + OpenShift Container Storage 3.11

  • Use storage options available from AWS that can reduce operational costs.

  • Run a sharded MongoDB database on OpenShift Container Platform + OpenShift Container Storage 3.11 

MongoDB

Just in case you don’t know what MongoDB is, here’s a very very short description:

MongoDB is a popular document-based database that allows developers to quickly build projects without worrying about schema.

Mongo components include: 

  • mongod - the core process that runs the actual database 

  • mongos - controls routing to the databases in case of sharding

  • config servers (CSRS) - stores the metadata in a sharded environment. 

From a data perspective, a "collection" is the mongo equivalent of a "table" in a SQL database and a "document" is the "row" equivalent. 

OpenShift on AWS Test Environment

All of the posts in this blog series are using OpenShift Container Platform on an AWS setup that includes 8 EC2 instances deployed as 1 master node, 1 infrastructure node and 6 worker nodes that also run OpenShift Container Storage Gluster and Heketi pods. The 6 worker nodes are basically the storage provider (OpenShift Container Storage) and persistent storage consumers (MongoDB). 

As shown in the next figure, the OpenShift Container Storage worker nodes are of instance type m5.2xlarge with 8 vCPUs, 32 GB Mem, and 3x100GB gp2 volumes attached to each node for OpenShift Container Platform and a single 1TB gp2 volume for OpenShift Container Storage storage cluster. The cluster is deployed in the us-west-2 region using a single availability zone (AZ) us-west-2a.

OpenShift Container Storage cluster in AWS

MongoDB template on OpenShift

One of the many benefits of using OpenShift is the ease of use and ease of deploying applications. OpenShift Container Platform comes with a set of templates that can be used to deploy all sorts of applications.

In this example I’m going to use the mongodb-persistent template that comes with the OpenShift Container Platform 3.11 installation and modify it for our needs.

To export the template run:

$ oc get template mongodb-persistent -n openshift -o yaml --export > ocs-mongodb-persistent.yaml

The template is long and it is out of the scope of this post to discuss all the details in it, so let us focus on the areas of the template that will be changed. The first thing to do is to provide this template a different name. This is just so it will differ from the default templates. I performed a vi search/replace and changed all instances of "mongodb-persistent" to "mongodb-persistent-ocs."

So for example the first lines in the template were:

apiVersion: template.openshift.io/v1
kind: Template
labels:
  template: mongodb-persistent-template
message: |-

And now changed to:

apiVersion: template.openshift.io/v1
kind: Template
labels:
  template: mongodb-persistent-ocs-template
message: |-

Now I need to change the template so it will use OpenShift Container Storage (Gluster) as the persistent volume provider.

(Note: you could just change the glusterfs-storage storage class to be the default storageclass if desired).

Search for "kind: PersistentVolumeClaim," and I will add an annotation below "PersistentVolumeClaim" to use the glusterfs-storage storageclass for volume claims. The original template looked like this:

- apiVersion: v1
  kind: PersistentVolumeClaim
  metadata:
    name: ${DATABASE_SERVICE_NAME}

And I modified the volume section so it would look like this:

- apiVersion: v1
  kind: PersistentVolumeClaim
  metadata:
    annotations:
      volume.beta.kubernetes.io/storage-class: glusterfs-storage
    name: ${DATABASE_SERVICE_NAME}

(The text in bold is the annotation I’ve added)

The last change in the template is the version of MongoDB. The template comes with version 3.2, but I would like to use 3.6, so look at the last few lines in the template, under MONGODB_VERSION: change the "value:" from 3.2 to 3.6.

That is it for changes, save the file and import the template:

$ oc create -n openshift -f ocs-mongodb-persistent.yaml

Now, to check that the template was imported just run "oc get template" and make sure that you get a reply with the template name you created.

$ oc -n openshift get template mongodb-persistent-ocs
NAME                     DESCRIPTION                                                           PARAMETERS OBJECTS
mongodb-persistent-ocs   MongoDB database service, with persistent storage. For more information about...   9 (3 generated) 4

Using a template to create a MongoDB application

Now that I have our modified MongoDB template that uses OpenShift Container Storage for persistent storage claims, all that is left is to create an application from it:

$ oc new-app --name=mongodb36 --template=mongodb-persistent-ocs \
    -e MONGODB_USER=sagy \
    -e MONGODB_PASSWORD=password \
    -e MONGODB_DATABASE=testdb \
    -e MONGODB_ADMIN_PASSWORD=password

The important parts of the output from the above command are outlined below:

--> Deploying template "app-storage/mongodb-persistent-ocs" to project app-storage
.
.
.
--> Creating resources ...
    secret "mongodb" created
    service "mongodb" created
    persistentvolumeclaim "mongodb" created
    deploymentconfig.apps.openshift.io "mongodb" created
--> Success
    Application is not exposed. You can expose services to the outside world by executing one or more of the commands below:
     'oc expose svc/mongodb'
    Run 'oc status' to view your app.

If you look at the pods being created, you’ll see a sidecar named "mongodb-x-deploy" and another MongoDB pod being created:

$ oc get pods
NAME               READY STATUS RESTARTS   AGE
mongodb-1-deploy   1/1 Running 0          3s
mongodb-1-jzsgf    0/1 Pending 0          0s

Once the sidecar container finishes the configuration (for example the database and username/password I’ve provided in our example), it will terminate itself and the actual MongoDB pod will be at a "Running" state.

Now, let’s take a look at the persistent storage:

$ oc get pvc
NAME      STATUS VOLUME                                     CAPACITY ACCESS MODES STORAGECLASS AGE
mongodb   Bound pvc-e3f0663e-8291-11e9-a236-027caf97f40a   1Gi RWO glusterfs-storage 2m

As you can see, the template created a 1GB Gluster volume and attached it to the MongoDB container.

Let’s insert some sample data. I have a file with three documents (or rows) to insert into a collection (or table) called redhat:

$ cat some_data
db.redhat.insert({name:'Red Hat Enterprise Linux',product_name:'RHEL',type:'linux-x86_64',release_date:'05/08/2019',version:8})
db.redhat.insert({name:'Red Hat Enterprise Linux',product_name:'RHEL',type:'linux-x86_64',release_date:'05/08/2014',version:7})
db.redhat.insert({name:'Red Hat Enterprise Linux',product_name:'RHEL',type:'linux-x86_64',release_date:'05/08/2011',version:6})

Insert the data:

$ oc exec -it mongodb-1-jzsgf -- bash -c "mongo -u sagy -p password testdb" < some_data
Unable to use a TTY - input is not a terminal or the right kind of file
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/testdb
MongoDB server version: 3.6.3
WriteResult({ "nInserted" : 1 })
WriteResult({ "nInserted" : 1 })
WriteResult({ "nInserted" : 1 })
bye

Note that I’m using the database name (testdb) and the username and password that I’ve sent as variables when I created the new application.

And now I can query the data:

$ oc exec -it mongodb-1-jzsgf -- bash -c "mongo -u sagy -p password testdb --eval \"db.redhat.find().pretty()\""
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/testdb
MongoDB server version: 3.6.3
{
"_id" : ObjectId("5cef5b7cd98cc7661f114679"),
"name" : "Red Hat Enterprise Linux",
"product_name" : "RHEL",
"type" : "linux-x86_64",
"release_date" : "05/08/2019",
"version" : 8
}
{
"_id" : ObjectId("5cef5b7cd98cc7661f11467a"),
"name" : "Red Hat Enterprise Linux",
"product_name" : "RHEL",
"type" : "linux-x86_64",
"release_date" : "05/08/2014",
"version" : 7
}
{
"_id" : ObjectId("5cef5b7cd98cc7661f11467b"),
"name" : "Red Hat Enterprise Linux",
"product_name" : "RHEL",
"type" : "linux-x86_64",
"release_date" : "05/08/2011",
"version" : 6
}

Conclusion

In this blog post about MongoDB on OpenShift Container Storage blog series I’ve shown how to create a new MongoDB template based on the default MongoDB template provided by OpenShift Container Platform. I have also explained how to modify this new template so that it will use OpenShift Container Storage as the provider of the persistent storage claim for the database.

In the next blog post I will concentrate on running the same app in a multi-tenant fashion and also run some performance testing using Yahoo Cloud Serving Benchmark (YCSB).