Chapter 5. Connecting applications to services

5.1. Release notes for Service Binding Operator

The Service Binding Operator consists of a controller and an accompanying custom resource definition (CRD) for service binding. It manages the data plane for workloads and backing services. The Service Binding Controller reads the data made available by the control plane of backing services. Then, it projects this data to workloads according to the rules specified through the ServiceBinding resource.

With Service Binding Operator, you can:

  • Bind your workloads together with Operator-managed backing services.
  • Automate configuration of binding data.
  • Provide service operators a low-touch administrative experience to provision and manage access to services.
  • Enrich development lifecycle with a consistent and declarative service binding method that eliminates discrepancies in cluster environments.

5.1.1. Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. We are beginning with these four terms: master, slave, blacklist, and whitelist. Because of the enormity of this endeavor, these changes will be implemented gradually over several upcoming releases. For more details, see Red Hat CTO Chris Wright’s message.

5.1.2. Release notes for Service Binding Operator 1.0.1

Service Binding Operator is now available on OpenShift Container Platform 4.7, 4.8 and 4.9.

Service Binding Operator 1.0.1 supports OpenShift Container Platform 4.9 and later running on:

  • IBM Power Systems
  • IBM Z and LinuxONE

The custom resource definition (CRD) of the Service Binding Operator 1.0.1 supports the following APIs:

  • Service Binding with the binding.operators.coreos.com API group.
  • Service Binding (Spec API Tech Preview) with the servicebinding.io API group.

    Important

    Service Binding (Spec API Tech Preview) with the servicebinding.io API group is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

    For more information about the support scope of Red Hat Technology Preview features, see https://access.redhat.com/support/offerings/techpreview/.

5.1.2.1. Support matrix

Some features in this release are currently in Technology Preview. These experimental features are not intended for production use.

Technology Preview Features Support Scope

In the table below, features are marked with the following statuses:

  • TP: Technology Preview
  • GA: General Availability

Note the following scope of support on the Red Hat Customer Portal for these features:

Table 5.1. Support matrix

FeatureService Binding Operator 1.0.1

binding.operators.coreos.com API group

GA

servicebinding.io API group

TP

5.1.2.2. Fixed issues

  • Before this update, binding the data values from a Cluster custom resource (CR) of the postgresql.k8s.enterpriesedb.io/v1 API collected the host binding value from the .metadata.name field of the CR. The collected binding value is an incorrect hostname and the correct hostname is available at the .status.writeService field. With this update, the annotations that the Service Binding Operator uses to expose the binding data values from the backing service CR are now modified to collect the host binding value from the .status.writeService field. The Service Binding Operator uses these modified annotations to project the correct hostname in the host and provider bindings. APPSVC-1040
  • Before this update, when you would bind a PostgresCluster CR of the postgres-operator.crunchydata.com/v1beta1 API, the binding data values did not include the values for the database certificates. As a result, the application failed to connect to the database. With this update, modifications to the annotations that the Service Binding Operator uses to expose the binding data from the backing service CR now include the database certificates. The Service Binding Operator uses these modified annotations to project the correct ca.crt, tls.crt, and tls.key certificate files. APPSVC-1045
  • Before this update, when you would bind a PerconaXtraDBCluster custom resource (CR) of the pxc.percona.com API, the binding data values did not include the port and database values. These binding values along with the others already projected are necessary for an application to successfully connect to the database service. With this update, the annotations that the Service Binding Operator uses to expose the binding data values from the backing service CR are now modified to project the additional port and database binding values. The Service Binding Operator uses these modified annotations to project the complete set of binding values that the application can use to successfully connect to the database service. APPSVC-1073

5.1.2.3. Known issues

  • Currently, when you install the Service Binding Operator in the single namespace installation mode, the absence of an appropriate namespace-scoped role-based access control (RBAC) rule prevents the successful binding of an application to a few known Operator-backed services that the Service Binding Operator can automatically detect and bind to. In addition, the following error message is generated:

    Example error message

    `postgresclusters.postgres-operator.crunchydata.com "hippo" is forbidden:
            User "system:serviceaccount:my-petclinic:service-binding-operator" cannot
            get resource "postgresclusters" in API group "postgres-operator.crunchydata.com"
            in the namespace "my-petclinic"`

    Workaround 1: Install the Service Binding Operator in the all namespaces installation mode. As a result, the appropriate cluster-scoped RBAC rule now exists and the binding succeeds.

    Workaround 2: If you cannot install the Service Binding Operator in the all namespaces installation mode, install the following role binding into the namespace where the Service Binding Operator is installed:

    Example: Role binding for Crunchy Postgres Operator

    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: service-binding-crunchy-postgres-viewer
    subjects:
      - kind: ServiceAccount
        name: service-binding-operator
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: service-binding-crunchy-postgres-viewer-role

    APPSVC-1062

5.1.3. Release notes for Service Binding Operator 1.0

Service Binding Operator is now available on OpenShift Container Platform 4.7, 4.8 and 4.9.

The custom resource definition (CRD) of the Service Binding Operator 1.0 supports the following APIs:

  • Service Binding with the binding.operators.coreos.com API group.
  • Service Binding (Spec API Tech Preview) with the servicebinding.io API group.

    Important

    Service Binding (Spec API Tech Preview) with the servicebinding.io API group is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

    For more information about the support scope of Red Hat Technology Preview features, see https://access.redhat.com/support/offerings/techpreview/.

5.1.3.1. Support matrix

Some features in this release are currently in Technology Preview. These experimental features are not intended for production use.

Technology Preview Features Support Scope

In the table below, features are marked with the following statuses:

  • TP: Technology Preview
  • GA: General Availability

Note the following scope of support on the Red Hat Customer Portal for these features:

Table 5.2. Support matrix

FeatureService Binding Operator 1.0

binding.operators.coreos.com API group

GA

servicebinding.io API group

TP

5.1.3.2. New features

Service Binding Operator 1.0 supports OpenShift Container Platform 4.9 and later running on:

  • IBM Power Systems
  • IBM Z and LinuxONE

This section highlights what is new in Service Binding Operator 1.0:

  • Exposal of binding data from services

    • Based on annotations present in CRD, custom resources (CRs), or resources.
    • Based on descriptors present in Operator Lifecycle Manager (OLM) descriptors.
    • Support for provisioned services
  • Workload projection

    • Projection of binding data as files, with volume mounts.
    • Projection of binding data as environment variables.
  • Service Binding Options

    • Bind backing services in a namespace that is different from the workload namespace.
    • Project binding data into the specific container workloads.
    • Auto-detection of the binding data from resources owned by the backing service CR.
    • Compose custom binding data from the exposed binding data.
    • Support for non-PodSpec compliant workload resources.
  • Security

    • Support for role-based access control (RBAC).

5.1.4. Additional resources

5.2. Understanding Service Binding Operator

Application developers need access to backing services to build and connect workloads. Connecting workloads to backing services is always a challenge because each service provider suggests a different way to access their secrets and consume them in a workload. In addition, manual configuration and maintenance of this binding together of workloads and backing services make the process tedious, inefficient, and error-prone.

