Connecting applications to the services that support them—for example, establishing the exchange of credentials between a Java application and a database that it requires—is referred to as binding. The configuration and maintenance of this binding together of applications and backing services can be a tedious and inefficient process. Manually editing YAML files to define binding information is error-prone and can introduce difficult-to-debug failures.
Introduction to service binding
The goal of the Service Binding Operator is to solve this binding problem. By making it easier for application developers to bind applications with needed backing services, the Service Binding Operator also assists operator providers in promoting and expanding the adoption of their operators. This article introduces the Service Binding Operator and describes how it functions. In the next article, we'll demonstrate its use through a real-world example.
The case for managed binding
The Service Binding Operator enables applications to use external services by automatically collecting and sharing binding information (credentials, connection details, volume mounts, secrets, etc.) with the application. In effect, the Service Binding Operator defines a contract between a "bindable" backing service (for example, a database operator) and an application requiring that backing service.
Note that in addition to the initial sharing of binding information, the binding is also "managed" by the Service Binding Operator. This statement means that, if credentials or URLs undergo modification by the backing service operator, those changes are automatically reflected in the application.
There are two parts to this contract. The first part concerns making the backing service bindable and the second part concerns binding the application and the service together. Both parts are supported by a new custom resource, the
ServiceBindingRequest custom resource
The Service Binding Operator enables application developers to more easily bind applications together with operator-managed backing services (such as a database) without having to perform manual configuration of secrets, ConfigMaps, etc. The Service Binding Operator accomplishes this task by automatically collecting binding information and sharing it with an application and an operator-managed backing service. This binding is performed through a new custom resource called a
apiVersion: apps.openshift.io/v1alpha1 kind: ServiceBindingRequest metadata: name: binding-request namespace: service-binding-demo spec: applicationSelector: resourceRef: nodejs-rest-http-crud group: apps version: v1 resource: deployments backingServiceSelector: group: postgresql.baiju.dev version: v1alpha1 kind: Database resourceRef: db-demo
ServiceBindingRequest includes the following two selectors. The first is the
applicationSelector, which identifies the application to be bound with the backing service. The
ResourceRef defined here marks an application for binding. The second is the
backingServiceSelector, which identifies the backing service with which applications will be bound, as shown in Figure 1:
Additional data in the
ServiceBindingRequest can contain a combination of sensitive information such as usernames and passwords, plus non-sensitive information such as port numbers. In order to configure an existing operator to be bindable, an operator provider has to add a
ServiceBindingRequest descriptor to the operator’s manifest. The
statusDescriptors in that manifest will contain the information needed by the Service Binding Operator to bind the application together with the backing service operator.
Note: Sample backing service operators that are already bindable are available here.
Figure 2 illustrates the relationship between the
ServiceBindingRequest, its selectors, the application being bound, and the backing service. Note that for the
applicationSelector, the relevant attributes are the application’s group, version, resource, and
resourceRef, and that for the
backingServiceSelector, the relevant attributes are the version, kind, and
Making an operator-managed backing service bindable
To make a service bindable, the operator provider needs to express the information needed by applications to bind with the services provided by the operator. In other words, the operator provider must express the information that is interesting to applications.
The binding information is provided as annotations in the Custom Resource Definition (CRD) of the operator that manages the backing service. The Service Binding Operator extracts the annotations to bind the application together with the backing service.
For example, Figure 3 shows a bind-able operator's annotations in its CRD for a PostgreSQL database backing operator. Note the highlighted text and that
status.dbConfigMap is a
ConfigMap where the username and password are interesting for binding:
An alternate method for making a service bindable enables operators that manage backing services, but which do not have any metadata in their CSV to use the Service Binding Operator to bind together the service and applications. The Service Binding Operator binds all sub-resources defined in the backing service CR by populating the binding secret with information from the routes, services,
ConfigMaps, and secrets owned by the backing service CR.
Note: This is how resource and sub-resource relationships are set in Kubernetes.
The binding itself is initiated by the introduction of the API option in the backing service CR (as shown in Figure 4):
When this API option is set to
true, the Service Binding Operator automatically detects the routes, services,
ConfigMaps, and secrets owned by the backing service CR.
Binding an application together with a backing service
Manually binding an application together with a backing service without the Service Binding Operator is a time-consuming and error-prone process. The steps needed to perform the binding include:
- Locating the binding information in the backing service’s resources.
- Creating and referencing any necessary secrets.
- Manually editing the application’s
KnativeService, or anything else that uses a standard
PodSpecto reference the binding request.
In contrast, by using the Service Binding Operator, the only action that an application developer must make during the import of the application is to make clear the intent that the binding must be performed. This task is accomplished by creating the
ServiceBindingRequest. The Service Binding Operator takes that intent and performs the binding on behalf of the application developer.
In summary, there are two steps that an application developer must perform. First, they must signal the intent to bind the application to the backing service by adding labels to the application. Second, they must create a new
ServiceBindingRequest that references the backing service.
ServiceBindingRequest is created, the Service Binding Operator's controller collects the binding information into an intermediary secret, which it shares with the application through environment variables.
Note that an optional approach that can be used to provide binding information is through custom environment variables. We'll provide more on this topic, along with a real-world example, in the next article.
- The Service Binding Operator GitHub repo.
- A set of examples, each of which illustrates a usage scenario for the Service Binding Operator, is being developed in parallel with the Operator. Each example includes documentation and can be run either through the OpenShift web console or command-line client.
- Sample Backing Service Operators are available here.