You are on page 1of 3

CHEAT SHEET

Writing a Kubernetes Operator in Java

This cheat sheet covers how to create a Kubernetes Operator in Java using Quarkus.
mvn "io.quarkus:quarkus-maven-plugin:1.4.0.Final:create" \
-DprojectGroupId="org.acme" \
-DprojectArtifactId="pizza-operator" \
-DprojectVersion="1.0-SNAPSHOT" \
-Dextensions="kubernetes, kubernetes-client" \

Tip You can generate the project in https://code.quarkus.io/ and selecting kubernetes and kubernetes-client extensions.

@JsonProperty("sauce")
DEFINING THE CRD private String sauce;
// getters/setters
First, you need to create a CRD de ning the custom resource: }
apiVersion: apiextensions.k8s.io/v1beta1 @JsonDeserialize
kind: CustomResourceDefinition public class PizzaResourceStatus {}
metadata: @JsonDeserialize
name: pizzas.mykubernetes.acme.org public class PizzaResource extends CustomResource {
labels: private PizzaResourceSpec spec;
app: pizzamaker private PizzaResourceStatus status;
mylabel: stuff // getters/setters
spec: }
group: mykubernetes.acme.org @JsonSerialize
scope: Namespaced public class PizzaResourceList extends
version: v1beta2 CustomResourceList<PizzaResource> {}
names:
kind: Pizza public class PizzaResourceDoneable extends
listKind: PizzaList CustomResourceDoneable<PizzaResource> {
plural: pizzas public PizzaResourceDoneable(PizzaResource resource,
singular: pizza Function<PizzaResource, PizzaResource>
shortNames: function)
- pz { super(resource, function);}
}
An example of a pizza resource:
apiVersion: mykubernetes.acme.org/v1beta2
kind: Pizza Registering the CRD in Kubernetes Client
metadata:
public class KubernetesClientProducer {
name: alexmeats
spec:
@Produces
toppings:
@Singleton
- mozzarella
@Named("namespace")
- pepperoni
String findMyCurrentNamespace() throws
- sausage
IOException {
- bacon
return new
sauce: extra
String(Files.readAllBytes(Paths.get("/
var/run/secrets/kubernetes.io/
DEFINING THE JAVA CODE serviceaccount/namespace")));
}
@Produces
Parsing of the pizza resource
@Singleton
KubernetesClient
You need to create a parser for reading the content of pizza resource.
makeDefaultClient(@Named("namespace") String
@JsonDeserialize namespace) {
public class PizzaResourceSpec { return new
@JsonProperty("toppings") DefaultKubernetesClient().inNamespace(namespace);
private List<String> toppings = new ArrayList<>(); }

some task with / description of what that would do


Build here. Go any where. developers.redhat.com | @RHdevelopers 1
CHEAT SHEET

@Produces final ContainerBuilder containerBuilder =


@Singleton new ContainerBuilder().withName("pizza-
MixedOperation<PizzaResource, PizzaResourceList, maker")
PizzaResourceDoneable, Resource<PizzaResource, .withImage("quay.io/lordofthejars/
PizzaResourceDoneable>> pizza-maker:1.0.0").withCommand("/work/
application")
makeCustomHelloResourceClient(KubernetesClient .withArgs("--sauce=" + sauce, "--
defaultClient) { toppings=" + String.join(",",toppings));

KubernetesDeserializer.registerCustomKind("mykuberne final PodSpecBuilder podSpecBuilder = new


tes.acme.org/v1beta2", "Pizza", PodSpecBuilder().withContainers
PizzaResource.class); (containerBuilder.build())
CustomResourceDefinition crd = .withRestartPolicy("Never");
defaultClient.customResourceDefinitions().
list().getItems().stream().findFirst() final PodBuilder podBuilder = new
.orElseThrow(RuntimeException::new); PodBuilder().withMetadata
return defaultClient.customResources(crd, (objectMetaBuilder.build())
PizzaResource.class, PizzaResourceList.class, .withSpec(podSpecBuilder.build());
PizzaResourceDoneable.class);
} final Pod pod = podBuilder.build();
} defaultClient.resource(pod)
.createOrReplace();
}
Implement the Operator
}

Operator is the logic that is executed when the custom resource (pizza) is
@Override
applied. In this case, a pod is instantiated with pizza-maker image. public void onClose(KubernetesClientException e)
public class PizzaResourceWatcher { {
}
@Inject });
KubernetesClient defaultClient; }
}
@Inject
MixedOperation<PizzaResource, PizzaResourceList,
Deploy Operator
PizzaResourceDoneable, Resource<PizzaResource,
PizzaResourceDoneable>> crClient;
You need to package and create a container with all the operator code and
deploy it to the cluster.
void onStartup(@Observes StartupEvent event) {
apiVersion: rbac.authorization.k8s.io/v1
crClient.watch(new Watcher<PizzaResource>() { kind: ClusterRole
@Override metadata:
public void eventReceived(Action action, name: quarkus-operator-example
PizzaResource resource) { rules:
if (action == Action.ADDED) { - apiGroups:
final String app = resource.getMetadata() - ''
.getName(); resources:
final String sauce = resource.getSpec() - pods
.getSauce(); verbs:
final List<Stri ng> toppings = - get
resource.getSpec().getToppings(); - list
- watch
final Map<String, String> labels = new - create
HashMap<>();labels.put("app", app); - update
- delete
final ObjectMetaBuilder objectMetaBuilder = - patch
new ObjectMetaBuilder().withName(app + "- - apiGroups:
pod") - apiextensions.k8s.io
.withNamespace(resource.getMetadata() resources:
.getNamespace()).withLabels(labels); - customresourcedefinitions
verbs:
- list

Build here. Go any where. developers.redhat.com | @RHdevelopers 2


CHEAT SHEET

- watch
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: quarkus-operator-example
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: quarkus-operator-example
subjects:
- kind: ServiceAccount
name: quarkus-operator-example
namespace: default
roleRef:
kind: ClusterRole
name: quarkus-operator-example
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: quarkus-operator-example
spec:
selector:
matchLabels:
app: quarkus-operator-example
replicas: 1
template:
metadata:
labels:
app: quarkus-operator-example
spec:
serviceAccountName: quarkus-operator-example
containers:
- image: quay.io/lordofthejars/pizza-operator:1.0.0
name: quarkus-operator-example
imagePullPolicy: IfNotPresent

Run the kubectl apply -f pizza-crd.yaml command to register the CRD


in the cluster. Run the kubectl apply -f deploy.yaml command to
register the operator.

Running the example

Apply the custom resource by running: kubectl apply -f meat-pizza.yaml


and check the output of kubectl get pods command.

Author Alex Soto


Java Champion, Working at Red Hat

Build here. Go any where. developers.redhat.com | @RHdevelopers 2

You might also like