Core Java

Kubernetes Native Development: From Java Operators to Golang Controllers

Kubernetes is built for extensibility, and one of its most powerful extension points is the Operator pattern—allowing you to codify operational knowledge directly into the cluster. While Golang is the native choice for Kubernetes development, frameworks like Fabric8 and Quarkus have brought first-class Kubernetes operator support to Java developers as well.

This article walks you through the core concepts of Custom Resource Definitions (CRDs), building custom operators in both Java and Go, and choosing the right approach based on your team’s skills, ecosystem, and performance needs.

What Are CRDs and Operators?

  • CRDs (Custom Resource Definitions) let you define your own Kubernetes resources (like KafkaCluster, BackupJob, etc.).
  • Operators are controllers that watch these custom resources and act accordingly.

Goal Example:

Let’s say we want to build an operator that provisions a database backup job whenever a BackupRequest resource is created.

Option 1: Writing a Kubernetes Operator in Go (Native)

Go is the official language of Kubernetes, and the Kubebuilder and Operator SDK provide robust tooling.

Setup (with Operator SDK)

operator-sdk init --domain example.com --repo github.com/example/db-backup-operator
operator-sdk create api --group apps --version v1alpha1 --kind BackupRequest --resource --controller

This scaffolds:

  • The CRD definition (BackupRequest)
  • Controller logic to reconcile resources

Sample CRD Spec (in Go)

type BackupRequestSpec struct {
    DatabaseName string `json:"databaseName"`
    Schedule     string `json:"schedule"` // e.g., cron
}

Sample Reconcile Logic

func (r *BackupRequestReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    var backup BackupRequest
    if err := r.Get(ctx, req.NamespacedName, amp;backup); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    job := createK8sJob(backup.Spec.DatabaseName)
    err := r.Create(ctx, amp;job)
    return ctrl.Result{}, err
}

Pros:

  • Full performance and API parity with Kubernetes internals
  • Native support, battle-tested tooling

Cons:

  • Requires learning Go
  • Boilerplate-heavy for Java-native teams

Option 2: Writing a Kubernetes Operator in Java (with Fabric8 or Quarkus)

🔹 Using Fabric8 Kubernetes Client

Fabric8 is the go-to Java client for Kubernetes. It also supports building operators using informers and controllers.

Maven Setup

<dependency>
    <groupId>io.fabric8</groupId>
    <artifactId>kubernetes-client</artifactId>
    <version>6.x.x</version>
</dependency>

Define the CRD POJO

@Group("apps.example.com")
@Version("v1alpha1")
@Kind("BackupRequest")
@Plural("backuprequests")
public class BackupRequest extends CustomResource<BackupRequestSpec, Void> {}

public class BackupRequestSpec {
    private String databaseName;
    private String schedule;
    // Getters/Setters
}

Reconciler Logic

public class BackupRequestController implements ResourceEventHandler<BackupRequest> {
    private final KubernetesClient client;

    public void onAdd(BackupRequest backupRequest) {
        Job job = createBackupJob(backupRequest.getSpec().getDatabaseName());
        client.batch().v1().jobs().inNamespace("default").create(job);
    }
}

Using Quarkus Extension

With Quarkus, operator development is even easier thanks to the quarkus-operator-sdk extension.

mvn io.quarkus.platform:quarkus-maven-plugin:2.x.x:create \
  -Dextensions="operator-sdk"

You can then annotate your reconciler like:

@Controller(crdName = "backuprequests.apps.example.com")
public class BackupRequestReconciler implements Reconciler<BackupRequest> {
    public UpdateControl<BackupRequest> reconcile(BackupRequest resource, Context context) {
        // Logic to create Kubernetes Job
        return UpdateControl.noUpdate();
    }
}

Pros:

  • Java ecosystem + Spring/Quarkus support
  • Easier onboarding for Java teams
  • Supports unit testing with JUnit/mock frameworks

Cons:

  • Not as performant as Go
  • Slightly behind in ecosystem maturity

Testing Your Operator (Both Go & Java)

  • Use kind or minikube to spin up a dev cluster.
  • Use controller-runtime’s envtest (Go) or Testcontainers (Java) for integration testing.
  • Always define status fields in CRDs for observability.

Java vs Go for Kubernetes Operators

FeatureGo (Kubebuilder)Java (Fabric8 / Quarkus)
Performance✅ Native, fastest⚠️ Slight overhead
Language Ecosystem✅ Designed for K8s✅ Leverage existing Java libs
Learning Curve⚠️ Need to learn Go✅ Java-friendly
Tooling✅ Rich (Kubebuilder, SDK)⚠️ Less standardization
Testing✅ envtest, fake client✅ JUnit, Mockito, Testcontainers

Final Thoughts

If you’re building a production-grade operator with high performance requirements, Golang is still the gold standard. But for Java-centric teams who want to extend Kubernetes without leaving their comfort zone, frameworks like Fabric8 and Quarkus Operator SDK offer powerful alternatives.

Ultimately, choose the language that aligns best with your team’s skills, and leverage the right tools to keep your operator robust and testable.

Resources

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button