Java-based Operator SDK is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information about the support scope of Red Hat Technology Preview features, see https://access.redhat.com/support/offerings/techpreview/.

Operator developers can take advantage of Java programming language support in the Operator SDK to build an example Java-based Operator for Memcached, a distributed key-value store, and manage its lifecycle.

This process is accomplished using two centerpieces of the Operator Framework:

Operator SDK

The operator-sdk CLI tool and java-operator-sdk library API

Operator Lifecycle Manager (OLM)

Installation, upgrade, and role-based access control (RBAC) of Operators on a cluster

This tutorial goes into greater detail than Getting started with Operator SDK for Java-based Operators.


  • Operator SDK CLI installed

  • OpenShift CLI (oc) v4.11+ installed

  • Java v11+

  • Maven v3.6.3+

  • Logged into an OpenShift Container Platform 4.11 cluster with oc with an account that has cluster-admin permissions

  • To allow the cluster to pull the image, the repository where you push your image must be set as public, or you must configure an image pull secret

Creating a project

Use the Operator SDK CLI to create a project called memcached-operator.

  1. Create a directory for the project:

    $ mkdir -p $HOME/projects/memcached-operator
  2. Change to the directory:

    $ cd $HOME/projects/memcached-operator
  3. Run the operator-sdk init command with the quarkus plug-in to initialize the project:

    $ operator-sdk init \
        --plugins=quarkus \
        --domain=example.com \


Among the files generated by the operator-sdk init command is a Kubebuilder PROJECT file. Subsequent operator-sdk commands, as well as help output, that are run from the project root read this file and are aware that the project type is Java. For example:

domain: example.com
- quarkus.javaoperatorsdk.io/v1-alpha
projectName: memcached-operator
version: "3"

Creating an API and controller

Use the Operator SDK CLI to create a custom resource definition (CRD) API and controller.

  1. Run the following command to create an API:

    $ operator-sdk create api \
        --plugins=quarkus \ (1)
        --group=cache \ (2)
        --version=v1 \ (3)
        --kind=Memcached (4)
    1 Set the plug-in flag to quarkus.
    2 Set the group flag to cache.
    3 Set the version flag to v1.
    4 Set the kind flag to Memcached.
  1. Run the tree command to view the file structure:

    $ tree
    Example output
    ├── Makefile
    ├── PROJECT
    ├── pom.xml
    └── src
        └── main
            ├── java
            │   └── com
            │       └── example
            │           ├── Memcached.java
            │           ├── MemcachedReconciler.java
            │           ├── MemcachedSpec.java
            │           └── MemcachedStatus.java
            └── resources
                └── application.properties
    6 directories, 8 files

Defining the API

Define the API for the Memcached custom resource (CR).

  • Edit the following files that were generated as part of the create api process:

    1. Update the following attributes in the MemcachedSpec.java file to define the desired state of the Memcached CR:

      public class MemcachedSpec {
          private Integer size;
          public Integer getSize() {
              return size;
          public void setSize(Integer size) {
              this.size = size;
    2. Update the following attributes in the MemcachedStatus.java file to define the observed state of the Memcached CR:

      The example below illustrates a Node status field. It is recommended that you use typical status properties in practice.

      import java.util.ArrayList;
      import java.util.List;
      public class MemcachedStatus {
          // Add Status information here
          // Nodes are the names of the memcached pods
          private List<String> nodes;
          public List<String> getNodes() {
              if (nodes == null) {
                  nodes = new ArrayList<>();
              return nodes;
          public void setNodes(List<String> nodes) {
              this.nodes = nodes;
    3. Update the Memcached.java file to define the Schema for Memcached APIs that extends to both MemcachedSpec.java and MemcachedStatus.java files.

      public class Memcached extends CustomResource<MemcachedSpec, MemcachedStatus> implements Namespaced {}

Generating CRD manifests

After the API is defined with MemcachedSpec and MemcachedStatus files, you can generate CRD manifests.

  • Run the following command from the memcached-operator directory to generate the CRD:

    $ mvn clean install
  • Verify the contents of the CRD in the target/kubernetes/memcacheds.cache.example.com-v1.yml file as shown in the following example:

    $ cat target/kubernetes/memcacheds.cache.example.com-v1.yaml
    Example output
    # Generated by Fabric8 CRDGenerator, manual edits might get overwritten!
    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
      name: memcacheds.cache.example.com
      group: cache.example.com
        kind: Memcached
        plural: memcacheds
        singular: memcached
      scope: Namespaced
      - name: v1
                    type: integer
                type: object
                      type: string
                    type: array
                type: object
            type: object
        served: true
        storage: true
          status: {}

Creating a Custom Resource

After generating the CRD manifests, you can create the Custom Resource (CR).

  • Create a Memcached CR called memcached-sample.yaml:

    apiVersion: cache.example.com/v1
    kind: Memcached
      name: memcached-sample
      # Add spec fields here
      size: 1

Implementing the controller

After creating a new API and controller, you can implement the controller logic.

  1. Append the following dependency to the pom.xml file:

  2. For this example, replace the generated controller file MemcachedReconciler.java with following example implementation:

    Example MemcachedReconciler.java
    package com.example;
    import io.fabric8.kubernetes.client.KubernetesClient;
    import io.javaoperatorsdk.operator.api.reconciler.Context;
    import io.javaoperatorsdk.o