Skip to main content

Binding to a database service without the Service Binding Operator

ยท 8 min read

How to bind your application to a database service without the Service Binding Operator.

There are a few ways of binding your application to a database service with the help of odo. The recommended way is with the help of Service Binding Operator(SBO), but it is also possible to bind without it, and this blog will show you how.

Architectureโ€‹

We have a simple CRUD application built in Go that can create/list/update/delete a place. This application requires connecting to a MongoDB database in order to function correctly, which will be deployed as a microservice on the cluster.

Prerequisites:โ€‹

This blog assumes:

(Optional) Setting up the namespaceโ€‹

  1. We will create a new namespace to deploy our application in, with the help of odo.
odo create namespace restapi-mongodb

Setting up the MongoDB microserviceโ€‹

We are going to use the Bitnami's helm charts for creating our MongoDB database.

  1. Add the Bitnami's Helm charts repository and make your Helm client up to date with it:
helm repo add bitnami https://charts.bitnami.com/bitnami && helm repo update
  1. Declare the necessary environment variables:
MY_MONGODB_ROOT_USERNAME=root
MY_MONGODB_ROOT_PASSWORD=my-super-secret-root-password
MY_MONGODB_USERNAME=my-app-username
MY_MONGODB_PASSWORD=my-app-super-secret-password
MY_MONGODB_DATABASE=my-app

Make sure MY_MONGODB_ROOT_USERNAME, and MY_MONGODB_ROOT_PASSWORD are declared/exported in any new terminal session from where you might run an odo command for this application.

  1. Create the MongoDB service.
helm install mongodb bitnami/mongodb \
--set auth.rootPassword=$MY_MONGODB_ROOT_PASSWORD \
--set auth.username=$MY_MONGODB_USERNAME \
--set auth.password=$MY_MONGODB_PASSWORD \
--set auth.database=$MY_MONGODB_DATABASE
Expected output:
$ helm install mongodb bitnami/mongodb \
--set auth.rootPassword=$MY_MONGODB_ROOT_PASSWORD \
--set auth.username=$MY_MONGODB_USERNAME \
--set auth.password=$MY_MONGODB_PASSWORD \
--set auth.database=$MY_MONGODB_DATABASE
NAME: mongodb
LAST DEPLOYED: Tue Jul 5 15:53:40 2022
NAMESPACE: restapi-mongodb
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: mongodb
CHART VERSION: 12.1.24
APP VERSION: 5.0.9

** Please be patient while the chart is being deployed **

MongoDB® can be accessed on the following DNS name(s) and ports from within your cluster:

mongodb.restapi-mongodb.svc.cluster.local

To get the root password run:

export MONGODB_ROOT_PASSWORD=$(kubectl get secret --namespace restapi-mongodb mongodb -o jsonpath="{.data.mongodb-root-password}" | base64 -d)

To get the password for "my-app-username" run:

export MONGODB_PASSWORD=$(kubectl get secret --namespace restapi-mongodb mongodb -o jsonpath="{.data.mongodb-passwords}" | base64 -d | awk -F'
,' '{print $1}')

To connect to your database, create a MongoDB® client container:

kubectl run --namespace restapi-mongodb mongodb-client --rm --tty -i --restart='Never' --env="MONGODB_ROOT_PASSWORD=$MONGODB_ROOT_PASSWORD" --
image docker.io/bitnami/mongodb:5.0.9-debian-11-r1 --command -- bash

Then, run the following command:
mongosh admin --host "mongodb" --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD

To connect to your database from outside the cluster execute the following commands:

kubectl port-forward --namespace restapi-mongodb svc/mongodb 27017:27017 &
mongosh --host 127.0.0.1 --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD

Notice the resources(sevice, deployment, and secrets) that are deployed.

Wait for the pods to come up, this might take a few minutes:

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mongodb-85fff797f6-fnwvl 1/1 Running 0 63s

Setting up the applicationโ€‹

  1. Clone the repository, and cd into it.
git clone https://github.com/valaparthvi/restapi-mongodb-odo.git && cd restapi-mongodb-odo

Download the devfile.yamlโ€‹

  1. Run odo init to fetch the necessary devfile.
odo init --devfile go --name places
Expected output:
  __
/ \__ Initializing new component
\__/ \ Files: Source code detected, a Devfile will be determined based upon source code autodetection
/ \__/ odo version: v3.0.0-beta1
\__/

Interactive mode enabled, please answer the following questions:
โœ“ Downloading devfile "go" [4s]

Your new component 'places' 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.
If you run odo dev to deploy the application at this point, you will notice that the 'run' command has failed with some logs, this is expected, because like we mentioned before, our Go application is dependent on the MongoDB service and will not function unless it is connected to it.
$ odo dev
__
/ \__ Developing using the restapi Devfile
\__/ \ Namespace: restapi-mongodb
/ \__/ odo version: v3.0.0-alpha3
\__/

โ†ช Deploying to the cluster in developer mode
โœ“ Waiting for Kubernetes resources [52s]
โœ“ Syncing files into the container [844ms]
โœ“ Building your application in container on cluster (command: build) [5s]
โ€ข Executing the application (command: run) ...
โœ— Executing the application (command: run) [188ms]
โš  Devfile command "run" exited with an error status in 20 second(s)
โš  Last 100 lines of log:
go: downloading github.com/sirupsen/logrus v1.8.1
...
...
2022/07/06 10:52:10 No binding username found
- Forwarding from 127.0.0.1:40001 -> 8080

Your application is now running on the cluster

Watching for changes in the current directory /home/pvala/restapi-mongodb-odo
Press Ctrl+c to exit `odo dev` and delete resources from the cluster

Adding the connection information to devfile.yamlโ€‹

There are a few changes that we will need to make to our devfile:

6.1 Change the schemaVersion of devfile to 2.2.0.

schemaVersion: 2.2.0

Please note that this change is only necessary because we are using devfile variable substitution.

6.2 Add a variables field in the devfile.

variables:
PASSWORD: password
USERNAME: user
HOST: host

6.3 Edit the 'runtime' container component in devfile to add information such as username, password, and host required to connect to the MongoDB service.

components:
- container:
...
...
env:
- name: username
value: "{{USERNAME}}"
- name: password
value: "{{PASSWORD}}"
- name: host
value: "{{HOST}}"
name: runtime

The values for username, password, and host will be passed to devfile.yaml with the --var flag when we run the odo dev command.

Your final devfile.yaml should look something like this:
commands:
- exec:
commandLine: GOCACHE=${PROJECT_SOURCE}/.cache go build main.go
component: runtime
group:
isDefault: true
kind: build
hotReloadCapable: false
workingDir: ${PROJECT_SOURCE}
id: build
- exec:
commandLine: ./main
component: runtime
group:
isDefault: true
kind: run
hotReloadCapable: false
workingDir: ${PROJECT_SOURCE}
id: run
components:
- container:
dedicatedPod: false
endpoints:
- name: http
targetPort: 8080
image: golang:latest
memoryLimit: 1024Mi
mountSources: true
env:
- name: username
value: "{{USERNAME}}"
- name: password
value: "{{PASSWORD}}"
- name: host
value: "{{HOST}}"
name: runtime
variables:
PASSWORD: password
USERNAME: user
HOST: host
metadata:
description: Stack with the latest Go version
displayName: Go Runtime
icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg
language: go
name: restapi
projectType: go
tags:
- Go
version: 1.0.0
schemaVersion: 2.2.0
starterProjects:
- git:
checkoutFrom:
revision: main
remotes:
origin: https://github.com/devfile-samples/devfile-stack-go.git
name: go-starter

Deploy the applicationโ€‹

  1. Run odo dev to deploy the application on the cluster.
odo dev \
--var PASSWORD=$MY_MONGODB_ROOT_PASSWORD \
--var USERNAME=$MY_MONGODB_ROOT_USERNAME \
--var HOST="mongodb"

The value for host is name of the service that belongs to our database application, in this case it is a service resource called "mongodb", you might have noticed it when we deployed the helm chart.

Expected output:
$ odo dev --var PASSWORD=$MY_MONGODB_ROOT_PASSWORD --var USERNAME=$MY_MONGODB_ROOT_USERNAME --var HOST="mongodb"
__
/ \__ Developing using the restapi Devfile
\__/ \ Namespace: restapi-mongodb
/ \__/ odo version: v3.0.0-alpha3
\__/

โ†ช Deploying to the cluster in developer mode
โœ“ Waiting for Kubernetes resources [52s]
โœ“ Syncing files into the container [844ms]
โœ“ Building your application in container on cluster (command: build) [5s]
โ€ข Executing the application (command: run) ...

Your application is now running on the cluster

- Forwarding from 127.0.0.1:40001 -> 8080

Watching for changes in the current directory /home/pvala/restapi-mongodb-odo
Press Ctrl+c to exit `odo dev` and delete resources from the cluster

Accessing the applicationโ€‹

  1. Run the following curl command to test the application:
curl 127.0.0.1:40001/api/places

This will return a null response since the database is currently empty, but it also means that we have successfully connected to our database application.

  1. Add some data to the database:
curl -sSL -XPOST -d '{"title": "Agra", "description": "Land of Tajmahal"}' 127.0.0.1:40001/api/places
  1. Fetch the list of places again:
$ curl 127.0.0.1:40001/api/places

{"id":"62c2a0659fa147e382a4db31","title":"Agra","description":"Land of Tajmahal"}

List of available API endpointsโ€‹

  • GET /api/places - List all places
  • POST /api/places - Add a new place
  • PUT /api/places - Update a place
  • GET /api/places/<id> - Fetch place with id <id>
  • DELETE /api/places/<id> - Delete place with id <id>

Conclusionโ€‹

To conclude this blog, it is possible to connect your application with another microservice without the Service Binding Operator if you have the correct connection information. Using the Service Binding Operator with a Bindable Operator makes it easy for you to not care about finding the connection information and ease the binding.