Featured image: 5 step API management.

This article concludes a two-part series about deploying a REST API application and binding it to a MongoDB using odo and a Service Binding Operator. Part 1, Set up an OpenShift cluster to deploy an application in odo CLI, explained the value of odo in managing a cluster and the applications in it. In that article, we installed both odo and the Service Binding Operator. Now you will learn how those tools easily create an instance of a database and a binding (connection) between the application and database.

Set up the application and database in 7 steps

Previously, we completed the prerequisites. Now we will demonstrate how to use odo to bind the REST application to the MongoDB database through the Service Binding Operator.

Follow these 7 steps:

Step 1: Get the application sources

Clone the application from the main repository:

$ git clone https://github.com/redhat-developer/openshift-app-services-demos.git --depth 1
Cloning into 'openshift-app-services-demos'...
remote: Enumerating objects: 219, done.
remote: Counting objects: 100% (119/119), done.
remote: Compressing objects: 100% (98/98), done.
remote: Total 219 (delta 18), reused 101 (delta 9), pack-reused 100
Receiving objects: 100% (219/219), 185.55 KiB | 2.02 MiB/s, done.
Resolving deltas: 100% (39/39), done.

Then, change directory to the project's one:

$ cd openshift-app-services-demos/samples/sbo/restapi-mongodb-odo/

 

Step 2: Create an odo component for the application

To create an odo component, use the odo init command. This command detects the application type and creates a devfile.yaml file.

In our case, we will change the port to match the port mentioned in the config.yaml file by performing the following steps in the interactive CLI:

  1. To confirm that you allow the installation of the application, enter Yes.
  2. To specify or change the container configurations, choose runtime.
  3. To get access to the port, choose the following configurations to match the port configured in the config.yaml file:
    1. Delete port 8080.

    2. Add the new port, with the value 3000.

  4. Proceed with NONE-configuration is correct when you are done specifying all the configuration changes.
  5. When prompted, enter the name of the application: For this demo, it is my-go-app.
$ odo init
  __
 /  \__     Initializing new component
 \__/  \    Files: Source code detected, a Devfile will be determined based upon source code autodetection
 /  \__/    odo version: v3.0.0
 \__/

Interactive mode enabled, please answer the following questions:
Based on the files in the current directory odo detected
Language: Go
Project type: Go
The devfile "go" from the registry "DefaultDevfileRegistry" will be downloaded.
? Is this correct? Yes
 ✓  Downloading devfile "go" from registry "DefaultDevfileRegistry" [2s]

↪ Container Configuration "runtime":
  OPEN PORTS:
    - 8080
  ENVIRONMENT VARIABLES:

? Select container for which you want to change configuration? runtime
? What configuration do you want change? Delete port "8080"
? What configuration do you want change? Add new port
 ⚠  Please ensure that you do not add a duplicate port number
? Enter port number: 3000
? What configuration do you want change? NOTHING - configuration is correct

↪ Container Configuration "runtime":
  OPEN PORTS:
    - 3000
  ENVIRONMENT VARIABLES:

? Select container for which you want to change configuration? NONE - configuration is correct
? Enter component name: my-go-app

Your new component 'my-go-app' is ready in the current directory.
To start editing your component, use 'odo dev' and open this folder in your favorite IDE.
Changes will be directly reflected on the cluster.

Your new component is now ready in the current directory. Verify that the odo component is created by listing the components:

$ odo list
✓  Listing resources from the namespace "mongodb-restapi" [295ms]

Components:
NAME              PROJECT TYPE  RUNNING IN  MANAGED
* my-go-app       Go            None        Unknown

Bindings:
✗  There are no service bindings in the "mongodb-restapi" namespace.

A devfile.yaml file is created in the same folder (restapi-mongodb-odo). You can look through this folder to understand the configurations the application is running with.

 

Step 3: Create the MongoDB service

To create a MongoDB database service, create an instance of the MongoDB database by using the mongo-cluster.yaml file that is available as part of the repository you cloned. The mongo-cluster.yaml file is a default MongoDB instance creation file:

$ oc apply -f mongo-cluster.yaml
perconaservermongodb.psmdb.percona.com/mongodb-instance created

If the MongoDB installation is successful, some pods will come up. It may take a while. Use the following command to check for pods:

$ oc get pods -n mongodb-restapi
NAME                                               READY   STATUS    RESTARTS      AGE
mongodb-instance-cfg-0                             0/1     Running   0             18s
mongodb-instance-mongos-67b779869d-k4c6h           0/1     Running   0             17s
mongodb-instance-rs0-0                             0/1     Running   0             18s
percona-server-mongodb-operator-6dc568f4bc-f6cq9   1/1     Running   7 (28m ago)   137m

You have now installed a service for the Percona MongoDB distribution.

 

Step 4: Bind the service and application

We can now use the command odo add binding to define a binding between the application. This binding, once published, will allow the application to communicate with the database.

$ odo add binding --service mongodb-instance.PerconaServerMongoDB.psmdb.percona.com --name my-go-app-mongodb-instance

