Connecting to a Database

In this section we will deploy and connect a MongoDB database where the nationalparks application will store location information.

Finally, we will mark the nationalparks application as a backend for the map visualization tool, so that it can be dynamically discovered by the parksmap component using the OpenShift discovery mechanism and the map will be displayed automatically.

Application architecture

Background: Storage

Most useful applications are "stateful" or "dynamic" in some way, and this is usually achieved with a database or other data storage. In this lab we are going to add MongoDB to our nationalparks application and then rewire it to talk to the database using environment variables via a secret.

We are going to use the MongoDB image that is included with OpenShift.

By default, this will use EmptyDir for data storage, which means if the Pod disappears the data does as well. In a real application you would use OpenShift’s persistent storage mechanism to attach real-world storage (NFS, Ceph, EBS, iSCSI, etc) to the Pods to give them a persistent place to store their data.

Background: Templates

In this module we will create MongoDB from a Template, which is useful mechanism in OpenShift to define parameters for certain values, such as DB username or password, that can be automatically generated by OpenShift at processing time.

Administrators can load Templates into OpenShift and make them available to all users. Users can create Templates and load them into their own Projects for other users (with access) to share and use.

The great thing about Templates is that they can speed up the deployment workflow for application development by providing a "recipe" of sorts that can be deployed with a single command. Not only that, they can be loaded into OpenShift from an external URL, which will allow you to keep your templates in a version control system.

Exercise: Create a MongoDB Template

If you are using Developer Sandbox for Red Hat OpenShift, you can skip this section and jump to the next one called Exercise: Deploy MongoDB because MongoDB Template it’s already available on Developer Sandbox.

In this step we will create a MongoDB template inside our project, so that is only visible to our user and we can access it from Developer Perspective to create a MongoDB instance.

oc create -f https://raw.githubusercontent.com/openshift-labs/starter-guides/ocp-4.8/mongodb-template.yaml -n %PROJECT%

What just happened? What did you just create? The item that we passed to the create command is a Template. create simply makes the template available in your Project.

If you are runnning OKD the mongodb image is missing and you will need to provide it.
oc import-image mongodb:3.6 --from=registry.access.redhat.com/rhscl/mongodb-36-rhel7 --confirm

Exercise: Deploy MongoDB

As you’ve seen so far, the web console makes it very easy to deploy things onto OpenShift. When we deploy the database, we pass in some values for configuration. These values are used to set the username, password, and name of the database.

The database image is built in a way that it will automatically configure itself using the supplied information (assuming there is no data already present in the persistent storage!). The image will ensure that:

  • A database exists with the specified name

  • A user exists with the specified name

  • The user can access the specified database with the specified password

In the Developer Perspective in your %PROJECT% project, click +Add and then Database. In the Databases view, you can click Mongo to filter for just MongoDB.

Make sure to uncheck Operator Backed option from Type section
Data Stores

Alternatively, you could type mongodb in the search box. Once you have drilled down to see MongoDB, find the MongoDB (Ephemeral) template and select it. You will notice that there are multiple MongoDB templates available. We do not need a database with persistent storage, so the ephemeral Mongo template is what you should choose. Go ahead and select the ephemeral template and click the Instantiate Template button.

When we performed the application build, there was no template. Rather, we selected the builder image directly and OpenShift presented only the standard build workflow. Now we are using a template - a preconfigured set of resources that includes parameters that can be customized. In our case, the parameters we are concerned with are — user, password, database, and admin password.

MongoDB Deploy
Make sure you name your database service name mongodb-nationalparks

You can see that some of the fields say "generated if empty". This is a feature of Templates in OpenShift. For now, be sure to use the following values in their respective fields:

Database Service Name:

mongodb-nationalparks

MongoDB Connection Username:

mongodb

MongoDB Connection Password:

mongodb

MongoDB Database Name:

mongodb

MongoDB Admin Password:

mongodb
Make sure to have configured the MongoDB Database Name parameter with the appropriate value as by default it will already have a value of sampledb.

Once you have entered in the above information, click on Create to go to the next step which will allow us to add a binding.

From left-side menu, click to Secrets.

List Secrets

Click the secret name listed that we will use for Parameters. The secret can be used in other components, such as the nationalparks backend, to authenticate to the database.

Now that the connection and authentication information stored in a secret in our project, we need to add it to the nationalparks backend. Click the Add Secret to Workload button.

National Parks Binding

Select the nationalparks workload and click Save.

Add binding to application

This change in configuration will trigger a new deployment of the nationalparks application with the environment variables properly injected.

Back in the Topology view, if your mongodb-nationalparks component is not already in the light gray area that denotes the workshop application, click and drag the component whilst holding down Shift to add it to the group with the other two components (as shown below)

