Introduction Link to heading
Kubernetes is around for almost 7 years now! Ever since the beggining there have been efforts to make consuming / binding to services simpler. And while discovering the actual service is not so much of an issue (if you employ a set of conventions), getting the credentials etc is slightly trickier.
The Service Catalog has been an effort that promised to simplify provisioning and binding to services, but it seems that it has lost its momentum. The lack of uniformity between providers, the differences in how each service communicated the binding information and the fact that people tend to favor operators for provisioning services made it pretty hard to use in practice.
The Service Binding Operator is a more recent and modern initiative. It stays out of the way of service provisioning (leaving that to operators) and focuses on how to best communicate the binding information to the application. An interesting part of the specification is the workload projection, which defines a directory structure that will be mounted to the application container when the binding happens in order to pass all the required binding information:
- type
- uri
- credentials
Other parts of the specification are related to the `ServiceBinding` resource (which controls what services are bound to which application and how).
Quarkus already supports the workload projection part of the spec and recently received enhancments on the binding part, which is going to be the focus of this post. In particular this post is going to discuss how the `ServiceBinding` can be automatically genenerated for the user and will walk you through the whole process from installing the needed operators to configuring and deploying the application.
For the shake of this post we are going to use kind install the Service Binding Operator and the Crunchy data operator for Postgres. Then, we are going to create a postgres cluster and finally we will create a simple todo application, deploy and bind it to the provisioned postgres.
Start a new kind cluster Link to heading
If you’ve already created one, or don’t use kind at all, feel free to skip.
|
|
Install the OLM Link to heading
Both operators that will be installed in this post, will be installed through the Operatorhub. So, the first step is to install the Operator Lifecycle Manager.
|
|
Install the Service Binding Operator Link to heading
|
|
To verify the installation execute the following command.
|
|
When the `phase` of the Service Binding Operator is `Succeeded` you may proceed to the next step.
Install the Postgres Crunchy Operator Link to heading
|
|
As above to verify the installation execute:
|
|
When the `phase` of the operator is `Succeeded` you may proceed to the next step.
Create a Postgres cluster Link to heading
We shall create a new namespace, where we will install our cluster and application:
|
|
To create the cluster we need to apply the following custom resource:
|
|
This resource has been borrowed from Service Binding Operator Quickstart, which is definitely something worth looking into (if you haven’t already).
Let’s save that file under `pg-cluster.yml` and apply it using `kubectl`
|
|
Let’s check the pods to verify the installation:
|
|
Create a Quarkus application that will bind to Postgres Link to heading
The application we are going to create is going to be a simple `todo` application that will connect to postgres via hibernate and panache.
The application that we will create is heavily inspired by Clement Escoffier’s Quarkus TODO app, but will focus less on the presentation and more on the binding aspect.
We will generate the application using the following maven command.
|
|
The next step is to add all required extensions for connecting to postgres, generating all required kubernetes resources and building the a container image for our application using docker.
|
|
At this point we need to create a simple entity:
|
|
And expose that via rest:
|
|
Bind to the target Postgres cluster
In order to bind the postgres service to our application we need to either provide a `ServiceBidning` resource or have it generated. To have the binding generated for us we need to provide the service coordinates:
apiVersion: `postgres-operator.crunchydata.com/v1beta1`
kind: `PostgresCluster`
name: `pg-cluster`
prefixed with `quarkus.kubernetes-service-binding.services.<id>.` as shown below:
1 2 3
quarkus.kubernetes-service-binding.services.my-db.api-version=postgres-operator.crunchydata.com/v1beta1 quarkus.kubernetes-service-binding.services.my-db.kind=PostgresCluster quarkus.kubernetes-service-binding.services.my-db.name=pg-cluster
The `id` is just used to group properties together and can be anything.
In addition to the configuration above we also need to configure the datasource:
1 2 3
quarkus.datasource.db-kind=postgresql quarkus.hibernate-orm.database.generation=drop-and-create quarkus.hibernate-orm.sql-load-script=import.sql
Finally, we will use `IfNotPresent` as image pull policy since we are not pushing our image to a registry and we just load it to the cluster.
1
quarkus.kubernetes.image-pull-policy=IfNotPresent
So, the application.properties file should look like:
1 2 3 4 5 6 7 8 9
quarkus.kubernetes-service-binding.services.my-db.api-version=postgres-operator.crunchydata.com/v1beta1 quarkus.kubernetes-service-binding.services.my-db.kind=PostgresCluster quarkus.kubernetes-service-binding.services.my-db.name=pg-cluster quarkus.datasource.db-kind=postgresql quarkus.hibernate-orm.database.generation=drop-and-create quarkus.hibernate-orm.sql-load-script=import.sql quarkus.kubernetes.image-pull-policy=IfNotPresent
Now, let’s create an import sql script with some intial data.
1
INSERT INTO todo(id, title, completed) VALUES (nextval('hibernate_sequence'), 'Finish the blog post', false);
Prepare for deployment Link to heading
To deploy, we need to perform a container image build, load the image to our cluster (remember we are using kind), generate the resource and perform the deployment.
Build the container image
To build the container image, you can use:
1
mvn clean install -Dquarkus.container-image.build=true -DskipTests
This assumes that you have docker up and running.
Load the docker image to the cluster
1
kind load docker-image iocanel/todo-example:1.0.0-SNAPSHOT
Loading the image on minikube
If you are using minikube instead, then execute:
1
eval $(minikube docker-env)
and re-build the image.
When using tools like kind or minikube, it is generally a good idea to change the image pull policy to `IfNotPresent` to avoid uneeded pulls, since most of the time the image will be loaded from the local docker daemon, as shown above. To set the image pull policy, we set `quarkus.kubernetes.image-pull-policy=IfNotPresent` as already shown above.
Deploy the application Link to heading
The next step will generate the deployment manifest, including the `ServiceBinding` and will apply them on kubernetes.
|
|
To verify everything is up and running:
|
|
Verify the installation Link to heading
The simplest way to verify that everything works as expected is to port forward to http port locally and access the `/todo` endpoint:
|
|
Open your browser on http://localhost:8080/todo and enjoy!
Thoughts and future steps Link to heading
I am really excited with the progress on the Service binding front. Thinks are looking great and can look even better. Some potential improvements I can see coming in the near future, is reducing the amount of needed configuration, with the use of smart conventions (e.g. assuming that custom resource name is the i same as the database name unless explicitly specified) and a reasonable set of defaults (e.g. assuming that for postgres the default operator is CrunchyData operator). This could even allow us to bind to services with zero config, without really sacrificing in flexibility and customizability!
I hope I could get you even half as excited as I am!