The Service Binding Operator enables application developers to easily bind workloads together with Operator-managed backing services, without any manual procedures to configure the binding connection.

5.2.1. Service Binding terminology

This section summarizes the basic terms used in Service Binding.

Service binding

The representation of the action of providing information about a service to a workload. Examples include establishing the exchange of credentials between a Java application and a database that it requires.

Backing service

Any service or software that the application consumes over the network as part of its normal operation. Examples include a database, a message broker, an application with REST endpoints, an event stream, an Application Performance Monitor (APM), or a Hardware Security Module (HSM).

Workload (application)

Any process, running within a container. Examples include a Spring Boot application, a NodeJS Express application, or a Ruby on Rails application.

Binding data

Information about a service that you use to configure the behavior of other resources within the cluster. Examples include credentials, connection details, volume mounts, or secrets.

Binding connection

Any connection that establishes an interaction between the connected components such as a bindable backing service and an application requiring that backing service.

5.2.2. About Service Binding Operator

The Service Binding Operator consists of a controller and an accompanying custom resource definition (CRD) for service binding. It manages the data plane for workloads and backing services. The Service Binding Controller reads the data made available by the control plane of backing services. Then, it projects this data to workloads according to the rules specified through the ServiceBinding resource.

As a result, the Service Binding Operator enables workloads to use backing services or external services by automatically collecting and sharing binding data with the workloads. The process involves making the backing service bindable and binding the workload and the service together.

5.2.2.1. Making an Operator-managed backing service bindable

To make a service bindable, as an Operator provider you need to expose the binding data required by workloads to bind with the services provided by the Operator. You can provide the binding data either as annotations or as descriptors in the CRD of the Operator that manages the backing service.

5.2.2.2. Binding a workload together with a backing service

By using the Service Binding Operator, as an application developer, you need to declare the intent of establishing a binding connection. You must create a Service Binding CR that references the backing service. This action triggers the Service Binding Operator to project the exposed binding data into the workload. The Service Binding Operator receives the declared intent and binds the workload together with the backing service.

The CRD of the Service Binding Operator supports the following APIs:

  • Service Binding with the binding.operators.coreos.com API group.
  • Service Binding (Spec API Tech Preview) with the servicebinding.io API group.

    Important

    Service Binding (Spec API Tech Preview) with the servicebinding.io API group is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process. For more information about the support scope of Red Hat Technology Preview features, see https://access.redhat.com/support/offerings/techpreview/.

With Service Binding Operator, you can:

  • Bind your workloads to Operator-managed backing services.
  • Automate configuration of binding data.
  • Provide service operators a low-touch administrative experience to provision and manage access to services.
  • Enrich development lifecycle with a consistent and declarative service binding method that eliminates discrepancies in cluster environments.

5.2.3. Key features

  • Exposal of binding data from services

    • Based on annotations present in CRD, custom resources (CRs), or resources.
    • Based on descriptors present in Operator Lifecycle Manager (OLM) descriptors.
  • Workload projection

    • Projection of binding data as files, with volume mounts.
    • Projection of binding data as environment variables.
  • Service Binding Options

    • Bind backing services in a namespace that is different from the workload namespace.
    • Project binding data into the specific container workloads.
    • Auto-detection of the binding data from resources owned by the backing service CR.
    • Compose custom binding data from the exposed binding data.
    • Support for non-PodSpec compliant workload resources.
  • Security

    • Support for role-based access control (RBAC).

5.2.4. Additional resources

5.3. Installing Service Binding Operator

This guide walks cluster administrators through the process of installing the Service Binding Operator to an OpenShift Container Platform cluster.

You can install Service Binding Operator on OpenShift Container Platform 4.7 and later.

5.3.1. Installing the Service Binding Operator using the web console

You can install Service Binding Operator using the OpenShift Container Platform OperatorHub. When you install the Service Binding Operator, the custom resources (CRs) required for the service binding configuration are automatically installed along with the Operator.

Prerequisites

You have access to an OpenShift Container Platform cluster using an account with cluster-admin permissions.

Procedure

  1. In the Administrator perspective of the web console, navigate to OperatorsOperatorHub.
  2. Use the Filter by keyword box to search for Service Binding Operator in the catalog. Click the Service Binding Operator tile.
  3. Read the brief description about the Operator on the Service Binding Operator page. Click Install.
  4. On the Install Operator page:

    1. Select All namespaces on the cluster (default) for the Installation Mode. This mode installs the Operator in the default openshift-operators namespace, which enables the Operator to watch and be made available to all namespaces in the cluster.
    2. Select Automatic for the Approval Strategy. This ensures that the future upgrades to the Operator are handled automatically by the Operator Lifecycle Manager (OLM). If you select the Manual approval strategy, OLM creates an update request. As a cluster administrator, you must then manually approve the OLM update request to update the Operator to the new version.
    3. Select an Update Channel.

      • By default, the stable channel enables installation of the latest stable and supported release of the Service Binding Operator.
  5. Click Install.

    Note

    The Operator is installed automatically into the openshift-operators namespace.

  6. On the Installed Operator — ready for use pane, click View Operator. You will see the Operator listed on the Installed Operators page.
  7. Verify that the Status is set to Succeeded to confirm successful installation of Service Binding Operator.

5.3.2. Additional Resources

5.4. Getting started with service binding

The 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 the Service Binding Operator to create a binding connection between the application and the database service.

Prerequisites

  • You have access to an OpenShift Container Platform cluster using an account with cluster-admin permissions.
  • You have installed the oc 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-petclinic namespace.

    Note

    You can create the namespace using the oc create namespace my-petclinic command.

5.4.1. 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 in the my-petclinic namespace by running the following command in shell:

    $ oc apply -n my-petclinic -f - << EOD
    ---
    apiVersion: postgres-operator.crunchydata.com/v1beta1
    kind: PostgresCluster
    metadata:
      name: hippo
    spec:
      image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres-ha:centos8-13.4-0
      postgresVersion: 13
      instances:
        - name: instance1
          dataVolumeClaimSpec:
            accessModes:
            - "ReadWriteOnce"
            resources:
              requests:
                storage: 1Gi
      backups:
        pgbackrest:
          image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:centos8-2.33-2
          repos:
          - name: repo1
            volume:
              volumeClaimSpec:
                accessModes:
                - "ReadWriteOnce"
                resources:
                  requests:
                    storage: 1Gi
          - name: repo2
            volume:
              volumeClaimSpec:
                accessModes:
                - "ReadWriteOnce"
                resources:
                  requests:
                    storage: 1Gi
      proxy:
        pgBouncer:
          image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:centos8-1.15-2
    EOD

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

    The output verifies that the database instance is created:

    Example output

    postgrescluster.postgres-operator.crunchydata.com/hippo created

  2. After you have created the database instance, ensure that all the pods in the my-petclinic namespace are running:

    $ oc get pods -n my-petclinic

    The output, which takes a few minutes to display, verifies that the database is created and configured:

    Example output

    NAME                               READY   STATUS    RESTARTS   AGE
    hippo-backup-nqjg-2rq94            1/1     Running   0          35s
    hippo-instance1-nw92-0             3/3     Running   0          112s
    hippo-pgbouncer-57b98f4476-znsk5   2/2     Running   0          112s
    hippo-repo-host-0                  1/1     Running   0          112s

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

