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

  1. apiVersion: binding.operators.coreos.com/v1alpha1
  2. kind: ServiceBinding
  3. metadata:
  4. name: spring-petclinic-pgcluster
  5. namespace: my-petclinic
  6. spec:
  7. services: (1)
  8. - group: postgres-operator.crunchydata.com
  9. version: v1beta1
  10. kind: PostgresCluster
  11. name: hippo
  12. application: (2)
  13. name: spring-petclinic
  14. group: apps
  15. version: v1
  16. resource: deployments
1Specifies a list of service resources.
2The sample application that points to a Deployment or any other similar resource with an embedded PodSpec.

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

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 or Operator Lifecycle Manager (OLM) descriptors 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.

    1. host: hippo-pgbouncer
    2. 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.

    1. DATABASE_HOST: hippo-pgbouncer
    2. 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.

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

Advanced binding options

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

Changing the binding names before projecting them into the workload

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

Example: Spring PetClinic sample application in the ServiceBinding CR

  1. ...
  2. application:
  3. name: spring-petclinic
  4. group: apps
  5. version: v1
  6. resource: deployments
  7. ...

Example: PostgreSQL database service in the ServiceBinding CR

  1. ...
  2. services:
  3. - group: postgres-operator.crunchydata.com
  4. version: v1beta1
  5. kind: PostgresCluster
  6. name: hippo
  7. ...

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

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

  1. POSTGRESQL_DATABASE_HOST_ENV: hippo-pgbouncer
  2. POSTGRESQL_DATABASE_PORT_ENV: 5432

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

  • .name: Refers to the binding name exposed by the backing service. In the previous example, the binding names are HOST and PORT.

  • .service.kind: Refers to the kind of service resource whose binding names are changed with the naming strategy.

  • upper: String function used to post-process the character string while compiling the Go template string.

  • POSTGRESQL: Prefix of the custom binding name.

  • ENV: Suffix of the custom binding name.

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

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

  1. apiVersion: binding.operators.coreos.com/v1alpha1
  2. kind: ServiceBinding
  3. metadata:
  4. name: spring-petclinic-pgcluster
  5. namespace: my-petclinic
  6. spec:
  7. services:
  8. - group: postgres-operator.crunchydata.com
  9. version: v1beta1
  10. kind: PostgresCluster
  11. name: hippo (1)
  12. id: postgresDB (2)
  13. - group: ""
  14. version: v1
  15. kind: Secret
  16. name: hippo-pguser-hippo
  17. id: postgresSecret
  18. application:
  19. name: spring-petclinic
  20. group: apps
  21. version: v1
  22. resource: deployments
  23. mappings:
  24. ## From the database service
  25. - name: JDBC_URL
  26. value: 'jdbc:postgresql://{{ .postgresDB.metadata.annotations.proxy }}:{{ .postgresDB.spec.port }}/{{ .postgresDB.metadata.name }}'
  27. ## From both the services!
  28. - name: CREDENTIALS
  29. value: '{{ .postgresDB.metadata.name }}{{ translationService.postgresSecret.data.password }}'
  30. ## Generate JSON
  31. - name: DB_JSON (3)
  32. value: {{ json .postgresDB.status }} (4)
1Name of the backing service resource.
2Optional identifier.
3Generated JSON name that is to be projected as the file content or environment value. The JSON name contains the attributes of the backing service custom resource.
4Generated JSON value that is to be projected as the file content or environment value. The JSON value contains the attributes of the backing service custom resource.

Binding secondary workloads that are not compliant with PodSpec

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

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

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

Configuring the custom location of the container path

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

Example: Secondary workload CR

  1. apiVersion: "operator.sbo.com/v1"
  2. kind: SecondaryWorkload
  3. metadata:
  4. name: secondary-workload
  5. spec:
  6. containers:
  7. - name: hello-world
  8. image: quay.io/baijum/secondary-workload:latest
  9. ports:
  10. - 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

    1. apiVersion: binding.operators.coreos.com/v1alpha1
    2. kind: ServiceBinding
    3. metadata:
    4. name: spring-petclinic-pgcluster
    5. spec:
    6. services:
    7. - group: postgres-operator.crunchydata.com
    8. version: v1beta1
    9. kind: PostgresCluster
    10. name: hippo
    11. id: postgresDB
    12. - group: ""
    13. version: v1
    14. kind: Secret
    15. name: hippo-pguser-hippo
    16. id: postgresSecret
    17. application: (1)
    18. name: spring-petclinic
    19. group: apps
    20. version: v1
    21. resource: deployments
    22. application: (2)
    23. name: secondary-workload
    24. group: operator.sbo.com
    25. version: v1
    26. resource: secondaryworkloads
    27. bindingPath:
    28. containersPath: spec.containers (3)
    1The sample application that points to a Deployment or any other similar resource with an embedded PodSpec.
    2The secondary workload, which is not compliant with the PodSpec.
    3The 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

  1. apiVersion: "operator.sbo.com/v1"
  2. kind: SecondaryWorkload
  3. metadata:
  4. name: secondary-workload
  5. spec:
  6. containers:
  7. - env: (1)
  8. - name: ServiceBindingOperatorChangeTriggerEnvVar
  9. value: "31793"
  10. envFrom:
  11. - secretRef:
  12. name: secret-resource-name (2)
  13. image: quay.io/baijum/secondary-workload:latest
  14. name: hello-world
  15. ports:
  16. - containerPort: 8080
  17. resources: {}
1Unique array of containers with values generated by the Service Binding Operator. These values are based on the backing service CR.
2Name of the Secret resource generated by the Service Binding Operator.

Configuring the custom location of the secret path

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

Example: Secondary workload CR

  1. apiVersion: "operator.sbo.com/v1"
  2. kind: SecondaryWorkload
  3. metadata:
  4. name: secondary-workload
  5. spec:
  6. 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

    1. apiVersion: binding.operators.coreos.com/v1alpha1
    2. kind: ServiceBinding
    3. metadata:
    4. name: spring-petclinic-pgcluster
    5. spec:
    6. ...
    7. application: (1)
    8. name: secondary-workload
    9. group: operator.sbo.com
    10. version: v1
    11. resource: secondaryworkloads
    12. bindingPath:
    13. secretPath: spec.secret (2)
    14. ...
    1The secondary workload, which is not compliant with the PodSpec.
    2The 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

  1. ...
  2. apiVersion: "operator.sbo.com/v1"
  3. kind: SecondaryWorkload
  4. metadata:
  5. name: secondary-workload
  6. spec:
  7. secret: binding-request-72ddc0c540ab3a290e138726940591debf14c581 (1)
  8. ...
1Unique name of the Secret resource generated by the Service Binding Operator.

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:

    1. $ oc delete ServiceBinding <.metadata.name>

    Example

    1. $ oc delete ServiceBinding spring-petclinic-pgcluster

    where:

    spring-petclinic-pgcluster

    Specifies the name of the ServiceBinding CR.

Additional resources