Chapter 6. Connecting applications to services 6.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. The custom resource definition (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/ . 6.1.1. Support matrix Some features in this release are currently in Technology Preview . These experimental features are not intended for production use. In the table, 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 6.1. Support matrix Service Binding Operator API Group and Support Status OpenShift Versions Version binding.operators.coreos.com servicebinding.io 1.1.1 GA TP 4.7-4.10 1.1 GA TP 4.7-4.10 1.0.1 GA TP 4.7-4.9 1.0 GA TP 4.7-4.9 6.1.2. 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 . 6.1.3. Release notes for Service Binding Operator 1.1.1 Service Binding Operator 1.1.1 is now available on OpenShift Container Platform 4.7, 4.8, 4.9, and 4.10. 6.1.3.1. Fixed issues Before this update, a security vulnerability CVE-2021-38561 was noted for Service Binding Operator Helm chart. This update fixes the CVE-2021-38561 error and updates the golang.org/x/text package from v0.3.6 to v0.3.7. APPSVC-1124 Before this update, users of the Developer Sandbox did not have sufficient permissions to read ClusterWorkloadResourceMapping resources. As a result, Service Binding Operator prevented all service bindings from being successful. With this update, the Service Binding Operator now includes the appropriate role-based access control (RBAC) rules for any authenticated subject including the Developer Sandbox users. These RBAC rules allow the Service Binding Operator to get , list , and watch the ClusterWorkloadResourceMapping resources for the Developer Sandbox users and to process service bindings successfully. APPSVC-1135 6.1.3.2. Known issues There is currently a known issue with installing Service Binding Operator in a 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. When this happens, it generates an error message similar to the following example: 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 Currently, when you modify the ClusterWorkloadResourceMapping resources, the Service Binding Operator does not implement correct behavior. As a workaround, perform the following steps: Delete any ServiceBinding resources that use the corresponding ClusterWorkloadResourceMapping resource. Modify the ClusterWorkloadResourceMapping resource. Re-apply the ServiceBinding resources that you previously removed in step 1. APPSVC-1102 6.1.4. Release notes for Service Binding Operator 1.1 Service Binding Operator is now available on OpenShift Container Platform 4.7, 4.8, 4.9, and 4.10. 6.1.4.1. New features This section highlights what is new in Service Binding Operator 1.1: Service Binding Options Workload resource mapping: Define exactly where binding data needs to be projected for the secondary workloads. Bind new workloads using a label selector. 6.1.4.2. Fixed issues Before this update, service bindings that used label selectors to pick up workloads did not project service binding data into the new workloads that matched the given label selectors. As a result, the Service Binding Operator could not periodically bind such new workloads. With this update, service bindings now project service binding data into the new workloads that match the given label selector. The Service Binding Operator now periodically attempts to find and bind such new workloads. APPSVC-1083 6.1.4.3. Known issues There is currently a known issue with installing Service Binding Operator in a 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. When this happens, it generates an error message similar to the following example: 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 Currently, when you modify the ClusterWorkloadResourceMapping resources, the Service Binding Operator does not implement correct behavior. As a workaround, perform the following steps: Delete any ServiceBinding resources that use the corresponding ClusterWorkloadResourceMapping resource. Modify the ClusterWorkloadResourceMapping resource. Re-apply the ServiceBinding resources that you previously removed in step 1. APPSVC-1102 6.1.5. 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 Technology Preview Features Support Scope . 6.1.5.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 6.2. Support matrix Feature Service Binding Operator 1.0.1 binding.operators.coreos.com API group GA servicebinding.io API group TP 6.1.5.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 6.1.5.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 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 6.1.6. 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 Technology Preview Features Support Scope . 6.1.6.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 6.3. Support matrix Feature Service Binding Operator 1.0 binding.operators.coreos.com API group GA servicebinding.io API group TP 6.1.6.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). 6.1.7. Additional resources Understanding Service Binding Operator . 6.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. 6.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. 6.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. 6.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. 6.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 ServiceBinding 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) with the servicebinding.io API group. With Service Binding Operator, you can: Bind your workloads to Operator-managed backing services. Automate configuration of binding data. Provide service operators with a low-touch administrative experience to provision and manage access to services. Enrich the development lifecycle with a consistent and declarative service binding method that eliminates discrepancies in cluster environments. 6.2.3. Key features Exposal of binding data from services Based on annotations present in CRD, custom resources (CRs), or resources. 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). 6.2.4. API differences 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) with the servicebinding.io API group. Both of these API groups have similar features, but they are not completely identical. Here is the complete list of differences between these API groups: Feature Supported by the binding.operators.coreos.com API group Supported by the servicebinding.io API group Notes Binding to provisioned services Yes Yes Not applicable (N/A) Direct secret projection Yes Yes Not applicable (N/A) Bind as files Yes Yes Default behavior for the service bindings of the servicebinding.io API group Opt-in functionality for the service bindings of the binding.operators.coreos.com API group Bind as environment variables Yes Yes Default behavior for the service bindings of the binding.operators.coreos.com API group. Opt-in functionality for the service bindings of the servicebinding.io API group: Environment variables are created alongside files. Selecting workload with a label selector Yes Yes Not applicable (N/A) Detecting binding resources ( .spec.detectBindingResources ) Yes No The servicebinding.io API group has no equivalent feature. Naming strategies Yes No There is no current mechanism within the servicebinding.io API group to interpret the templates that naming strategies use. Container path Yes Partial Because a service binding of the binding.operators.coreos.com API group can specify mapping behavior within the ServiceBinding resource, the servicebinding.io API group cannot fully support an equivalent behavior without more information about the workload. Container name filtering No Yes The binding.operators.coreos.com API group has no equivalent feature. Secret path Yes No The servicebinding.io API group has no equivalent feature. Alternative binding sources (for example, binding data from annotations) Yes Allowed by Service Binding Operator The specification requires support for getting binding data from provisioned services and secrets. However, a strict reading of the specification suggests that support for other binding data sources is allowed. Using this fact, Service Binding Operator can pull the binding data from various sources (for example, pulling binding data from annotations). Service Binding Operator supports these sources on both the API groups. 6.2.5. Additional resources Getting started with service binding . 6.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. 6.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 In the Administrator perspective of the web console, navigate to Operators OperatorHub . Use the Filter by keyword box to search for Service Binding Operator in the catalog. Click the Service Binding Operator tile. Read the brief description about the Operator on the Service Binding Operator page. Click Install . On the Install Operator page: 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. 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. Select an Update Channel . By default, the stable channel enables installation of the latest stable and supported release of the Service Binding Operator. Click Install . Note The Operator is installed automatically into the openshift-operators namespace. On the Installed Operator - ready for use pane, click View Operator . You will see the Operator listed on the Installed Operators page. Verify that the Status is set to Succeeded to confirm successful installation of Service Binding Operator. 6.3.2. Additional Resources Getting started with service binding . 6.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 5.0.5 version of 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. 6.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 Create the PostgresCluster CR in the my-petclinic namespace by running the following command in shell: USD 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 After you have created the database instance, ensure that all the pods in the my-petclinic namespace are running: USD 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. 6.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 Deploy the spring-petclinic application with the PostgresCluster custom resource (CR) by running the following command in shell: USD 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 Verify that the application is not yet connected to the database service by running the following command: USD 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. 6.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 Create a ServiceBinding CR to project the binding data: USD 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 Verify that the request for service binding is successful: USD 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: USD 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/*/'USDi' -exec echo -n {}:" " \; -exec cat {} \;'; echo; done Example output: With all the values from the secret resource /bindings/spring-petclinic-pgcluster/username: <username> /bindings/spring-petclinic-pgcluster/password: <password> /bindings/spring-petclinic-pgcluster/host: hippo-primary.my-petclinic.svc /bindings/spring-petclinic-pgcluster/port: 5432 /bindings/spring-petclinic-pgcluster/type: postgresql Set up the port forwarding from the application port to access the sample application from your local environment: USD 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 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. 6.4.4. Additional Resources Installing Service Binding Operator . Creating applications using the Developer perspective . Managing resources from custom resource definitions . Known bindable Operators . 6.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. 6.5.1. Deploying a PostgreSQL Operator Procedure To deploy the Dev4Devs PostgreSQL Operator in the my-petclinic namespace run the following command in shell: USD 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 After the operator is installed, list the operator subscriptions in the openshift-operators namespace: USD 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 6.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 Create the Database CR in the my-petclinic namespace by running the following command in shell: USD 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 After you have created the database instance, ensure that all the pods in the my-petclinic namespace are running: USD 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. 6.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 Deploy the spring-petclinic application with the PostgresCluster custom resource (CR) by running the following command in shell: USD 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 Verify that the application is not yet connected to the database service by running the following command: USD 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. 6.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 Create a ServiceBinding CR to project the binding data: USD 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 Verify that the request for service binding is successful: USD 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. Once this is created, you can go to the topology to see the visual connection. Figure 6.1. Connecting spring-petclinic to a sample database Set up the port forwarding from the application port to access the sample application from your local environment: USD 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 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. 6.5.5. Additional resources Installing Service Binding Operator Creating applications using the Developer perspective Managing resources from custom resource definitions 6.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. 6.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 6.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: "<password>" user: "<username>" ... 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 Example: ServiceBinding resource in Specification API apiVersion: servicebinding.io/v1beta1 kind: ServiceBinding metadata: name: account-service spec: ... service: apiVersion: example.com/v1alpha1 kind: AccountService name: prod-account-service workload: 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. 6.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/v1beta1 kind: ServiceBinding metadata: name: account-service spec: ... service: apiVersion: v1 kind: Secret name: hippo-pguser-hippo 6.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 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: "<password>" user: "<username>" 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 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" 6.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 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. 6.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 6.4. Parameters and their descriptions Parameter Description Default 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. 6.6.3. Setting annotations mapping to be optional You can have optional fields in the annotations. For example, a path to the credentials might not be present if the service endpoint does not require authentication. In such cases, a field might not exist in the target path of the annotations. As a result, Service Binding Operator generates an error, by default. As a service provider, to indicate whether you require annotations mapping, you can set a value for the optional flag in your annotations when enabling services. Service Binding Operator provides annotations mapping only if the target path is available. When the target path is not available, the Service Binding Operator skips the optional mapping and continues with the projection of the existing mappings without throwing any errors. Procedure To make a field in the annotations optional, set the optional flag value to true : Example apiVersion: apps.example.org/v1beta1 kind: Database metadata: name: my-db namespace: my-petclinic annotations: service.binding/username: path={.spec.name},optional=true ... Note If you set the optional flag value to false and the Service Binding Operator is unable to find the target path, the Operator fails the annotations mapping. If the optional flag has no value set, the Service Binding Operator considers the value as false by default and fails the annotations mapping. 6.6.4. 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. 6.6.5. 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. 6.6.5.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} ... 6.6.5.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. 6.6.5.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: "<password>" user: "<username>" 6.6.5.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" 6.6.5.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} ... 6.6.5.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 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 example helps you to project all those values with keys such as primary , secondary , and so on. 6.6.5.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 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 6.6.5.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 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 6.6.6. Additional resources Defining cluster service versions (CSVs) . Projecting binding data . 6.7. Projecting binding data This section provides information on how you can consume the binding data. 6.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: By default, as files. As environment variables, after you configure the .spec.bindAsFiles parameter from the ServiceBinding resource. 6.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 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 Warning For using the binding data directory name to look up the binding data Service Binding Operator uses the ServiceBinding resource name ( .metadata.name ) as the binding data directory name. The spec also provides a way to override that name through the .spec.name field. As a result, there is a chance for binding data name collision if there are multiple ServiceBinding resources in the namespace. However, due to the nature of the volume mount in Kubernetes, the binding data directory will contain values from only one of the Secret resources. 6.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 6.5. Summary of the final path computation SERVICE_BINDING_ROOT Final path Not available /bindings/<ServiceBinding_ResourceName> dir/path/root dir/path/root/<ServiceBinding_ResourceName> In the 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). Note By default, the projected files get their permissions set to 0644. Service Binding Operator cannot set specific permissions due to a bug in Kubernetes that causes issues if the service expects specific permissions such as 0600 . As a workaround, you can modify the code of the program or the application that is running inside a workload resource to copy the file to the /tmp directory and set the appropriate permissions. 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 In the example, the bindings_list variable contains the binding data for the postgresql database service type. 6.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 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. 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). 6.7.4. Additional resources Exposing binding data from a service . Using the projected binding data in the source code of the application . 6.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 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. 6.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. 6.8.2. Advanced binding options You can define the ServiceBinding custom resource (CR) to use the following advanced binding options: Changing binding names: This option is available only for the binding.operators.coreos.com API group. Composing custom binding data: This option is available only for the binding.operators.coreos.com API group. Binding workloads using label selectors: This option is available for both the binding.operators.coreos.com and servicebinding.io API groups. 6.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 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 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 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. 6.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 The JSON name that the Service Binding Operator generates. The Service Binding Operator projects this JSON name as the name of a file or environment variable. 4 The JSON value that the Service Binding Operator generates. The Service Binding Operator projects this JSON value as a file or environment variable. The JSON value contains the attributes from your specified field of the backing service custom resource. 6.8.2.3. Binding workloads using a label selector You can use a label selector to specify the workload to bind. If you declare a service binding using the label selectors to pick up workloads, the Service Binding Operator periodically attempts to find and bind new workloads that match the given label selector. For example, as a cluster administrator, you can bind a service to every Deployment in a namespace with the environment: production label by setting an appropriate labelSelector field in the ServiceBinding CR. This enables the Service Binding Operator to bind each of these workloads with one ServiceBinding CR. Example ServiceBinding CR in the binding.operators.coreos.com/v1alpha1 API apiVersion: binding.operators.coreos.com/v1alpha1 kind: ServiceBinding metadata: name: multi-application-binding namespace: service-binding-demo spec: application: labelSelector: 1 matchLabels: environment: production group: apps version: v1 resource: deployments services: group: "" version: v1 kind: Secret name: super-secret-data 1 Specifies the workload that is being bound. Example ServiceBinding CR in the servicebinding.io API apiVersion: servicebindings.io/v1beta1 kind: ServiceBinding metadata: name: multi-application-binding namespace: service-binding-demo spec: workload: selector: 1 matchLabels: environment: production apiVersion: app/v1 kind: Deployment service: apiVersion: v1 kind: Secret name: super-secret-data 1 Specifies the workload that is being bound. Important If you define the following pairs of fields, Service Binding Operator refuses the binding operation and generates an error: The name and labelSelector fields in the binding.operators.coreos.com/v1alpha1 API. The name and selector fields in the servicebinding.io API (Spec API). Understanding the rebinding behavior Consider a case where, after a successful binding, you use the name field to identify a workload. If you delete and recreate that workload, the ServiceBinding reconciler does not rebind the workload, and the Operator cannot project the binding data to the workload. However, if you use the labelSelector field to identify a workload, the ServiceBinding reconciler rebinds the workload, and the Operator projects the binding data. 6.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. In Service Binding Operator, you can configure the path of where containers or secrets reside within a workload and bind these paths at a custom location. 6.8.3.1. Configuring the custom location of the container path This custom location is available for the binding.operators.coreos.com API group when Service Binding Operator projects the binding data as environment variables. 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. 6.8.3.2. Configuring the custom location of the secret path This custom location is available for the binding.operators.coreos.com API group when Service Binding Operator projects the binding data as environment variables. 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 The unique name of the Secret resource that Service Binding Operator generates. 6.8.3.3. Workload resource mapping Note Workload resource mapping is available for the secondary workloads of the ServiceBinding custom resource (CR) for both the API groups: binding.operators.coreos.com and servicebinding.io . You must define ClusterWorkloadResourceMapping resources only under the servicebinding.io API group. However, the ClusterWorkloadResourceMapping resources interact with ServiceBinding resources under both the binding.operators.coreos.com and servicebinding.io API groups. If you cannot configure custom path locations by using the configuration method for container path, you can define exactly where binding data needs to be projected. Specify where to project the binding data for a given workload kind by defining the ClusterWorkloadResourceMapping resources in the servicebinding.io API group. The following example shows how to define a mapping for the CronJob.batch/v1 resources. Example: Mapping for CronJob.batch/v1 resources apiVersion: servicebinding.io/v1beta1 kind: ClusterWorkloadResourceMapping metadata: name: cronjobs.batch 1 spec: versions: - version: "v1" 2 annotations: .spec.jobTemplate.spec.template.metadata.annotations 3 containers: - path: .spec.jobTemplate.spec.template.spec.containers[*] 4 - path: .spec.jobTemplate.spec.template.spec.initContainers[*] name: .name 5 env: .env 6 volumeMounts: .volumeMounts 7 volumes: .spec.jobTemplate.spec.template.spec.volumes 8 1 Name of the ClusterWorkloadResourceMapping resource, which must be qualified as the plural.group of the mapped workload resource. 2 Version of the resource that is being mapped. Any version that is not specified can be matched with the "*" wildcard. 3 Optional: Identifier of the .annotations field in a pod, specified with a fixed JSONPath. The default value is .spec.template.spec.annotations . 4 Identifier of the .containers and .initContainers fields in a pod, specified with a JSONPath. If no entries under the containers field are defined, the Service Binding Operator defaults to two paths: .spec.template.spec.containers[*] and .spec.template.spec.initContainers[\*] , with all other fields set as their default. However, if you specify an entry, then you must define the .path field. 5 Optional: Identifier of the .name field in a container, specified with a fixed JSONPath. The default value is .name . 6 Optional: Identifier of the .env field in a container, specified with a fixed JSONPath. The default value is .env . 7 Optional: Identifier of the .volumeMounts field in a container, specified with a fixed JSONPath. The default value is .volumeMounts . 8 Optional: Identifier of the .volumes field in a pod, specified with a fixed JSONPath. The default value is .spec.template.spec.volumes . Important In this context, a fixed JSONPath is a subset of the JSONPath grammar that accepts only the following operations: Field lookup: .spec.template Array indexing: .spec['template'] All other operations are not accepted. Most of these fields are optional. When they are not specified, the Service Binding Operator assumes defaults compatible with PodSpec resources. The Service Binding Operator requires that each of these fields is structurally equivalent to the corresponding field in a pod deployment. For example, the contents of the .env field in a workload resource must be able to accept the same structure of data that the .env field in a Pod resource would. Otherwise, projecting binding data into such a workload might result in unexpected behavior from the Service Binding Operator. Behavior specific to the binding.operators.coreos.com API group You can expect the following behaviors when ClusterWorkloadResourceMapping resources interact with ServiceBinding resources under the binding.operators.coreos.com API group: If a ServiceBinding resource with the bindAsFiles: false flag value is created together with one of these mappings, then environment variables are projected into the .envFrom field underneath each path field specified in the corresponding ClusterWorkloadResourceMapping resource. As a cluster administrator, you can specify both a ClusterWorkloadResourceMapping resource and the .spec.application.bindingPath.containersPath field in a ServiceBinding.bindings.coreos.com resource for binding purposes. The Service Binding Operator attempts to project binding data into the locations specified in both a ClusterWorkloadResourceMapping resource and the .spec.application.bindingPath.containersPath field. This behavior is equivalent to adding a container entry to the corresponding ClusterWorkloadResourceMapping resource with the path: USDcontainersPath attribute, with all other values taking their default value. 6.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: USD oc delete ServiceBinding <.metadata.name> Example USD oc delete ServiceBinding spring-petclinic-pgcluster where: spring-petclinic-pgcluster Specifies the name of the ServiceBinding CR. 6.8.5. Additional resources Binding a workload together with a backing service . Connecting the Spring PetClinic sample application to the PostgreSQL database service Creating custom resources from a file Example schema of the ClusterWorkloadResourceMapping resource . 6.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. 6.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 Hover over the Spring PetClinic sample application to see a dangling arrow on the node. Figure 6.2. Visual connector Click and drag the arrow towards the hippo-pgbouncer deployment to connect the Spring PetClinic sample application with it. 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 6.3. Connecting multiple applications 6.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 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. Click and drag the arrow towards the hippo database in the Postgres Cluster to make a binding connection with the Spring PetClinic sample application. A Create Service Binding dialog box appears. Enter the name and click Create . Figure 6.4. Service Binding modal 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 6.5. 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 6.6. Context menu to create binding connection 6.9.3. Additional resources Getting started with service binding . Known bindable Operators .

Commands:
`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"`
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
`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"`
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
`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"`
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
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
postgrescluster.postgres-operator.crunchydata.com/hippo created
oc get pods -n my-petclinic
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
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
deployment.apps/spring-petclinic created service/spring-petclinic created
oc get pods -n my-petclinic
NAME READY STATUS RESTARTS AGE spring-petclinic-5b4c7999d4-wzdtz 0/1 CrashLoopBackOff 4 (13s ago) 2m25s
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
servicebinding.binding.operators.coreos.com/spring-petclinic created
oc get servicebindings -n my-petclinic
NAME READY REASON AGE spring-petclinic-pgcluster True ApplicationsBound 7s
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/*/'USDi' -exec echo -n {}:" " \; -exec cat {} \;'; echo; done
/bindings/spring-petclinic-pgcluster/username: <username> /bindings/spring-petclinic-pgcluster/password: <password> /bindings/spring-petclinic-pgcluster/host: hippo-primary.my-petclinic.svc /bindings/spring-petclinic-pgcluster/port: 5432 /bindings/spring-petclinic-pgcluster/type: postgresql
oc port-forward --address 0.0.0.0 svc/spring-petclinic 8080:80 -n my-petclinic
Forwarding from 0.0.0.0:8080 -> 8080 Handling connection for 8080
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
oc get subs -n openshift-operators
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
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
database.postgresql.dev4devs.com/sampledatabase created
oc get pods -n my-petclinic
NAME READY STATUS RESTARTS AGE sampledatabase-cbc655488-74kss 0/1 Running 0 32s
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
deployment.apps/spring-petclinic created service/spring-petclinic created
oc get pods -n my-petclinic
NAME READY STATUS RESTARTS AGE spring-petclinic-5b4c7999d4-wzdtz 0/1 CrashLoopBackOff 4 (13s ago) 2m25s
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
servicebinding.binding.operators.coreos.com/spring-petclinic created
oc get servicebindings -n my-petclinic
NAME READY REASON AGE spring-petclinic-postgresql True ApplicationsBound 47m
oc port-forward --address 0.0.0.0 svc/spring-petclinic 8080:80 -n my-petclinic
Forwarding from 0.0.0.0:8080 -> 8080 Handling connection for 8080
apiVersion: example.com/v1alpha1 kind: AccountService name: prod-account-service spec: status: binding: name: hippo-pguser-hippo
apiVersion: v1 kind: Secret metadata: name: hippo-pguser-hippo data: password: "<password>" user: "<username>"
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
apiVersion: servicebinding.io/v1beta1 kind: ServiceBinding metadata: name: account-service spec: service: apiVersion: example.com/v1alpha1 kind: AccountService name: prod-account-service workload: apiVersion: apps/v1 kind: Deployment name: spring-petclinic
apiVersion: binding.operators.coreos.com/v1alpha1 kind: ServiceBinding metadata: name: account-service spec: services: - group: "" version: v1 kind: Secret name: hippo-pguser-hippo
apiVersion: servicebinding.io/v1beta1 kind: ServiceBinding metadata: name: account-service spec: service: apiVersion: v1 kind: Secret name: hippo-pguser-hippo
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'
apiVersion: v1 kind: Secret metadata: name: hippo-pguser-hippo data: password: "<password>" user: "<username>"
apiVersion: postgres-operator.crunchydata.com/v1beta1 kind: PostgresCluster metadata: name: hippo namespace: my-petclinic annotations: service.binding: 'path={.metadata.name}-config,objectType=ConfigMap'
apiVersion: v1 kind: ConfigMap metadata: name: hippo-config data: db_timeout: "10s" user: "hippo"
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
service.binding(/<NAME>)?: "<VALUE>|(path=<JSONPATH_TEMPLATE>(,objectType=<OBJECT_TYPE>)?(,elementType=<ELEMENT_TYPE>)?(,sourceKey=<SOURCE_KEY>)?(,sourceValue=<SOURCE_VALUE>)?)"
apiVersion: apps.example.org/v1beta1 kind: Database metadata: name: my-db namespace: my-petclinic annotations: service.binding/username: path={.spec.name},optional=true
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
apiVersion: postgres-operator.crunchydata.com/v1beta1 kind: PostgresCluster metadata: name: hippo namespace: my-petclinic annotations: service.binding/username: path={.metadata.name}
apiVersion: postgres-operator.crunchydata.com/v1beta1 kind: PostgresCluster metadata: name: hippo namespace: my-petclinic annotations: "service.binding/type": "postgresql" 1
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'
apiVersion: v1 kind: Secret metadata: name: hippo-pguser-hippo data: password: "<password>" user: "<username>"
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'
apiVersion: v1 kind: ConfigMap metadata: name: hippo-config data: db_timeout: "10s" user: "hippo"
apiVersion: postgres-operator.crunchydata.com/v1beta1 kind: PostgresCluster metadata: name: hippo namespace: my-petclinic annotations: service.binding/username: path={.metadata.name}
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
/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
status: connections: - type: primary url: primary.example.com - type: secondary url: secondary.example.com - type: '404' url: black-hole.example.com
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
/bindings/<binding-name>/tags_0 => knowledge /bindings/<binding-name>/tags_1 => is /bindings/<binding-name>/tags_2 => power
spec: tags: - knowledge - is - power
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
/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
USDSERVICE_BINDING_ROOT 1 ├── account-database 2 │ ├── type 3 │ ├── provider 4 │ ├── uri │ ├── username │ └── password └── transaction-event-stream 5 ├── type ├── connection-count ├── uri ├── certificates └── private-key
import os username = os.getenv("USERNAME") password = os.getenv("PASSWORD")
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")
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
host: hippo-pgbouncer port: 5432
DATABASE_HOST: hippo-pgbouncer DATABASE_PORT: 5432
application: name: spring-petclinic group: apps version: v1 resource: deployments
services: - group: postgres-operator.crunchydata.com version: v1beta1 kind: PostgresCluster name: hippo
DATABASE_HOST: hippo-pgbouncer
POSTGRESQL_DATABASE_HOST_ENV: hippo-pgbouncer POSTGRESQL_DATABASE_PORT_ENV: 5432
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
apiVersion: binding.operators.coreos.com/v1alpha1 kind: ServiceBinding metadata: name: multi-application-binding namespace: service-binding-demo spec: application: labelSelector: 1 matchLabels: environment: production group: apps version: v1 resource: deployments services: group: "" version: v1 kind: Secret name: super-secret-data
apiVersion: servicebindings.io/v1beta1 kind: ServiceBinding metadata: name: multi-application-binding namespace: service-binding-demo spec: workload: selector: 1 matchLabels: environment: production apiVersion: app/v1 kind: Deployment service: apiVersion: v1 kind: Secret name: super-secret-data
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
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
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: {}
apiVersion: "operator.sbo.com/v1" kind: SecondaryWorkload metadata: name: secondary-workload spec: secret: ""
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
apiVersion: "operator.sbo.com/v1" kind: SecondaryWorkload metadata: name: secondary-workload spec: secret: binding-request-72ddc0c540ab3a290e138726940591debf14c581 1
apiVersion: servicebinding.io/v1beta1 kind: ClusterWorkloadResourceMapping metadata: name: cronjobs.batch 1 spec: versions: - version: "v1" 2 annotations: .spec.jobTemplate.spec.template.metadata.annotations 3 containers: - path: .spec.jobTemplate.spec.template.spec.containers[*] 4 - path: .spec.jobTemplate.spec.template.spec.initContainers[*] name: .name 5 env: .env 6 volumeMounts: .volumeMounts 7 volumes: .spec.jobTemplate.spec.template.spec.volumes 8
oc delete ServiceBinding <.metadata.name>
oc delete ServiceBinding spring-petclinic-pgcluster
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