Connecting PetClinic application to an Operator-backed PostgreSQL database

pgcluster spring boot

In this configuration, we leverage the Service Binding Operator to collect the binding data from the PostgreSQL database and to project them into the Spring PetClinic application.

The PostgreSQL database in this scenario is deployed using the PostgresCluster resource provided by the Crunchy Postgres Operator from Crunchy Data that requires the Operator Lifecycle Manager (OLM) to install and manage.

This scenario involves the following procedures:

Creating a PostgreSQL database instance

This scenario uses a PostgreSQL database service, which you must install using the Operator Lifecycle Manager (OLM).

Prerequisites

The installation of the Crunchy PostgreSQL Operator does not create a database instance. To create a database service instance, you must create the following custom resource (CR), which will be processed by the Operator:

PostgresCluster resource to run the actual database instance

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
spec:
  image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.6-2
  postgresVersion: 14
  instances:
    - name: instance1
      dataVolumeClaimSpec:
        accessModes:
        - "ReadWriteOnce"
        resources:
          requests:
            storage: 1Gi
  backups:
    pgbackrest:
      image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.41-2
      repos:
      - name: repo1
        volume:
          volumeClaimSpec:
            accessModes:
            - "ReadWriteOnce"
            resources:
              requests:
                storage: 1Gi

Procedure

  1. To create a database instance, create a PostgresCluster CR by running the following command:

  2. After the database is created, verify that all the pods in the my-petclinic namespace are running (it will take a few minutes):

    kubectl get pods -n my-petclinic
    Example output:
    NAME                      READY   STATUS      RESTARTS   AGE
    hippo-backup-bthn-p6xmn   0/1     Completed   0          16s
    hippo-instance1-jqpz-0    4/4     Running     0          99s
    hippo-repo-host-0         2/2     Running     0          99s

    The previous output verifies that the database service is created and configured.

Now, after the database is configured for the application, you can deploy the application and connect it to the database service.

Deploying the Spring PetClinic application

To deploy the Spring PetClinic application on our Kubernetes cluster, use a deployment configuration consisting of the following resources:

Deployment resource to run the actual application instance

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-petclinic
  labels:
    app: spring-petclinic
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spring-petclinic
  template:
    metadata:
      labels:
        app: spring-petclinic
    spec:
      containers:
        - name: app
          image: quay.io/service-binding/spring-petclinic:latest
          imagePullPolicy: Always
          env:
          - name: SPRING_PROFILES_ACTIVE
            value: postgres
          ports:
          - name: http
            containerPort: 8080

Service resource to provide a way to access the application UI

apiVersion: v1
kind: Service
metadata:
  labels:
    app: spring-petclinic
  name: spring-petclinic
spec:
  type: NodePort
  ports:
    - port: 80
      protocol: TCP
      targetPort: 8080
  selector:
    app: spring-petclinic

Procedure

  1. Create the application resources by running the following command:

  2. At this stage, the application is not yet connected to the database service. Hence the pod fails to start. To verify run the following command:

    kubectl get pods -n my-petclinic
    Example output:
    NAME                                 READY  STATUS            RESTARTS    AGE
    spring-petclinic-5d47b7dbcd-7zd8v    0/1    CrashLoopBackOff  1 (7s ago)  28s

You can now use the Service Binding Operator to connect the application to the database service.

Connecting the application to the database service with Service Binding Operator

In the absence of the Service Binding Operator, as an administrator of the application, you must perform the following steps manually to extract all the configuration details, create a Secret resource, and expose it to the application through a volume mount in Kubernetes:

  1. Identify the required values for connecting the application to the database.

  2. Locate the resources where the values are present.

  3. Take the values from different resources and create a Secret resource.

  4. Mount the Secret resource into the application.

  5. Depending on the application requirement expose the values as environment variables or files.

To leverage the Service Binding Operator as a way to easily and safely connect the sample application to the database service, you must create a ServiceBinding custom resource (CR) that triggers the Service Binding Operator to project the binding data into the application:

ServiceBinding resource to project the binding data

apiVersion: binding.operators.coreos.com/v1alpha1
kind: ServiceBinding
metadata:
  name:
    spring-petclinic-pgcluster
spec:
  services:
    - group: postgres-operator.crunchydata.com
      version: v1beta1
      kind: PostgresCluster
      name: hippo
  application:
    name: spring-petclinic
    group: apps
    version: v1
    resource: deployments

The .spec field of the ServiceBinding CR has two sections:

  • The first section is a list of service resources (.spec.services). The services resources point to the database service resources. For more information on how the values are exposed from the service resources, see the Exposing binding data section.

  • The second section is the application (.spec.application). The application points to a Deployment or any resource that is compliant with PodSpec.

Procedure

  1. Create the ServiceBinding CR by running the following command in shell:

  2. Verify that the request for service binding is successful by running the following command:

    kubectl get servicebindings -n my-petclinic
    Example output:
    NAME                          READY   REASON              AGE
    spring-petclinic-pgcluster   True    ApplicationsBound   28s

    By creating this ServiceBinding resource, we now have the binding data values from the database that is to be projected into the application container as files, by default. Alternatively, you can also choose to project the binding data values as environment variables if you prefer. If you check under the /bindings/spring-petclinic-pgcluster directory, you can see all the values from the Secret resource projected there.

    In the case of the previous example, you can find username and password as the projected values. The values pointed out through the annotation are also projected, such as the database, host, and port values. For connectivity, the type value is projected as the binding data.

    The application looks for the SERVICE_BINDING_ROOT environment variable to find the location of the /bindings directory. The Spring Boot application used here uses the Spring Cloud Bindings library and it looks for the SERVICE_BINDING_ROOT environment variable to get the projected binding data. For more information on how an application uses these values, see the Projecting binding data section.

  3. Verify that the binding is successful by setting up the port forwarding from the application port to access the sample application from your local environment:

    kubectl port-forward --address 0.0.0.0 svc/spring-petclinic 8080:80 -n my-petclinic
    Example output:
    Forwarding from 0.0.0.0:8080 -> 8080
  4. Access http://localhost:8080.

    You can now remotely access web UI of the application and see that the application is now connected to the database service.

For more information on creating requests for service binding, see the Creating service binding section.

Conclusion

In this scenario, we set up an Operator-backed PostgreSQL database and connected it to the Spring PetClinic application using the Service Binding Operator to collect the binding data and expose them to the application.

Next Steps

By using service bindings, developers are able to more easily leverage the services available to them on a Kubernetes cluster. This method provides consistency across different services and is repeatable for the developers. Service binding provides a unified way to create a binding connection between the application and service and eliminates the need for the usual manual and error-prone configuration.

For more information, see the following sections: