Getting started with service binding

Service Binding Operator manages the data plane for workloads and backing services. This guide provides instructions with examples to help you create a database instance, deploy an application, and use Service Binding Operator to create a binding connection between the application and the database service.

Prerequisites

  • You have access to an OKD cluster using an account with cluster-admin permissions.

  • You have installed the oc CLI.

  • You have installed PostgreSQL psql CLI.

  • You have installed Service Binding Operator from OperatorHub.

  • You have installed the Crunchy Postgres for Kubernetes Operator from OperatorHub using the v5 Update channel. The installed Operator is available in an appropriate namespace, such as the my-postgresql namespace.

Creating a PostgreSQL database instance

To create a PostgreSQL database instance, you must create a PostgresCluster custom resource (CR) and configure the database.

Procedure

  1. Create the PostgresCluster CR and the my-postgresql namespace by running the following command in shell:

    1. $ oc apply -f - << EOD
    2. ---
    3. apiVersion: v1
    4. kind: Namespace
    5. metadata:
    6. name: my-postgresql
    7. ---
    8. apiVersion: postgres-operator.crunchydata.com/v1beta1
    9. kind: PostgresCluster
    10. metadata:
    11. name: hippo
    12. namespace: my-postgresql
    13. annotations:
    14. service.binding: 'path={.metadata.annotations.dbsecret},objectType=Secret'
    15. dbsecret: hippo-pguser-hippo
    16. proxy: hippo-pgbouncer
    17. type: postgresql
    18. service.binding/database: path={.metadata.name}
    19. service.binding/port: path={.spec.port}
    20. service.binding/username: path={.metadata.name}
    21. service.binding/host: path={.metadata.annotations.proxy}
    22. service.binding/type: path={.metadata.annotations.type}
    23. spec:
    24. image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres-ha:centos8-13.4-0
    25. postgresVersion: 13
    26. instances:
    27. - name: instance1
    28. dataVolumeClaimSpec:
    29. accessModes:
    30. - "ReadWriteOnce"
    31. resources:
    32. requests:
    33. storage: 1Gi
    34. backups:
    35. pgbackrest:
    36. image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:centos8-2.33-2
    37. repos:
    38. - name: repo1
    39. volume:
    40. volumeClaimSpec:
    41. accessModes:
    42. - "ReadWriteOnce"
    43. resources:
    44. requests:
    45. storage: 1Gi
    46. - name: repo2
    47. volume:
    48. volumeClaimSpec:
    49. accessModes:
    50. - "ReadWriteOnce"
    51. resources:
    52. requests:
    53. storage: 1Gi
    54. proxy:
    55. pgBouncer:
    56. image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:centos8-1.15-2
    57. EOD

    The annotations added in this PostgresCluster CR help in enabling the service binding connection and trigger the Operator reconciliation.

    The output verifies that the database instance is created:

    Example output

    1. namespace/my-postgresql configured
    2. postgrescluster.postgres-operator.crunchydata.com/hippo created
  2. After you have created the database instance, ensure that all the pods in my-postgresql namespace are running (it will take a few minutes):

    1. $ oc get pods -n my-postgresql

    The output verifies that the database is created:

    Example output

    1. NAME READY STATUS RESTARTS AGE
    2. hippo-backup-6th6--1-28849 0/1 Completed 0 1m
    3. hippo-instance1-sl4r-0 2/2 Running 0 2m
    4. hippo-pgbouncer-8454474bc7-lhcn9 2/2 Running 0 2m

    The new database is empty at this stage. You can set its schema and project a sample data set to interact with the sample application.

  3. Initialize the database with the schema and sample data. To do so, use the following custom shell script by copying the code into the shell and running it:

    1. $ cat << EOD | bash
    2. #!/bin/bash
    3. export pgo_cluster_name=hippo
    4. export cluster_namespace=my-postgresql
    5. export pgo_cluster_username=hippo
    6. export PGPASSWORD=\$(oc -n "\${cluster_namespace}" get secrets \
    7. "\${pgo_cluster_name}-pguser-\${pgo_cluster_username}" -o "jsonpath={.data['password']}" | base64 -d)
    8. nohup oc -n \${cluster_namespace} port-forward svc/hippo-pgbouncer 5432:5432 &
    9. sleep 5
    10. curl -LO https://raw.githubusercontent.com/spring-petclinic/spring-petclinic-rest/master/src/main/resources/db/postgresql/initDB.sql
    11. psql -h localhost -U "\${pgo_cluster_username}" "\${pgo_cluster_name}" -f initDB.sql
    12. curl -LO https://raw.githubusercontent.com/spring-petclinic/spring-petclinic-rest/master/src/main/resources/db/postgresql/populateDB.sql
    13. psql -h localhost -U "\${pgo_cluster_username}" "\${pgo_cluster_name}" -f populateDB.sql
    14. EOD

    The output in the terminal shows you that the database is being configured for the application.

After the database is configured, you can deploy the sample application and connect it to the database service.

Deploying the Spring PetClinic sample application

To deploy the Spring PetClinic sample application on an OKD cluster, you must use a deployment configuration and configure your local environment to be able to test the application.