5.4.2. Deploying the Spring PetClinic sample application

To deploy the Spring PetClinic sample application on an OpenShift Container Platform 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 application with the PostgresCluster custom resource (CR) by running the following command in shell:

    $ oc apply -n my-petclinic -f - << EOD
    ---
    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
    ---
    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
    EOD

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

    Example output

    deployment.apps/spring-petclinic created
    service/spring-petclinic created

    Note

    If you are deploying the application using Container images in the Developer perspective of the web console, you must enter the following environment variables under the Deployment section of the Advanced options:

    • Name: SPRING_PROFILES_ACTIVE
    • Value: postgres
  2. Verify that the application is not yet connected to the database service by running the following command:

    $ oc get pods -n my-petclinic

    The output takes a few minutes to display the CrashLoopBackOff status:

    Example output

    NAME                                READY   STATUS             RESTARTS      AGE
    spring-petclinic-5b4c7999d4-wzdtz   0/1     CrashLoopBackOff   4 (13s ago)   2m25s

    At this stage, the pod fails to start. If you try to interact with the application, it returns errors.

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

5.4.3. 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:

    $ oc apply -n my-petclinic -f - << EOD
    ---
    apiVersion: binding.operators.coreos.com/v1alpha1
    kind: ServiceBinding
    metadata:
      name: spring-petclinic-pgcluster
    spec:
      services: 1
        - group: postgres-operator.crunchydata.com
          version: v1beta1
          kind: PostgresCluster 2
          name: hippo
      application: 3
        name: spring-petclinic
        group: apps
        version: v1
        resource: deployments
    EOD
    1
    Specifies a list of service resources.
    2
    The CR of the database.
    3
    The 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

    servicebinding.binding.operators.coreos.com/spring-petclinic created

  2. Verify that the request for service binding is successful:

    $ oc get servicebindings -n my-petclinic

    Example output

    NAME                         READY   REASON              AGE
    spring-petclinic-pgcluster   True    ApplicationsBound   7s

    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. For example, all the values from the Secret resource are projected into the bindings/spring-petclinic-pgcluster directory.

    Note

    Optionally, you can also verify that the files in the application contain the projected binding data, by printing out the directory contents:

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

    Example output: With all the values from the secret resource

    /bindings/spring-petclinic-pgcluster/username: hippo
    /bindings/spring-petclinic-pgcluster/password: KXKF{nAI,I-J6zLt:W+FKnze
    /bindings/spring-petclinic-pgcluster/host: hippo-primary.my-petclinic.svc
    /bindings/spring-petclinic-pgcluster/port: 5432
    /bindings/spring-petclinic-pgcluster/type: postgresql

  3. Set up the port forwarding from the application port to access the sample application from your local environment:

    $ oc 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
    Handling connection for 8080

  4. Access http://localhost:8080/petclinic.

    You can now remotely access the Spring PetClinic sample application at localhost:8080 and see that the application is now connected to the database service.

5.4.4. Additional Resources

5.5. Getting started with service binding on IBM Power Systems, IBM Z, and LinuxONE

The 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 the Service Binding Operator to create a binding connection between the application and the database service.

Prerequisites

  • You have access to an OpenShift Container Platform cluster using an account with cluster-admin permissions.
  • You have installed the oc CLI.
  • You have installed the Service Binding Operator from OperatorHub.

5.5.1. Deploying a PostgreSQL Operator

Procedure

  1. To deploy the Dev4Devs PostgreSQL Operator in the my-petclinic namespace run the following command in shell:
$ oc apply -f - << EOD
---
apiVersion: v1
kind: Namespace
metadata:
  name: my-petclinic
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: postgres-operator-group
  namespace: my-petclinic
---
apiVersion: operators.coreos.com/v1alpha1
kind: CatalogSource
metadata:
  name: ibm-multiarch-catalog
  namespace: openshift-marketplace
spec:
  sourceType: grpc
  image: quay.io/ibm/operator-registry-<architecture> 1
  imagePullPolicy: IfNotPresent
  displayName: ibm-multiarch-catalog
  updateStrategy:
    registryPoll:
      interval: 30m
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: postgresql-operator-dev4devs-com
  namespace: openshift-operators
spec:
  channel: alpha
  installPlanApproval: Automatic
  name: postgresql-operator-dev4devs-com
  source: ibm-multiarch-catalog
  sourceNamespace: openshift-marketplace
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: database-view
  labels:
    servicebinding.io/controller: "true"
rules:
  - apiGroups:
      - postgresql.dev4devs.com
    resources:
      - databases
    verbs:
      - get
      - list
EOD
1
The Operator image.
  • For IBM Power: quay.io/ibm/operator-registry-ppc64le:release-4.9
  • For IBM Z and LinuxONE: quay.io/ibm/operator-registry-s390x:release-4.8

Verification

  1. After the operator is installed, list the operator subscriptions in the openshift-operators namespace:

    $ oc get subs -n openshift-operators

    Example output

    NAME                               PACKAGE                            SOURCE                  CHANNEL
    postgresql-operator-dev4devs-com   postgresql-operator-dev4devs-com   ibm-multiarch-catalog   alpha
    rh-service-binding-operator        rh-service-binding-operator        redhat-operators        stable

5.5.2. Creating a PostgreSQL database instance

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

Procedure

  1. Create the Database CR in the my-petclinic namespace by running the following command in shell:

    $ oc apply -f - << EOD
    apiVersion: postgresql.dev4devs.com/v1alpha1
    kind: Database
    metadata:
      name: sampledatabase
      namespace: my-petclinic
      annotations:
        host: sampledatabase
        type: postgresql
        port: "5432"
        service.binding/database: 'path={.spec.databaseName}'
        service.binding/port: 'path={.metadata.annotations.port}'
        service.binding/password: 'path={.spec.databasePassword}'
        service.binding/username: 'path={.spec.databaseUser}'
        service.binding/type: 'path={.metadata.annotations.type}'
        service.binding/host: 'path={.metadata.annotations.host}'
    spec:
      databaseCpu: 30m
      databaseCpuLimit: 60m
      databaseMemoryLimit: 512Mi
      databaseMemoryRequest: 128Mi
      databaseName: "sampledb"
      databaseNameKeyEnvVar: POSTGRESQL_DATABASE
      databasePassword: "samplepwd"
      databasePasswordKeyEnvVar: POSTGRESQL_PASSWORD
      databaseStorageRequest: 1Gi
      databaseUser: "sampleuser"
      databaseUserKeyEnvVar: POSTGRESQL_USER
      image: registry.redhat.io/rhel8/postgresql-13:latest
      databaseStorageClassName: nfs-storage-provisioner
      size: 1
    EOD

    The annotations added in this Database CR enable the service binding connection and trigger the Operator reconciliation.

    The output verifies that the database instance is created:

    Example output

    database.postgresql.dev4devs.com/sampledatabase created

  2. After you have created the database instance, ensure that all the pods in the my-petclinic namespace are running:

    $ oc get pods -n my-petclinic

    The output, which takes a few minutes to display, verifies that the database is created and configured:

    Example output

    NAME                                     READY    STATUS      RESTARTS   AGE
    sampledatabase-cbc655488-74kss            0/1     Running        0       32s

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

5.5.3. Deploying the Spring PetClinic sample application

To deploy the Spring PetClinic sample application on an OpenShift Container Platform 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 application with the PostgresCluster custom resource (CR) by running the following command in shell:

    $ oc apply -n my-petclinic -f - << EOD
    ---
    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
              - name: org.springframework.cloud.bindings.boot.enable
                value: "true"
              ports:
              - name: http
                containerPort: 8080
    ---
    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
    EOD

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

    Example output

    deployment.apps/spring-petclinic created
    service/spring-petclinic created

    Note

    If you are deploying the application using Container images in the Developer perspective of the web console, you must enter the following environment variables under the Deployment section of the Advanced options:

    • Name: SPRING_PROFILES_ACTIVE
    • Value: postgres
  2. Verify that the application is not yet connected to the database service by running the following command:

    $ oc get pods -n my-petclinic

    It takes take a few minutes until the CrashLoopBackOff status is displayed:

    Example output

    NAME                                READY   STATUS             RESTARTS      AGE
    spring-petclinic-5b4c7999d4-wzdtz   0/1     CrashLoopBackOff   4 (13s ago)   2m25s

    At this stage, the pod fails to start. If you try to interact with the application, it returns errors.

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

5.5.4. 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:

    $ oc apply -n my-petclinic -f - << EOD
    ---
    apiVersion: binding.operators.coreos.com/v1alpha1
    kind: ServiceBinding
    metadata:
        name: spring-petclinic-pgcluster
    spec:
      services: 1
        - group: postgresql.dev4devs.com
          kind: Database 2
          name: sampledatabase
          version: v1alpha1
      application: 3
        name: spring-petclinic
        group: apps
        version: v1
        resource: deployments
    EOD
    1
    Specifies a list of service resources.
    2
    The CR of the database.
    3
    The 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

    servicebinding.binding.operators.coreos.com/spring-petclinic created

  2. Verify that the request for service binding is successful:

    $ oc get servicebindings -n my-petclinic

    Example output

    NAME                          READY   REASON              AGE
    spring-petclinic-postgresql   True    ApplicationsBound   47m

    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. For example, all the values from the Secret resource are projected into the bindings/spring-petclinic-pgcluster directory.

  3. Once this is created, you can go to the topology to see the visual connection.

    Figure 5.1. Connecting spring-petclinic to a sample database

    img power
  4. Set up the port forwarding from the application port to access the sample application from your local environment:

    $ oc 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
    Handling connection for 8080

  5. Access http://localhost:8080.

    You can now remotely access the Spring PetClinic sample application at localhost:8080 and see that the application is now connected to the database service.

5.5.5. Additional resources

5.6. Exposing binding data from a service

Application developers need access to backing services to build and connect workloads. Connecting workloads to backing services is always a challenge because each service provider requires a different way to access their secrets and consume them in a workload.

The Service Binding Operator enables application developers to easily bind workloads together with operator-managed backing services, without any manual procedures to configure the binding connection. For the Service Binding Operator to provide the binding data, as an Operator provider or user who creates backing services, you must expose the binding data to be automatically detected by the Service Binding Operator. Then, the Service Binding Operator automatically collects the binding data from the backing service and shares it with a workload to provide a consistent and predictable experience.

5.6.1. Methods of exposing binding data

This section describes the methods you can use to expose the binding data.

Ensure that you know and understand your workload requirements and environment, and how it works with the provided services.

Binding data is exposed under the following circumstances:

  • Backing service is available as a provisioned service resource.

    The service you intend to connect to is compliant with the Service Binding specification. You must create a Secret resource with all the required binding data values and reference it in the backing service custom resource (CR). The detection of all the binding data values is automatic.

  • Backing service is not available as a provisioned service resource.

    You must expose the binding data from the backing service. Depending on your workload requirements and environment, you can choose any of the following methods to expose the binding data:

    • Direct secret reference
    • Declaring binding data through custom resource definition (CRD) or CR annotations
    • Detection of binding data through owned resources

5.6.1.1. Provisioned service

Provisioned service represents a backing service CR with a reference to a Secret resource placed in the .status.binding.name field of the backing service CR.

As an Operator provider or the user who creates backing services, you can use this method to be compliant with the Service Binding specification, by creating a Secret resource and referencing it in the .status.binding.name section of the backing service CR. This Secret resource must provide all the binding data values required for a workload to connect to the backing service.

The following examples show an AccountService CR that represents a backing service and a Secret resource referenced from the CR.

Example: AccountService CR

apiVersion: example.com/v1alpha1
kind: AccountService
name: prod-account-service
spec:
  ...
status:
  binding:
    name: hippo-pguser-hippo

Example: Referenced Secret resource

apiVersion: v1
kind: Secret
metadata:
  name: hippo-pguser-hippo
data:
  password: "MTBz"
  user: "Z3Vlc3Q="
  ...

When creating a service binding resource, you can directly give the details of the AccountService resource in the ServiceBinding specification as follows:

Example: ServiceBinding resource

apiVersion: binding.operators.coreos.com/v1alpha1
kind: ServiceBinding
metadata:
  name: account-service
spec:
  ...
  services:
  - group: "example.com"
    version: v1alpha1
    kind: AccountService
    name: prod-account-service
  application:
    name: spring-petclinic
    group: apps
    version: v1
    resource: deployments

Important

Service Binding (Spec API Tech Preview) with the servicebinding.io API group is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process. For more information about the support scope of Red Hat Technology Preview features, see https://access.redhat.com/support/offerings/techpreview/.

Example: ServiceBinding resource in Specification API

apiVersion: servicebinding.io/v1alpha3
kind: ServiceBinding
metadata:
  name: account-service
spec:
  ...
  service:
    apiVersion: example.com/v1alpha1
    kind: AccountService
    name: prod-account-service
  application:
    apiVersion: apps/v1
    kind: Deployment
    name: spring-petclinic

This method exposes all the keys in the hippo-pguser-hippo referenced Secret resource as binding data that is to be projected into the workload.

5.6.1.2. Direct secret reference

You can use this method, if all the required binding data values are available in a Secret resource that you can reference in your Service Binding definition. In this method, a ServiceBinding resource directly references a Secret resource to connect to a service. All the keys in the Secret resource are exposed as binding data.

Example: Specification with the binding.operators.coreos.com API

apiVersion: binding.operators.coreos.com/v1alpha1
kind: ServiceBinding
metadata:
  name: account-service
spec:
  ...
  services:
  - group: ""
    version: v1
    kind: Secret
    name: hippo-pguser-hippo

Example: Specification that is compliant with the servicebinding.io API

apiVersion: servicebinding.io/v1alpha3
kind: ServiceBinding
metadata:
  name: account-service
spec:
  ...
  service:
    apiVersion: v1
    kind: Secret
    name: hippo-pguser-hippo

5.6.1.3. Declaring binding data through CRD or CR annotations

You can use this method to annotate the resources of the backing service to expose the binding data with specific annotations. Adding annotations under the metadata section alters the CRs and CRDs of the backing services. Service Binding Operator detects the annotations added to the CRs and CRDs and then creates a Secret resource with the values extracted based on the annotations.

The following examples show the annotations that are added under the metadata section and a referenced ConfigMap object from a resource:

Example: Exposing binding data from a Secret object defined in the CR annotations

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    service.binding: 'path={.metadata.name}-pguser-{.metadata.name},objectType=Secret'
    ...

The previous example places the name of the secret name in the {.metadata.name}-pguser-{.metadata.name} template that resolves to hippo-pguser-hippo. The template can contain multiple JSONPath expressions.

Example: Referenced Secret object from a resource

apiVersion: v1
kind: Secret
metadata:
  name: hippo-pguser-hippo
data:
  password: "MTBz"
  user: "Z3Vlc3Q="

Example: Exposing binding data from a ConfigMap object defined in the CR annotations

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    service.binding: 'path={.metadata.name}-config,objectType=ConfigMap'
    ...

The previous example places the name of the config map in the {.metadata.name}-config template that resolves to hippo-config. The template can contain multiple JSONPath expressions.

Example: Referenced ConfigMap object from a resource

apiVersion: v1
kind: ConfigMap
metadata:
  name: hippo-config
data:
  db_timeout: "10s"
  user: "hippo"

5.6.1.4. Detection of binding data through owned resources

You can use this method if your backing service owns one or more Kubernetes resources such as route, service, config map, or secret that you can use to detect the binding data. In this method, the Service Binding Operator detects the binding data from resources owned by the backing service CR.

The following examples show the detectBindingResources API option set to true in the ServiceBinding CR:

Example

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

In the previous example, PostgresCluster custom service resource owns one or more Kubernetes resources such as route, service, config map, or secret.

The Service Binding Operator automatically detects the binding data exposed on each of the owned resources.

5.6.2. Data model

The data model used in the annotations follows specific conventions.

Service binding annotations must use the following convention:

service.binding(/<NAME>)?:
    "<VALUE>|(path=<JSONPATH_TEMPLATE>(,objectType=<OBJECT_TYPE>)?(,elementType=<ELEMENT_TYPE>)?(,sourceKey=<SOURCE_KEY>)?(,sourceValue=<SOURCE_VALUE>)?)"

where:

<NAME>

Specifies the name under which the binding value is to be exposed. You can exclude it only when the objectType parameter is set to Secret or ConfigMap.

<VALUE>

Specifies the constant value exposed when no path is set.

The data model provides the details on the allowed values and semantic for the path, elementType, objectType, sourceKey, and sourceValue parameters.

Table 5.3. Parameters and their descriptions

ParameterDescriptionDefault value

path

JSONPath template that consists JSONPath expressions enclosed by curly braces {}.

N/A

elementType

Specifies whether the value of the element referenced in the path parameter complies with any one of the following types:

  • string
  • sliceOfStrings
  • sliceOfMaps

string

objectType

Specifies whether the value of the element indicated in the path parameter refers to a ConfigMap, Secret, or plain string in the current namespace.

Secret, if elementType is non-string.

sourceKey

Specifies the key in the ConfigMap or Secret resource to be added to the binding secret when collecting the binding data.

Note:

  • When used in conjunction with elementType=sliceOfMaps, the sourceKey parameter specifies the key in the slice of maps whose value is used as a key in the binding secret.
  • Use this optional parameter to expose a specific entry in the referenced Secret or ConfigMap resource as binding data.
  • When not specified, all keys and values from the Secret or ConfigMap resource are exposed and are added to the binding secret.

N/A

sourceValue

Specifies the key in the slice of maps.

Note:

  • The value of this key is used as the base to generate the value of the entry for the key-value pair to be added to the binding secret.
  • In addition, the value of the sourceKey is used as the key of the entry for the key-value pair to be added to the binding secret.
  • It is mandatory only if elementType=sliceOfMaps.

N/A

Note

The sourceKey and sourceValue parameters are applicable only if the element indicated in the path parameter refers to a ConfigMap or Secret resource.

5.6.3. RBAC requirements

To expose the backing service binding data using the Service Binding Operator, you require certain Role-based access control (RBAC) permissions. Specify certain verbs under the rules field of the ClusterRole resource to grant the RBAC permissions for the backing service resources. When you define these rules, you allow the Service Binding Operator to read the binding data of the backing service resources throughout the cluster. If the users do not have permissions to read binding data or modify application resource, the Service Binding Operator prevents such users to bind services to application. Adhering to the RBAC requirements avoids unnecessary permission elevation for the user and prevents access to unauthorized services or applications.

The Service Binding Operator performs requests against the Kubernetes API using a dedicated service account. By default, this account has permissions to bind services to workloads, both represented by the following standard Kubernetes or OpenShift objects:

  • Deployments
  • DaemonSets
  • ReplicaSets
  • StatefulSets
  • DeploymentConfigs

The Operator service account is bound to an aggregated cluster role, allowing Operator providers or cluster administrators to enable binding custom service resources to workloads. To grant the required permissions within a ClusterRole, label it with the servicebinding.io/controller flag and set the flag value to true. The following example shows how to allow the Service Binding Operator to get, watch, and list the custom resources (CRs) of Crunchy PostgreSQL Operator:

Example: Enable binding to PostgreSQL database instances provisioned by Crunchy PostgreSQL Operator

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: postgrescluster-reader
  labels:
     servicebinding.io/controller: "true"
rules:
- apiGroups:
    - postgres-operator.crunchydata.com
  resources:
    - postgresclusters
  verbs:
    - get
    - watch
    - list
  ...

This cluster role can be deployed during the installation of the backing service Operator.

5.6.4. Categories of exposable binding data

The Service Binding Operator enables you to expose the binding data values from the backing service resources and custom resource definitions (CRDs).

This section provides examples to show how you can use the various categories of exposable binding data. You must modify these examples to suit your work environment and requirements.

5.6.4.1. Exposing a string from a resource

The following example shows how to expose the string from the metadata.name field of the PostgresCluster custom resource (CR) as a username:

Example

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    service.binding/username: path={.metadata.name}
    ...

5.6.4.2. Exposing a constant value as the binding item

The following examples show how to expose a constant value from the PostgresCluster custom resource (CR):

Example: Exposing a constant value

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    "service.binding/type": "postgresql" 1

1
Binding type to be exposed with the postgresql value.

5.6.4.3. Exposing an entire config map or secret that is referenced from a resource

The following examples show how to expose an entire secret through annotations:

Example: Exposing an entire secret through annotations

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    service.binding: 'path={.metadata.name}-pguser-{.metadata.name},objectType=Secret'

Example: The referenced secret from the backing service resource

apiVersion: v1
kind: Secret
metadata:
  name: hippo-pguser-hippo
data:
  password: "MTBz"
  user: "Z3Vlc3Q="

5.6.4.4. Exposing a specific entry from a config map or secret that is referenced from a resource

The following examples show how to expose a specific entry from a config map through annotations:

Example: Exposing an entry from a config map through annotations

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    service.binding: 'path={.metadata.name}-config,objectType=ConfigMap,sourceKey=user'

Example: The referenced config map from the backing service resource

The binding data should have a key with name as db_timeout and value as 10s:

apiVersion: v1
kind: ConfigMap
metadata:
  name: hippo-config
data:
  db_timeout: "10s"
  user: "hippo"

5.6.4.5. Exposing a resource definition value

The following example shows how to expose a resource definition value through annotations:

Example: Exposing a resource definition value through annotations

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    service.binding/username: path={.metadata.name}
    ...

5.6.4.6. Exposing entries of a collection with the key and value from each entry

The following example shows how to expose the entries of a collection with the key and value from each entry through annotations:

Example: Exposing the entries of a collection through annotations

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    "service.binding/uri": "path={.status.connections},elementType=sliceOfMaps,sourceKey=type,sourceValue=url"
spec:
  ...
status:
  connections:
    - type: primary
      url: primary.example.com
    - type: secondary
      url: secondary.example.com
    - type: '404'
      url: black-hole.example.com

The following example shows how the previous entries of a collection in annotations are projected into the bound application.

Example: Binding data files

/bindings/<binding-name>/uri_primary => primary.example.com
/bindings/<binding-name>/uri_secondary => secondary.example.com
/bindings/<binding-name>/uri_404 => black-hole.example.com

Example: Configuration from a backing service resource

status:
  connections:
    - type: primary
      url: primary.example.com
    - type: secondary
      url: secondary.example.com
    - type: '404'
      url: black-hole.example.com

The previous example helps you to project all those values with keys such as primary, secondary, and so on.

5.6.4.7. Exposing items of a collection with one key per item

The following example shows how to expose the items of a collection with one key per item through annotations:

Example: Exposing the items of a collection through annotations

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    "service.binding/tags": "path={.spec.tags},elementType=sliceOfStrings"
spec:
    tags:
      - knowledge
      - is
      - power

The following example shows how the previous items of a collection in annotations are projected into the bound application.

Example: Binding data files

/bindings/<binding-name>/tags_0 => knowledge
/bindings/<binding-name>/tags_1 => is
/bindings/<binding-name>/tags_2 => power

Example: Configuration from a backing service resource

spec:
  tags:
  - knowledge
  - is
  - power

5.6.4.8. Exposing values of collection entries with one key per entry value

The following example shows how to expose the values of collection entries with one key per entry value through annotations:

Example: Exposing the values of collection entries through annotations

apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: hippo
  namespace: my-petclinic
  annotations:
    "service.binding/url": "path={.spec.connections},elementType=sliceOfStrings,sourceValue=url"
spec:
  connections:
    - type: primary
      url: primary.example.com
    - type: secondary
      url: secondary.example.com
    - type: '404'
      url: black-hole.example.com

The following example shows how the previous values of a collection in annotations are projected into the bound application.

Example: Binding data files

/bindings/<binding-name>/url_0 => primary.example.com
/bindings/<binding-name>/url_1 => secondary.example.com
/bindings/<binding-name>/url_2 => black-hole.example.com

5.6.5. Additional resources

5.7. Projecting binding data

This section provides information on how you can consume the binding data.

5.7.1. Consumption of binding data

After the backing service exposes the binding data, for a workload to access and consume this data, you must project it into the workload from a backing service. Service Binding Operator automatically projects this set of data into the workload in the following methods:

  1. By default, as files.
  2. As environment variables, after you configure the .spec.bindAsFiles parameter from the ServiceBinding resource.

5.7.2. Configuration of the directory path to project the binding data inside workload container

By default, Service Binding Operator mounts the binding data as files at a specific directory in your workload resource. You can configure the directory path using the SERVICE_BINDING_ROOT environment variable setup in the container where your workload runs.

Example: Binding data mounted as files

$SERVICE_BINDING_ROOT 1
├── account-database 2
│   ├── type 3
│   ├── provider 4
│   ├── uri
│   ├── username
│   └── password
└── transaction-event-stream 5
    ├── type
    ├── connection-count
    ├── uri
    ├── certificates
    └── private-key

1
Root directory.
2 5
Directory that stores the binding data.
3
Mandatory identifier that identifies the type of the binding data projected into the corresponding directory.
4
Optional: Identifier to identify the provider so that the application can identify the type of backing service it can connect to.

To consume the binding data as environment variables, use the built-in language feature of your programming language of choice that can read environment variables.

Example: Python client usage

import os
username = os.getenv("USERNAME")
password = os.getenv("PASSWORD")

5.7.2.1. Computation of the final path for projecting the binding data as files

The following table summarizes the configuration of how the final path for the binding data projection is computed when files are mounted at a specific directory:

Table 5.4. Summary of the final path computation

SERVICE_BINDING_ROOTFinal path

Not available

/bindings/<ServiceBinding_ResourceName>

dir/path/root

dir/path/root/<ServiceBinding_ResourceName>

In the previous table, the <ServiceBinding_ResourceName> entry specifies the name of the ServiceBinding resource that you configure in the .metadata.name section of the custom resource (CR).

To access and consume the binding data within the existing SERVICE_BINDING_ROOT environment variable, use the built-in language feature of your programming language of choice that can read environment variables.

Example: Python client usage

from pyservicebinding import binding
try:
    sb = binding.ServiceBinding()
except binding.ServiceBindingRootMissingError as msg:
    # log the error message and retry/exit
    print("SERVICE_BINDING_ROOT env var not set")
sb = binding.ServiceBinding()
bindings_list = sb.bindings("postgresql")

In the previous example, the bindings_list variable contains the binding data for the postgresql database service type.

5.7.3. Projecting the binding data

Depending on your workload requirements and environment, you can choose to project the binding data either as files or environment variables.

Prerequisites

  • You understand the following concepts:

    • Environment and requirements of your workload, and how it works with the provided services.
    • Consumption of the binding data in your workload resource.
    • Configuration of how the final path for data projection is computed for the default method.
  • The binding data is exposed from the backing service.

Procedure

  1. To project the binding data as files, determine the destination folder by ensuring that the existing SERVICE_BINDING_ROOT environment variable is present in the container where your workload runs.
  2. To project the binding data as environment variables, set the value for the .spec.bindAsFiles parameter to false from the ServiceBinding resource in the custom resource (CR).

5.7.4. Additional resources

5.8. Binding workloads using Service Binding Operator

Application developers must bind a workload to one or more backing services by using a binding secret. This secret is generated for the purpose of storing information to be consumed by the workload.

As an example, consider that the service you want to connect to is already exposing the binding data. In this case, you would also need a workload to be used along with the ServiceBinding custom resource (CR). By using this ServiceBinding CR, the workload sends a binding request with the details of the services to bind with.

Example of ServiceBinding CR

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

1
Specifies a list of service resources.
2
The sample application that points to a Deployment or any other similar resource with an embedded PodSpec.

As shown in the previous example, you can also directly use a ConfigMap or a Secret itself as a service resource to be used as a source of binding data.

5.8.1. Naming strategies

Naming strategies are available only for the binding.operators.coreos.com API group.

Naming strategies use Go templates to help you define custom binding names through the service binding request. Naming strategies apply for all attributes including the mappings in the ServiceBinding custom resource (CR).

A backing service projects the binding names as files or environment variables into the workload. If a workload expects the projected binding names in a particular format, but the binding names to be projected from the backing service are not available in that format, then you can change the binding names using naming strategies.

Predefined post-processing functions

While using naming strategies, depending on the expectations or requirements of your workload, you can use the following predefined post-processing functions in any combination to convert the character strings:

  • upper: Converts the character strings into capital or uppercase letters.
  • lower: Converts the character strings into lowercase letters.
  • title: Converts the character strings where the first letter of each word is capitalized except for certain minor words.

Predefined naming strategies

Binding names declared through annotations are processed for their name change before their projection into the workload according to the following predefined naming strategies:

  • none: When applied, there are no changes in the binding names.

    Example

    After the template compilation, the binding names take the {{ .name }} form.

    host: hippo-pgbouncer
    port: 5432
  • upper: Applied when no namingStrategy is defined. When applied, converts all the character strings of the binding name key into capital or uppercase letters.

    Example

    After the template compilation, the binding names take the {{ .service.kind | upper}}_{{ .name | upper }} form.

    DATABASE_HOST: hippo-pgbouncer
    DATABASE_PORT: 5432

    If your workload requires a different format, you can define a custom naming strategy and change the binding name using a prefix and a separator, for example, PORT_DATABASE.

Note
  • When the binding names are projected as files, by default the predefined none naming strategy is applied, and the binding names do not change.
  • When the binding names are projected as environment variables and no namingStrategy is defined, by default the predefined uppercase naming strategy is applied.
  • You can override the predefined naming strategies by defining custom naming strategies using different combinations of custom binding names and predefined post-processing functions.

5.8.2. Advanced binding options

Advanced binding options are available only for the binding.operators.coreos.com API group.

5.8.2.1. Changing the binding names before projecting them into the workload

You can specify the rules to change the binding names in the .spec.namingStrategy attribute of the ServiceBinding custom resource (CR). For example, consider a Spring PetClinic sample application that connects to the PostgreSQL database. In this case, the PostgreSQL database service exposes the host and port fields of the database to use for binding. The Spring PetClinic sample application can access this exposed binding data through the binding names.

Example: Spring PetClinic sample application in the ServiceBinding CR

...
    application:
      name: spring-petclinic
      group: apps
      version: v1
      resource: deployments
...

Example: PostgreSQL database service in the ServiceBinding CR

...
    services:
    - group: postgres-operator.crunchydata.com
      version: v1beta1
      kind: PostgresCluster
      name: hippo
...

If namingStrategy is not defined and the binding names are projected as environment variables, then the host: hippo-pgbouncer value in the backing service and the projected environment variable would appear as shown in the following example:

Example

DATABASE_HOST: hippo-pgbouncer

where:

DATABASE

Specifies the kind backend service.

HOST

Specifies the binding name.

After applying the POSTGRESQL_{{ .service.kind | upper }}_{{ .name | upper }}_ENV naming strategy, the list of custom binding names prepared by the service binding request appears as shown in the following example:

Example

POSTGRESQL_DATABASE_HOST_ENV: hippo-pgbouncer
POSTGRESQL_DATABASE_PORT_ENV: 5432

The following items describe the expressions defined in the POSTGRESQL_{{ .service.kind | upper }}_{{ .name | upper }}_ENV naming strategy:

  • .name: Refers to the binding name exposed by the backing service. In the previous example, the binding names are HOST and PORT.
  • .service.kind: Refers to the kind of service resource whose binding names are changed with the naming strategy.
  • upper: String function used to post-process the character string while compiling the Go template string.
  • POSTGRESQL: Prefix of the custom binding name.
  • ENV: Suffix of the custom binding name.

Similar to the previous example, you can define the string templates in namingStrategy to define how each key of the binding names should be prepared by the service binding request.

5.8.2.2. Composing custom binding data

As an application developer, you can compose custom binding data under the following circumstances:

  • The backing service does not expose binding data.
  • The values exposed are not available in the required format as expected by the workload.

For example, consider a case where the backing service CR exposes the host, port, and database user as binding data, but the workload requires that the binding data be consumed as a connection string. You can compose custom binding data using attributes in the Kubernetes resource representing the backing service.

Example

apiVersion: binding.operators.coreos.com/v1alpha1
kind: ServiceBinding
metadata:
    name: spring-petclinic-pgcluster
    namespace: my-petclinic
spec:
    services:
    - group: postgres-operator.crunchydata.com
      version: v1beta1
      kind: PostgresCluster
      name: hippo 1
      id: postgresDB 2
    - group: ""
      version: v1
      kind: Secret
      name: hippo-pguser-hippo
      id: postgresSecret
    application:
      name: spring-petclinic
      group: apps
      version: v1
      resource: deployments
    mappings:
      ## From the database service
      - name: JDBC_URL
        value: 'jdbc:postgresql://{{ .postgresDB.metadata.annotations.proxy }}:{{ .postgresDB.spec.port }}/{{ .postgresDB.metadata.name }}'
      ## From both the services!
      - name: CREDENTIALS
        value: '{{ .postgresDB.metadata.name }}{{ translationService.postgresSecret.data.password }}'
      ## Generate JSON
      - name: DB_JSON 3
        value: {{ json .postgresDB.status }} 4

1
Name of the backing service resource.
2
Optional identifier.
3
Generated JSON name that is to be projected as the file content or environment value. The JSON name contains the attributes of the backing service custom resource.
4
Generated JSON value that is to be projected as the file content or environment value. The JSON value contains the attributes of the backing service custom resource.

5.8.3. Binding secondary workloads that are not compliant with PodSpec

A typical scenario in service binding involves configuring the backing service, the workload (Deployment), and Service Binding Operator. Consider a scenario that involves a secondary workload (which can also be an application Operator) that is not compliant with PodSpec and is between the primary workload (Deployment) and Service Binding Operator.

For such secondary workload resources, the location of the container path is arbitrary. For service binding, if the secondary workload in a CR is not compliant with the PodSpec, you must specify the location of the container path. Doing so projects the binding data into the container path specified in the secondary workload of the ServiceBinding custom resource (CR), for example, when you do not want the binding data inside a pod.

Service Binding Operator provides an option to configure the value of where the container path or secret path is and bind these paths at a custom location. This option is available only for the binding.operators.coreos.com API group when the binding data is projected as environment variables.

5.8.3.1. Configuring the custom location of the container path

Consider a secondary workload CR, which is not compliant with the PodSpec and has containers located at the spec.containers path:

Example: Secondary workload CR

apiVersion: "operator.sbo.com/v1"
kind: SecondaryWorkload
metadata:
    name: secondary-workload
spec:
    containers:
    - name: hello-world
      image: quay.io/baijum/secondary-workload:latest
      ports:
      - containerPort: 8080

Procedure

  • Configure the spec.containers path by specifying a value in the ServiceBinding CR and bind this path to a spec.application.bindingPath.containersPath custom location:

    Example: ServiceBinding CR with the spec.containers path in a custom location

    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
          id: postgresDB
        - group: ""
          version: v1
          kind: Secret
          name: hippo-pguser-hippo
          id: postgresSecret
        application: 1
          name: spring-petclinic
          group: apps
          version: v1
          resource: deployments
        application: 2
          name: secondary-workload
          group: operator.sbo.com
          version: v1
          resource: secondaryworkloads
          bindingPath:
            containersPath: spec.containers 3

    1
    The sample application that points to a Deployment or any other similar resource with an embedded PodSpec.
    2
    The secondary workload, which is not compliant with the PodSpec.
    3
    The custom location of the container path.

After you specify the location of the container path, Service Binding Operator generates the binding data, which becomes available in the container path specified in the secondary workload of the ServiceBinding CR.

The following example shows the spec.containers path with the envFrom and secretRef fields:

Example: Secondary workload CR with the envFrom and secretRef fields

apiVersion: "operator.sbo.com/v1"
kind: SecondaryWorkload
metadata:
    name: secondary-workload
spec:
    containers:
    - env: 1
      - name: ServiceBindingOperatorChangeTriggerEnvVar
        value: "31793"
      envFrom:
      - secretRef:
          name: secret-resource-name 2
      image: quay.io/baijum/secondary-workload:latest
      name: hello-world
      ports:
      - containerPort: 8080
      resources: {}

1
Unique array of containers with values generated by the Service Binding Operator. These values are based on the backing service CR.
2
Name of the Secret resource generated by the Service Binding Operator.

5.8.3.2. Configuring the custom location of the secret path

Consider a secondary workload CR, which is not compliant with the PodSpec, with only the secret at the spec.secret path:

Example: Secondary workload CR

apiVersion: "operator.sbo.com/v1"
kind: SecondaryWorkload
metadata:
    name: secondary-workload
spec:
    secret: ""

Procedure

  • Configure the spec.secret path by specifying a value in the ServiceBinding CR and bind this path at a spec.application.bindingPath.secretPath custom location:

    Example: ServiceBinding CR with the spec.secret path in a custom location

    apiVersion: binding.operators.coreos.com/v1alpha1
    kind: ServiceBinding
    metadata:
        name: spring-petclinic-pgcluster
    spec:
    ...
        application: 1
          name: secondary-workload
          group: operator.sbo.com
          version: v1
          resource: secondaryworkloads
          bindingPath:
            secretPath: spec.secret 2
    ...

    1
    The secondary workload, which is not compliant with the PodSpec.
    2
    The custom location of the secret path that contains the name of the Secret resource.

After you specify the location of the secret path, Service Binding Operator generates the binding data, which becomes available in the secret path specified in the secondary workload of the ServiceBinding CR.

The following example shows the spec.secret path with the binding-request value:

Example: Secondary workload CR with the binding-request value

...
apiVersion: "operator.sbo.com/v1"
kind: SecondaryWorkload
metadata:
    name: secondary-workload
spec:
    secret: binding-request-72ddc0c540ab3a290e138726940591debf14c581 1
...

1
Unique name of the Secret resource generated by the Service Binding Operator.

5.8.4. Unbinding workloads from a backing service

You can unbind a workload from a backing service by using the oc tool.

  • To unbind a workload from a backing service, delete the ServiceBinding custom resource (CR) linked to it:

    $ oc delete ServiceBinding <.metadata.name>

    Example

    $ oc delete ServiceBinding spring-petclinic-pgcluster

    where:

    spring-petclinic-pgcluster

    Specifies the name of the ServiceBinding CR.

5.8.5. Additional resources

5.9. Connecting an application to a service using the Developer perspective

In addition to grouping multiple components within an application, you can also use the Topology view to connect components with each other. You can either use a binding connector or a visual one to connect components.

A binding connection between the components can be established only if the target node is an Operator-backed service. This is indicated by the Create a binding connector tool-tip which appears when you drag an arrow to such a target node. When an application is connected to a service using a binding connector a ServiceBinding resource is created. Then, the Service Binding Operator controller projects the necessary binding data into the application deployment. After the request is successful, the application is redeployed establishing an interaction between the connected components.

A visual connector establishes only a visual connection between the components, depicting an intent to connect. No interaction between the components is established. If the target node is not an Operator-backed service the Create a visual connector tool-tip is displayed when you drag an arrow to a target node.

5.9.1. Creating a visual connection between components

You can depict an intent to connect application components using the visual connector.

This procedure walks you through an example of creating a visual connection between a PostgreSQL Database service and a Spring PetClinic sample application.

Prerequisites

  • You have created and deployed a Spring PetClinic sample application using the Developer perspective.
  • You have created and deployed a Crunchy PostgreSQL database instance using the Developer perspective. This instance has the following four components: hippo-backup, hippo-instance, hippo-repo-host, and hippo-pgbouncer.

Procedure

  1. Hover over the Spring PetClinic sample application to see a dangling arrow on the node.

    Figure 5.2. Visual connector

    odc connector
  2. Click and drag the arrow towards the hippo-pgbouncer deployment to connect the Spring PetClinic sample application with it.
  3. Click the spring-petclinic deployment to see the Overview panel. Under the Details tab, click the edit icon in the Annotations section to see the Key = app.openshift.io/connects-to and Value = [{"apiVersion":"apps/v1","kind":"Deployment","name":"hippo-pgbouncer"}] annotation added to the deployment.

Similarly you can create other applications and components and establish visual connections between them.

Figure 5.3. Connecting multiple applications

odc connecting multiple applications

5.9.2. Creating a binding connection between components

You can establish a binding connection with Operator-backed components.

This procedure walks through an example of creating a binding connection between a PostgreSQL Database service and a Spring PetClinic sample application. To create a binding connection with a service that is backed by the PostgreSQL Database Operator, you must first add the Red Hat-provided PostgreSQL Database Operator to the OperatorHub, and then install the Operator. The PostreSQL Database Operator then creates and manages the Database resource, which exposes the binding information in secrets, config maps, status, and spec attributes.

Prerequisites

  • You have created and deployed a Spring PetClinic sample application using the Developer perspective.
  • You have installed the Service Binding Operator from the OperatorHub.
  • You have installed the Crunchy Postgres for Kubernetes Operator from the OperatorHub using v5 Update channel.
  • You have created and deployed a Crunchy PostgreSQL database instance using the Developer perspective. This instance has the following four components: hippo-backup, hippo-instance, hippo-repo-host, and hippo-pgbouncer.

Procedure

  1. Switch to the Developer perspective and ensure that you are in the appropriate project, for example, my-petclinic. In the Topology view, hover over the Spring PetClinic sample application to see a dangling arrow on the node.
  2. Click and drag the arrow towards the hippo database Postgres Cluster to make a binding connection with the Spring PetClinic sample application.

    Alternatively, in the +Add view, click the YAML option to see the Import YAML screen. Use the YAML editor and add the ServiceBinding resource:

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

A service binding request is created and the Service Binding Operator controller projects the database service connection information into the application deployment as files using a volume mount. After the request is successful, the application is redeployed and the connection is established.

Figure 5.4. Binding connector

odc binding connector
Note

You can also use the context menu by dragging the dangling arrow to add and create a binding connection to an operator-backed service.

Figure 5.5. Context menu to create binding connection

odc context operator

5.9.3. Additional resources