|
| 1 | +#+BLOG: iocanel.com |
| 2 | +#+ORG2BLOG: |
| 3 | +#+OPTIONS: toc:nil num:nil todo:nil pri:nil tags:nil ^:nil |
| 4 | +#+TITLE: Using Quarkus with the Service Binding Operator |
| 5 | +#+DESCRIPTION: A quick walkthrough on how to use Quarkus with the Service Binding Operator |
| 6 | +#+CATEGORY: Hints, Cloud, Development |
| 7 | +#+TAGS: Java, Quarkus, Kubernetes |
| 8 | + |
| 9 | +* Introduction |
| 10 | + |
| 11 | + [[https://kubernetes.io][Kubernetes]] is around for almost 7 years now and ever since the beggining there have been efforts to make consuming / binding to services simpler. |
| 12 | + 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. |
| 13 | + |
| 14 | + The [[https://svc-cat.io][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 |
| 15 | + 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. |
| 16 | + |
| 17 | + The [[https://github.com/redhat-developer/service-binding-operator][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. |
| 18 | + An interesting part of the specification is the [[https://github.com/servicebinding/spec#workload-projection][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: |
| 19 | + |
| 20 | + - type |
| 21 | + - uri |
| 22 | + - credentials |
| 23 | + |
| 24 | + Other parts of the specification are related to the `ServiceBinding` resource (which controls what services are bound to which application and how). |
| 25 | + |
| 26 | + [[https://quarkus.io/][Quarkus]] already supports the [[https://github.com/servicebinding/spec#workload-projection][workload projection]] part of the spec and recently received enhancments on the binding part, which is going to be the focus of this post. |
| 27 | + 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. |
| 28 | + |
| 29 | + For the shake of this post I am going to use [[https://kind.sigs.k8s.io/][kind]] where I am going to install the [[https://github.com/redhat-developer/service-binding-operator][Service Binding Operator]] and the [[https://github.com/CrunchyData/postgres-operator][Crunchy data operator for Postgres]]. |
| 30 | + Then, I am going to create a postgres cluster and finally I am going to use one of the [[https://quarkus.io/][Quarkus]] quickstarts to bind to the provisioned postgres. |
| 31 | + |
| 32 | +** Start a new kind cluster |
| 33 | + |
| 34 | + If you've already created one, or don't use [[https://kind.sigs.k8s.io/][kind]] at all, feel free to skip. |
| 35 | + |
| 36 | + #+begin_src sh |
| 37 | + kind create cluster |
| 38 | + #+end_src |
| 39 | + |
| 40 | +** Install the OLM |
| 41 | + |
| 42 | + Both operators that will be installed in this post, will be installed through the [[https://operatorhub.io][Operatorhub]]. |
| 43 | + So, the first step is to install the [[https://olm.operatorframework.io/][Operator Lifecycle Manager]]. |
| 44 | + |
| 45 | + #+begin_src sh |
| 46 | + curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.19.1/install.sh | bash -s v0.19.1 |
| 47 | + #+end_src |
| 48 | + |
| 49 | +** Install the Service Binding Operator |
| 50 | + |
| 51 | + #+begin_src sh |
| 52 | + kubectl create -f https://operatorhub.io/install/service-binding-operator.yaml |
| 53 | + #+end_src |
| 54 | + |
| 55 | + To verify the installation execute the following command. |
| 56 | + |
| 57 | + #+begin_src sh |
| 58 | + kubectl get csv -n operators |
| 59 | + #+end_src |
| 60 | + |
| 61 | + When the `phase` of the [[https://github.com/redhat-developer/service-binding-operator][Service Binding Operator]] is `Succeeded` you may proceed to the next step. |
| 62 | + |
| 63 | +** Install the Postgres Crunchy Operator |
| 64 | + |
| 65 | + #+begin_src sh |
| 66 | + kubectl create -f https://operatorhub.io/install/postgresql.yaml |
| 67 | + #+end_src |
| 68 | + |
| 69 | + As above to verify the installation execute: |
| 70 | + |
| 71 | + #+begin_src sh |
| 72 | + kubectl get csv -n operators |
| 73 | + #+end_src |
| 74 | + |
| 75 | + When the `phase` of the operator is `Succeeded` you may proceed to the next step. |
| 76 | + |
| 77 | + |
| 78 | +** Create a Postgres cluster |
| 79 | + |
| 80 | + We shall create a new namespace, where we will install our cluster and application |
| 81 | + |
| 82 | + #+begin_src sh |
| 83 | + kubectl create ns demo |
| 84 | + kubectl config set-context --current --namespace=demo |
| 85 | + #+end_src |
| 86 | + |
| 87 | + |
| 88 | + To create the cluster we need to apply the following custom resource: |
| 89 | + |
| 90 | + #+begin_src yaml :tangle ~/pg-cluster.yml |
| 91 | +apiVersion: postgres-operator.crunchydata.com/v1beta1 |
| 92 | +kind: PostgresCluster |
| 93 | +metadata: |
| 94 | + name: pg-cluster |
| 95 | + namespace: demo |
| 96 | +spec: |
| 97 | + image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres-ha:centos8-13.4-0 |
| 98 | + postgresVersion: 13 |
| 99 | + instances: |
| 100 | + - name: instance1 |
| 101 | + dataVolumeClaimSpec: |
| 102 | + accessModes: |
| 103 | + - "ReadWriteOnce" |
| 104 | + resources: |
| 105 | + requests: |
| 106 | + storage: 1Gi |
| 107 | + backups: |
| 108 | + pgbackrest: |
| 109 | + image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:centos8-2.33-2 |
| 110 | + repos: |
| 111 | + - name: repo1 |
| 112 | + volume: |
| 113 | + volumeClaimSpec: |
| 114 | + accessModes: |
| 115 | + - "ReadWriteOnce" |
| 116 | + resources: |
| 117 | + requests: |
| 118 | + storage: 1Gi |
| 119 | + - name: repo2 |
| 120 | + volume: |
| 121 | + volumeClaimSpec: |
| 122 | + accessModes: |
| 123 | + - "ReadWriteOnce" |
| 124 | + resources: |
| 125 | + requests: |
| 126 | + storage: 1Gi |
| 127 | + proxy: |
| 128 | + pgBouncer: |
| 129 | + image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:centos8-1.15-2 |
| 130 | + #+end_src |
| 131 | + |
| 132 | + This resource has been borrowed from [[https://redhat-developer.github.io/service-binding-operator/userguide/getting-started/quick-start.html][Service Binding Operator Quickstart]], which is definitely something worth looking into (if you haven't already). |
| 133 | + |
| 134 | + Let's save that file under `pg-cluster.yml` and apply it using `kubectl` |
| 135 | + |
| 136 | + #+begin_src sh |
| 137 | + kubectl apply -f ~/pg-cluster.yml |
| 138 | + #+end_src |
| 139 | + |
| 140 | + Let's check the pods to verify the installation: |
| 141 | + |
| 142 | + #+begin_src sh |
| 143 | + kubectl get pods -n demo |
| 144 | + #+end_src |
| 145 | + |
| 146 | +** Create a Quarkus application that will bind to Postgres |
| 147 | + |
| 148 | + Instead of creating an application from scratch, I am going to use one of the [[https://github.com/quarkusio/quarkus-quickstarts.git][Quarkus Quickstarts]]. |
| 149 | + |
| 150 | +*** Grab a quickstart that uses postgres |
| 151 | + |
| 152 | + The quickstart repository is quite large, So if you don't want to [[clone the repo]] you can just perform a [[sparse checkout]]. |
| 153 | + Both ways are demonstrated below and in both cases the quickstart from `2.3.1.Final` tag should be available under `~/quickstarts/hibernate-orm-panache-quickstart`. |
| 154 | + |
| 155 | +**** clone the repo |
| 156 | + |
| 157 | + #+begin_src sh |
| 158 | + git clone --depth 1 --branch 2.3.1.Final [email protected]:quarkusio/quarkus-quickstarts.git ~/quickstarts |
| 159 | + cd ~/quickstarts/hibernate-orm-panache-quickstart |
| 160 | + #+end_src |
| 161 | + |
| 162 | +**** sparse checkout |
| 163 | + |
| 164 | + #+begin_src sh |
| 165 | + mkdir ~/quickstarts |
| 166 | + cd ~/quickstarts |
| 167 | + git init |
| 168 | + git config core.sparseCheckout true |
| 169 | + git remote add origin [email protected]:quarkusio/quarkus-quickstarts.git |
| 170 | + echo "hibernate-orm-panache-quickstart/" > .git/info/sparse-checkout |
| 171 | + git pull origin 2.3.1.Final |
| 172 | + cd hibernate-orm-panache-quickstart |
| 173 | + #+end_src |
| 174 | + |
| 175 | + |
| 176 | +*** Add the Kubernetes and Service Binding extensions |
| 177 | + |
| 178 | + #+begin_src sh :dir ~/quickstarts/hibernate-orm-panache-quickstart/ |
| 179 | + quarkus ext add -B kubernetes |
| 180 | + quarkus ext add -B kubernetes-service-binding |
| 181 | + quarkus ext add -B container-image-docker |
| 182 | + #+end_src |
| 183 | + |
| 184 | +*** Bind to the target Postgres cluster |
| 185 | + |
| 186 | + In order to bind the postgres service to our application we need to either provide a `ServiceBidning` resource or have it generated. |
| 187 | + To have the binding generated for us we need to provide the service coordinates: |
| 188 | + |
| 189 | + - apiVersion: `postgres-operator.crunchydata.com/v1beta1` |
| 190 | + - kind: `PostgresCluster` |
| 191 | + - name: `pg-cluster` |
| 192 | + |
| 193 | + prefixed with `quarkus.kubernetes-service-binding.services.<id>.` as shown below: |
| 194 | + |
| 195 | + #+begin_src sh |
| 196 | + echo "quarkus.kubernetes-service-binding.services.my-db.api-version=postgres-operator.crunchydata.com/v1beta1 |
| 197 | + quarkus.kubernetes-service-binding.services.my-db.kind=PostgresCluster |
| 198 | + quarkus.kubernetes-service-binding.services.my-db.name=pg-cluster" >> ~/quickstarts/hibernate-orm-panache-quickstart/src/main/resources/application.properties |
| 199 | + #+end_src |
| 200 | + |
| 201 | + *Note*: The <id> can be anything at this point. It's only used for correlating the service coordinates. |
| 202 | + |
| 203 | +*** Switch the latest Quarkus version |
| 204 | + |
| 205 | + Generation of the Service Binding resource is not available in `2.3.1.Final` so we are going to switch to a snapshot version. |
| 206 | + This means that you need to checkout and build quarkus from latest `main`. |
| 207 | + This post assumes you have already done so and skips directly to the next step, which is switching to the snapshot version: |
| 208 | + |
| 209 | + #+begin_src sh :dir ~/quickstarts/hibernate-orm-panache-quickstart |
| 210 | + sed -i "s|2.3.1.Final|999-SNAPSHOT|g" pom.xml |
| 211 | + #+end_src |
| 212 | + |
| 213 | +*** Prepare for deployment |
| 214 | + |
| 215 | + To deploy, we need to perform a container image build, load the image to our cluster (remember we are using [[https://kind.sigs.k8s.io/][kind]]), generate the resource and perform the deployment. |
| 216 | + |
| 217 | +**** Build the container image |
| 218 | + |
| 219 | + To build the container image, you can use: |
| 220 | + |
| 221 | + #+begin_src sh :dir ~/quickstarts/hibernate-orm-panache-quickstart |
| 222 | + mvn clean install -Dquarkus.container-image.build=true -DskipTests |
| 223 | + #+end_src |
| 224 | + |
| 225 | + This assumes that you have docker up and running. |
| 226 | + |
| 227 | +**** Load the docker image to the cluster |
| 228 | + |
| 229 | + #+begin_src sh |
| 230 | + kind load docker-image iocanel/hibernate-orm-panache-quickstart:1.0.0-SNAPSHOT |
| 231 | + #+end_src |
| 232 | + |
| 233 | +***** Loading the image on minikube |
| 234 | + |
| 235 | + If you are using [[https://minikube.sigs.k8s.io/docs/start/][minikube]] instead, then execute: |
| 236 | + #+begin_src sh |
| 237 | + eval $(minikube docker-env) |
| 238 | + #+end_src |
| 239 | + |
| 240 | + and re-build the image. |
| 241 | + |
| 242 | + When using tools like [[https://kind.sigs.k8s.io/][kind]] or [[https://minikube.sigs.k8s.io/docs/start/][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. |
| 243 | + To set the image pull policy: |
| 244 | + |
| 245 | + #+begin_src sh |
| 246 | + echo "quarkus.kubernetes.image-pull-policy=IfNotPresent" >> ~/quickstarts/hibernate-orm-panache-quickstart/src/main/resources/application.properties |
| 247 | + #+end_src |
| 248 | + |
| 249 | +**** Deploy the application |
| 250 | + |
| 251 | + The next step will generate the deployment manifest, including the `ServiceBinding` and will apply them on kubernetes. |
| 252 | + |
| 253 | + #+begin_src sh :dir ~/quickstarts/hibernate-orm-panache-quickstart |
| 254 | + mvn clean install -Dquarkus.kubernetes.deploy=true -DskipTests |
| 255 | + #+end_src |
| 256 | + |
| 257 | + |
| 258 | +**** Verify the installation |
| 259 | + |
| 260 | + #+begin_src sh |
| 261 | + kubectl port-forward service/hibernate-orm-panache-quickstart 8080:80 |
| 262 | + #+end_src |
| 263 | + |
| 264 | + Open your browser on [[http://localhost:8080]] and enjoy! |
| 265 | + |
| 266 | +* Thoughs and future steps |
| 267 | + |
| 268 | + I am really excited with the progress on the Service binding front. Thinks are looking great and can look even better. |
| 269 | + 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 same as the database name unless explicitly specified) and a reasonable set of defaults (e.g. assuming that for postgres the default operator is [[https://github.com/CrunchyData/postgres-operator][CrunchyData operator]]). |
| 270 | + This could even allow us to bind to services with zero config, without really sacrificing in flexibility and customizability! |
| 271 | + |
| 272 | + I hope I could get you even half as excited as I am! |
| 273 | + |
| 274 | + |
| 275 | + |
0 commit comments