Procedure

  1. Deploy the spring-petclinic-rest application with the PostgresCluster custom resource (CR) by running the following command in shell:

    1. $ oc apply -f - << EOD
    2. ---
    3. apiVersion: apps/v1
    4. kind: Deployment
    5. metadata:
    6. name: spring-petclinic-rest
    7. namespace: my-postgresql
    8. labels:
    9. app: spring-petclinic-rest
    10. spec:
    11. replicas: 1
    12. selector:
    13. matchLabels:
    14. app: spring-petclinic-rest
    15. template:
    16. metadata:
    17. labels:
    18. app: spring-petclinic-rest
    19. spec:
    20. containers:
    21. - name: application
    22. image: quay.io/baijum/spring-petclinic-rest:latest
    23. env:
    24. - name: SPRING_PROFILES_ACTIVE
    25. value: postgresql,spring-data-jpa
    26. ports:
    27. - name: http
    28. containerPort: 9966
    29. ---
    30. apiVersion: v1
    31. kind: Service
    32. metadata:
    33. name: spring-petclinic-rest
    34. namespace: my-postgresql
    35. spec:
    36. ports:
    37. - port: 80
    38. targetPort: 9966
    39. selector:
    40. app: spring-petclinic-rest
    41. EOD

    The output verifies that the Spring PetClinic sample application is created and deployed:

    Example output

    1. deployment.apps/spring-petclinic-rest created
    2. service/spring-petclinic-rest created
  2. Set up port forwarding from the application port to access the sample application from your local environment:

    1. $ oc port-forward --address 0.0.0.0 svc/spring-petclinic-rest 9966:80 -n my-postgresql
  3. Access http://localhost:9966/petclinic.

    You can now remotely access the Spring PetClinic sample application at localhost:9966.

    The application is not yet connected to the database service. If you try to interact with the application, it will return errors.

    For example, if you try to access the list of all pets using curl, you can see an error message similar to the following sample message:

    1. $ curl -X GET "http://localhost:9966/petclinic/api/pets" -H "accept: application/json"
    2. {"className":"org.springframework.transaction.CannotCreateTransactionException","exMessage":"Could
    3. not open JPA EntityManager for transaction; nested exception is
    4. org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC
    5. Connection"}

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

Connecting the Spring PetClinic sample application to the PostgreSQL database service

To 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.

Procedure

  1. Create a ServiceBinding CR to project the binding data:

    1. $ oc apply -f - << EOD
    2. ---
    3. apiVersion: binding.operators.coreos.com/v1alpha1
    4. kind: ServiceBinding
    5. metadata:
    6. name: spring-petclinic-rest
    7. namespace: my-postgresql
    8. spec:
    9. services: (1)
    10. - group: postgres-operator.crunchydata.com
    11. version: v1beta1
    12. kind: PostgresCluster (2)
    13. name: hippo
    14. - group: ""
    15. version: v1
    16. kind: Secret
    17. name: hippo-pguser-hippo
    18. application: (3)
    19. name: spring-petclinic-rest
    20. group: apps
    21. version: v1
    22. resource: deployments
    23. EOD
    1Specifies a list of service resources.
    2The CR of the database.
    3The sample application that points to a Deployment or any other similar resource with an embedded PodSpec.

    The output verifies that the ServiceBinding CR is created to project the binding data into the sample application.

    Example output

    1. servicebinding.binding.operators.coreos.com/spring-petclinic-rest created
  2. To verify that the binding is successful, check the status conditions of the binding resource:

    1. $ oc get servicebindings spring-petclinic-rest -n my-postgresql -o jsonpath-as-json='{.status.conditions}'

    Example output

    1. [
    2. [
    3. {
    4. "lastTransitionTime": "2021-09-06T13:42:28Z",
    5. "message": "",
    6. "reason": "DataCollected",
    7. "status": "True",
    8. "type": "CollectionReady",
    9. },
    10. {
    11. "lastTransitionTime": "2021-09-06T13:42:28Z",
    12. "message": "",
    13. "reason": "ApplicationUpdated",
    14. "status": "True",
    15. "type": "InjectionReady",
    16. },
    17. {
    18. "lastTransitionTime": "2021-09-06T13:42:28Z",
    19. "message": "",
    20. "reason": "ApplicationsBound",
    21. "status": "True",
    22. "type": "Ready",
    23. },
    24. ],
    25. ]

    By default, the values from the binding data of the database service are projected as files into the workload container that runs the sample application.

  3. To verify that the files in the application contain the projected binding data, use the following command in shell to print out the contents:

    1. $ for i in username password host port type; do oc exec -it deploy/spring-petclinic-rest -n my-postgresql -- /bin/bash -c 'find /bindings/*/'$i' -exec echo -n {}:" " \; -exec cat {} \;'; echo; done

    Example output: With all the values from the secret resource

    1. /bindings/spring-petclinic-rest/username: hippo
    2. /bindings/spring-petclinic-rest/password: w0ZB<0j1W|K;+4*TlK7-w^z/
    3. /bindings/spring-petclinic-rest/host: hippo-pgbouncer
    4. /bindings/spring-petclinic-rest/port: 5432
    5. /bindings/spring-petclinic-rest/type: postgresql
  4. Set up the port forwarding from the application port to access the sample application from your local environment:

    1. $ oc port-forward --address 0.0.0.0 svc/spring-petclinic-rest 9966:80 -n my-postgresql
  5. Access http://localhost:9966/petclinic.

    You can now remotely access the Spring PetClinic sample application at localhost:9966.

  6. To verify that the application is now connected to the database service, access the list of all pets:

    1. $ curl -X GET "http://localhost:9966/petclinic/api/pets" -H "accept: application/json"

    Example output

    1. [{"id":1,"name":"Leo","birthDate":"2000/09/07","type":{"id":1,"name":"cat"},
    2. "owner":{"id":1,"firstName":"George","lastName":"Franklin","address":"110...

    The previous output shows the initially configured sample data and verifies that the application is now connected to the database service.

Additional Resources