✓  Successfully added the binding to the devfile.
Run `odo dev` to create it on the cluster.

The command adds the binding details to the devfile.yaml file. The binding information is in the .components.kubernetes section of this file. That section contains the names of the application and service and the kind of Kubernetes resource added to devfile.yaml:

components:
    components:
    - kubernetes:
        inlined: |
          apiVersion: binding.operators.coreos.com/v1alpha1
          kind: ServiceBinding
          metadata:
             name: my-go-app-mongodb-instance
          spec:
             application:
               group: apps
               name: my-go-app-app
               resource: deployments
               version: v1
             bindAsFiles: true
             detectBindingResources: true
             services:
             - group: psmdb.percona.com
               id: my-go-app-mongodb-instance
               kind: PerconaServerMongoDB
               name: mongodb-instance
               resource: perconaservermongodbs
               version: v1-12-0
        name: my-go-app-mongodb-instance

 

Step 5: Create the application

Use the devfile.yaml file created earlier to create the application by running the following command:

$ odo dev
  __
 /  \__     Developing using the my-go-app Devfile
 \__/  \    Namespace: mongodb-restapi
 /  \__/    odo version: v3.0.0
 \__/

↪ Deploying to the cluster in developer mode
 •  Waiting for Kubernetes resources  ...
 ✓  Creating kind ServiceBinding
 ⚠  Pod is Pending
 ⚠  Pod is Terminating
 ⚠  No pod exists
 ⚠  Pod is Pending
 ✓  Pod is Running
 ✓  Syncing files into the container [163ms]
 ✓  Building your application in container on cluster (command: build) [32s]
 •  Executing the application (command: run)  ...
 -  Forwarding from 127.0.0.1:40001 -> 3000


↪ Dev mode
 Status:
 Watching for changes in the current directory /tmp/openshift-app-services-demos/samples/sbo/restapi-mongodb-odo

 Keyboard Commands:
[Ctrl+c] - Exit and delete resources from the cluster
     [p] - Manually apply local changes to the application on the cluster
Pushing files...


File /tmp/openshift-app-services-demos/samples/sbo/restapi-mongodb-odo/.odo changed
 •  Waiting for Kubernetes resources  ...
 ✓  Syncing files into the container [11ms]

↪ Dev mode
 Status:
 Watching for changes in the current directory /tmp/openshift-app-services-demos/samples/sbo/restapi-mongodb-odo

 Keyboard Commands:
[Ctrl+c] - Exit and delete resources from the cluster
     [p] - Manually apply local changes to the application on the cluster

The command deploys the application in developer mode.

 

Step 6: Check the Service Binding status

You can check whether the Service Binding Operator has actually created a working connection through the following command:

$ oc get servicebinding -n mongodb-restapi
NAME                         READY   REASON              AGE
my-go-app-mongodb-instance   True    ApplicationsBound   2m45s

Here, my-go-app-mongodb-instance is the Service Binding resource that was created.

This Service Binding resource manages the binding data values from the database and projects them into the application's container as files.

To see the details of the application pod that was created, enter the same command used before:

$ oc get pods -n mongodb-restapi
NAME                                               READY   STATUS    RESTARTS      AGE
mongodb-instance-cfg-0                             1/1     Running   0             5m4s
mongodb-instance-mongos-67b779869d-k4c6h           1/1     Running   0             5m3s
mongodb-instance-rs0-0                             1/1     Running   0             5m4s
my-go-app-app-799546f4f6-sbtf7                     1/1     Running   0             2m38s
percona-server-mongodb-operator-6dc568f4bc-f6cq9   1/1     Running   7 (33m ago)   142m

To see the content of the Service Binding that was created, enter the following command:

$ oc get servicebinding -n mongodb-restapi my-go-app-mongodb-instance -o yaml

apiVersion: binding.operators.coreos.com/v1alpha1
kind: ServiceBinding
metadata:
  annotations:
    odo.dev/project-type: Go
  finalizers:
  - finalizer.servicebinding.openshift.io
  labels:
    app: app
    app.kubernetes.io/instance: my-go-app
    app.kubernetes.io/managed-by: odo
    app.kubernetes.io/managed-by-version: v3.0.0
    app.kubernetes.io/part-of: app
    app.openshift.io/runtime: Go
    odo.dev/mode: Dev
  name: my-go-app-mongodb-instance
  namespace: mongodb-restapi
spec:
  application:
    group: apps
    kind: Deployment
    name: my-go-app-app
    version: v1
  bindAsFiles: true
  detectBindingResources: true
  services:
  - group: psmdb.percona.com
    id: my-go-app-mongodb-instance
    kind: PerconaServerMongoDB
    name: mongodb-instance
    resource: perconaservermongodbs
    version: v1-12-0
status:
  conditions:
  - lastTransitionTime: "2022-10-25T16:15:19Z"
    message: ""
    reason: ApplicationsBound
    status: "True"
    type: Ready
  - lastTransitionTime: "2022-10-25T16:15:19Z"
    message: ""
    reason: DataCollected
    status: "True"
    type: CollectionReady
  - lastTransitionTime: "2022-10-25T16:15:19Z"
    message: ""
    reason: ApplicationUpdated
    status: "True"
    type: InjectionReady
  secret: my-go-app-mongodb-instance-654af1d6

The following excerpt of the output shows which application is bound to which service:

apiVersion: binding.operators.coreos.com/v1alpha1
kind: ServiceBinding
metadata:
  name: my-go-app-mongodb-instance
  namespace: mongodb-restapi
spec:
  application:
    group: apps
    kind: Deployment
    name: my-go-app-app
    version: v1
  bindAsFiles: true
  detectBindingResources: true
  services:
  - group: psmdb.percona.com
    id: my-go-app-mongodb-instance
    kind: PerconaServerMongoDB
    name: mongodb-instance
    resource: perconaservermongodbs
    version: v1-12-0

The output also shows the secret ( my-go-app-mongodb-instance-654af1d6) that was created and added to the Service binding resource, and the details of the Service Binding.

apiVersion: binding.operators.coreos.com/v1alpha1
kind: ServiceBinding
...
status:
    conditions:
    - lastTransitionTime: "2022-10-25T16:15:19Z"
        message: ""
        reason: ApplicationsBound
        status: "True"
        type: Ready
    - lastTransitionTime: "2022-10-25T16:15:19Z"
        message: ""
        reason: DataCollected
        status: "True"
        type: CollectionReady
    - lastTransitionTime: "2022-10-25T16:15:19Z"
        message: ""
        reason: ApplicationUpdated
        status: "True"
        type: InjectionReady
    secret: my-go-app-mongodb-instance-654af1d6

The following list shows Boolean parameters and what a true status indicates:

  • CollectionReady: The service can collect and persist intermediate manifests.
  • InjectionReady: The application manifests can use the intermediate manifests.
  • Ready: The application is bound successfully to the backing service.

To see the secret mounted in the pod, you can check the .spec.volumes section of the YAML (the output is truncated for brevity):

$ oc get pods $(oc get pods -l "app.kubernetes.io/instance=my-go-app" -o jsonpath='{.items[0].metadata.name}') -o yaml

apiVersion: v1
kind: Pod
metadata:
...
    labels:
    app: app
    app.kubernetes.io/instance: my-go-app
    app.kubernetes.io/managed-by: odo
    app.kubernetes.io/managed-by-version: v3.0.0
    app.kubernetes.io/part-of: app
    app.openshift.io/runtime: Go
    component: my-go-app
    odo.dev/mode: Dev
    pod-template-hash: 856d6c49c6
    name: my-go-app-app-856d6c49c6-kf8mv
    namespace: mongodb-restapi
...
spec:
...
    volumes:
...
    - name: my-go-app-mongodb-instance
    secret:
        defaultMode: 420
        secretName: my-go-app-mongodb-instance-2a4a6313
...    

 

Step 7: Check the application status

The published application offers the following ​RESTful API endpoints to perform operations on places:

  • GET (List all places): /api/places
  • POST (Add a new place): /api/places
  • PUT (Update a place): /api/places
  • GET (Fetch place with the ID <id>): /api/places/<id>
  • DELETE (Delete place with the ID <id>): /api/places/<id>

You can interact with the running application either through the curl command in the CLI or through the OpenShift UI.

In both cases, you need to know the URL of the application. You can find the application URL in the logs of the odo dev command. More precisely, you have to look for a line that says "- Forwarding from 127.0.0.1:; -> 3000".

In the following we assume it is published on 127.0.0.1:40001.

$ curl -sSl 127.0.0.1:40001/api/places
null%

If the command is successful, the returned output is null.

To check the application in the user interface (UI), enter the URL 127.0.0.1:40001/api/places  into a browser of your choice. It should show null.

The null response verifies that you have successfully created the application and that it is connected to the MongoDB database service. You can invoke the application to add and change data in the database.

In the following some examples using the API:

  • POST:

    $ curl -sSL -XPOST -d '{"title":"Chennai","description":"Land of Beaches"}' 127.0.0.1:40001/api/places
    {"id":"635925095e12c04bfdc74ea6","title":"Chennai","description":"Land of Beaches"}%
    
  • GET:

    $ curl -sSl 127.0.0.1:40001/api/places
    [{"id":"635925095e12c04bfdc74ea6","title":"Chennai","description":"Land of Beaches"}]%    
    
  • DELETE: Perform this command with the id that was generated on adding the entry.

    $ curl -sSL -XDELETE 127.0.0.1:40001/api/places/635925095e12c04bfdc74ea6
    
    

 

odo and the Service Binding Operator provide convenience and safety

This list outlines the benefits of using the odo CLI with the Service Binding Operator to bind a service to an application:

  • It enables you to connect your applications to backing services with a consistent and predictable experience.

  • It eliminates the error-prone manual configuration of binding information.
  • The interactive CLI helps you understand how to create and bind applications.
  • It is easier than manually writing a service-binding.yaml file to create the binding.

Comments