Java Operator
In this section we implement an Operator in Java which will define some Custom Resource to control and deploy a 3-tier app:
-
Frontend: React app from
docker.io/jdob/visitors-webui:1.0.0
-
Backend: Python app from
docker.io/jdob/visitors-service:1.0.0
-
DB: MySQL 5.7 from
docker.io/library/mysql:5.7
Scaffold the new operator
Create a new directory on your machine, for instance : $HOME/visitors-operator
operator-sdk init --domain operators.redhat.com --plugins quarkus
This will scaffold an empty Quarkus
project for you.
The plugin is is running some versions behind, so open the pom.xml
and in the properties
section update to this :
<quarkus-sdk.version>2.0.2</quarkus-sdk.version>
<quarkus.version>2.5.1.Final</quarkus.version>
And you can remove this portion from dependencyManagement
:
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client-bom</artifactId>
<version>${fabric8-client.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Generate an API
Le’s create an API for our operator :
operator-sdk create api --group=app --version=v1 --kind=Visitor
This will scaffold your operator’s classes : controller and POJO objects.
In general, it’s recommended to have one controller responsible for manage each API created for the project to properly follow the design goals set by controller-runtime.
API definition
To begin, we will represent our API by defining the Visitor
type :
Open generated API:
$HOME/visitors-operator/src/main/java/com/redhat/operators/VisitorSpec.java
Fill these sections with the following:
package com.redhat.operators;
public class VisitorSpec {
private int size;
private String title;
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
And also update the status class, open : $HOME/visitors-operator/src/main/java/com/redhat/operators/VisitorStatus.java
package com.redhat.operators;
public class VisitorStatus {
private String backendImage;
private String frontendImage;
public VisitorStatus() {
}
public VisitorStatus(String backendImage, String frontendImage) {
this.backendImage = backendImage;
this.frontendImage = frontendImage;
}
public String getBackendImage() {
return backendImage;
}
public void setBackendImage(String backendImage) {
this.backendImage = backendImage;
}
public String getFrontendImage() {
return frontendImage;
}
public void setFrontendImage(String frontendImage) {
this.frontendImage = frontendImage;
}
}
Generate CRDs
With the quarkus
extension your CRDs will be generated each time you compile your project.
Execute a mvn clean package
and check the target/kubernetes
folder, it contains your CRD but also all the other resources needed to deploy your operator on the cluster.
You can also make sure that the CRDs will applied to the cluster automacilly when running in dev
mode, go to src/main/resources/application.properties
and set :
quarkus.operator-sdk.crd.apply=true
Controllers
Copy the controllers logic :
cp -R $TUTORIAL_HOME/apps/java/quarkus/src/main/java/com/redhat/operators/controllers $HOME/visitors-operator/src/main/java/com/redhat/operators
Run your operator locally
Be sure to be connected to a Kubernetes cluster and then run
mvn quarkus:dev
Since you are in dev
mode, you can benefit from all the Developer Experience that Quarkus offers you : live reload, etc …
Apply a Custom Resource
You can now apply a custom resource
apiVersion: app.redhat.com/v1
kind: VisitorsApp
metadata:
name: visitorsapp-sample
spec:
size: 1
title: "My First Operator in Quarkus!"
kubectl apply -f $TUTORIAL_HOME/apps/cr/visitorsapp-java.yaml
Check the pods getting created :
kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-86c559bb7f-kjjvt 1/1 Running 0 28h
visitors-backend-7489bb97dd-wggkt 1/1 Running 0 28h
visitors-frontend-86df47fffc-d2bgl 1/1 Running 0 28h
Check your newly create CR:
kubectl get visitor
NAME AGE
visitorsapp-sample 1m
Get your VisitorApp status:
kubectl describe visitor visitorsapp-sample
Name: visitorsapp-sample
Namespace: default
Labels: <none>
Annotations: <none>
API Version: app.redhat.com/v1
Kind: Visitor
Metadata:
Creation Timestamp: 2021-10-28T07:39:34Z
Spec:
Size: 1
Title: My First Operator in Go!
Status:
Backend Image: jdob/visitors-service:1.0.0
Frontend Image: jdob/visitors-webui:1.0.0
Events: <none>
Access the VisitorsApp! A kubernetes service for the frontend has been created (visitorsapp-sample-frontend-service
) and it is exposed as a NodePort
on port 30686
.
On Minikube, get Minikube IP and access the app:
IP=$(minikube ip -p operators)
PORT=$(kubectl get service/visitorsapp-sample-frontend-service -o jsonpath="{.spec.ports[*].nodePort}")
curl $IP:$PORT
Or open it in the browser:
Build and Push the Operator
In your application properties make sure to set the correct container group (using your own group/username), i.e
quarkus.container-image.group=quay.io/rhdevelopers
Be sure to be logged to your registry, then build, push your operator and apply the kubernetes
resources :
mvn clean package -Dquarkus.container-image.push=true -Dquarkus.kubernetes.deploy=true
Deploy to Kubernetes with OLM
The Operator Lifecycle Manager (OLM) is a set of cluster resources that manage the lifecycle of an Operator. The Operator SDK supports both creating manifests for OLM deployment, and testing your Operator on an OLM-enabled Kubernetes cluster.
Install OLM with the Operator SDK CLI:
operator-sdk olm install
TODO : Bundling a Quarkus Operator