Add mongodb to the workshop app

Next, let’s fix the labels assigned to the mongodb-nationalparks deployment. Currently, we cannot set labels when using the database template from the catalog, so we will fix these labels manually.

Like before, we’ll add 3 labels:

The name of the Application group:

app=workshop

Next the name of this deployment.

component=nationalparks

And finally, the role this component plays in the overall application.

role=database

Execute the following command:

oc label dc/mongodb-nationalparks svc/mongodb-nationalparks app=workshop component=nationalparks role=database --overwrite

Exercise: Exploring OpenShift Magic

As soon as we attached the Secret to the Deployment, some magic happened. OpenShift decided that this was a significant enough change to warrant updating the internal version number of the ReplicaSet. You can verify this by looking at the output of oc get rs:

NAME                       DESIRED   CURRENT   READY   AGE
nationalparks-58bd4758fc   0         0         0       4m58s
nationalparks-7445576cd9   0         0         0       6m42s
nationalparks-789c6bc4f4   1         1         1       41s
parksmap-57df75c46d        1         1         1       8m24s
parksmap-65c4f8b676        0         0         0       18m

We see that the DESIRED and CURRENT number of instances for the current deployment. The desired and current number of the other instances are 0. This means that OpenShift has gracefully torn down our "old" application and stood up a "new" instance.

Exercise: Data, Data, Everywhere

Now that we have a database deployed, we can again visit the nationalparks web service to query for data:

https://nationalparks-%PROJECT%.%CLUSTER_SUBDOMAIN%/ws/data/all

And the result?

[]

Where’s the data? Think about the process you went through. You deployed the application and then deployed the database. Nothing actually loaded anything INTO the database, though.

The application provides an endpoint to do just that:

https://nationalparks-%PROJECT%.%CLUSTER_SUBDOMAIN%/ws/data/load

And the result?

Items inserted in database: 2893

If you then go back to /ws/data/all you will see tons of JSON data now. That’s great. Our parks map should finally work!

There are some errors reported with browsers like Firefox 54 that don’t properly parse the resulting JSON. It’s a browser problem, and the application is working properly.
https://parksmap-%PROJECT%.%CLUSTER_SUBDOMAIN%

Hmm…​ There’s just one thing. The main map STILL isn’t displaying the parks. That’s because the front end parks map only tries to talk to services that have the right Label.

You are probably wondering how the database connection magically started working? When deploying applications to OpenShift, it is always best to use environment variables, secrets, or configMaps to define connections to dependent systems. This allows for application portability across different environments. The source file that performs the connection as well as creates the database schema can be viewed here:

http://www.github.com/openshift-roadshow/nationalparks/blob/master/src/main/java/com/openshift/evg/roadshow/parks/db/MongoDBConnection.java#L44-l48

In short summary: By referring to bindings to connect to services (like databases), it can be trivial to promote applications throughout different lifecycle environments on OpenShift without having to modify application code.

Exercise: Working With Labels

We explored how a Label is just a key=value pair earlier when looking at Services and Routes and Selectors. In general, a Label is simply an arbitrary key=value pair. It could be anything.

  • pizza=pepperoni

  • pet=dog

  • openshift=awesome

In the case of the parks map, the application is actually querying the OpenShift API and asking about the Routes and Services in the project. If any of them have a Label that is type=parksmap-backend, the application knows to interrogate the endpoints to look for map data. You can see the code that does this here.

Fortunately, the command line provides a convenient way for us to manipulate labels. describe the nationalparks service:

oc describe route nationalparks
Name:                   nationalparks
Namespace:              %PROJECT%
Created:                2 hours ago
Labels:                 app=workshop
                        app.kubernetes.io/component=nationalparks
                        app.kubernetes.io/instance=nationalparks
                        app.kubernetes.io/name=java
                        app.kubernetes.io/part-of=workshop
                        app.openshift.io/runtime=java
                        app.openshift.io/runtime-version=11
                        component=nationalparks
                        role=backend
Annotations:            openshift.io/host.generated=true
Requested Host:         nationalparks-%PROJECT%.%CLUSTER_SUBDOMAIN%
                        exposed on router router 2 hours ago
Path:                   <none>
TLS Termination:        <none>
Insecure Policy:        <none>
Endpoint Port:          8080-tcp

Service:                nationalparks
Weight:                 100 (100%)
Endpoints:              10.1.9.8:8080

You see that it already has some labels. Now, use oc label:

oc label route nationalparks type=parksmap-backend

You will see something like:

route.route.openshift.io/nationalparks labeled

If you check your browser now:

https://parksmap-%PROJECT%.%CLUSTER_SUBDOMAIN%/
MongoDB

You’ll notice that the parks suddenly are showing up. That’s really cool!