MHRubel
HomeAboutProjectsSkillsExperienceBlogContact
MHRubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
KubernetesDevOpsEngineeringJune 19, 20263 min read

Kubernetes CRDs and Controller-Runtime: A Practical Guide to Operators

Master Kubernetes CRDs and Controller-Runtime to build powerful Kubernetes Operators. Learn how to implement custom automation with the Go Operator SDK today.

KubernetesGoOperatorsAutomationDevOpsCloudNative

If you’ve ever found yourself manually syncing configurations or orchestrating complex state across your cluster, you’ve hit the ceiling of standard Kubernetes objects. That’s where Kubernetes CRDs and the Controller-Runtime library come in, allowing you to codify your operational knowledge into a custom operator.

In this guide, we’ll move beyond basic YAML manifests. We’ll build a custom automation engine using the Go Operator SDK to manage resources exactly how your infrastructure requires.

Why Build Custom Operators?

Standard controllers handle things like Deployments and Services, but they don't know your business logic. When you need to manage Kubernetes Secret Management, you might rely on existing operators, but for internal platform requirements, custom automation is often the only way to maintain consistency.

Think of an operator as a control loop. It watches the state of your cluster, compares it to your desired state, and executes actions to bridge the gap. By using the Controller-Runtime library, you get battle-tested scaffolding that handles the heavy lifting of caching, leader election, and event filtering.

Getting Started with the Go Operator SDK

First, ensure you have the Operator SDK (I'm using v1.30.0) and Go (1.21+) installed. We’ll initialize a project to define our custom API.

Bash
mkdir my-operator && cd my-operator
operator-sdk init --domain mahamudul.dev --repo github.com/mhrubel/my-operator
operator-sdk create api --group apps --version v1alpha1 --kind AppConfig

This command generates the boilerplate for your Kubernetes CRDs and the controller scaffolding. The api/v1alpha1/appconfig_types.go file is where you define your schema.

Implementing the Reconciliation Loop

The heart of your operator is the Reconcile function. This is where the magic happens. You don't just "do" things; you reconcile the state.

Go
func (r *AppConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    log := log.FromContext(ctx)

    // 1. Fetch the AppConfig instance
    appConfig := &appsv1alpha1.AppConfig{}
    if err := r.Get(ctx, req.NamespacedName, appConfig); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    // 2. Add your custom automation logic here
    log.Info("Reconciling AppConfig", "name", appConfig.Name)

    // 3. Update status or create dependent resources
    return ctrl.Result{}, nil
}

The key here is idempotency. Your logic should be able to run hundreds of times without causing side effects. If your operator manages complex node lifecycle tasks, you might consider integrating Kubernetes Cluster API patterns to ensure you aren't fighting with existing cluster state controllers.

Advanced Patterns for Production

Once your basic controller is working, you need to think about observability and stability. You can’t debug a distributed system by guessing. I strongly recommend setting up Kubernetes Observability early in your development process so you can trace reconciliation requests through your custom controllers.

Also, consider how your CRDs interact with the rest of the cluster. If you’re managing resources that cross namespace boundaries, look at how Kubernetes Multi-Tenancy handles hierarchy to avoid permission nightmares.

Best Practices for Your Controller

  • Use Finalizers: If your custom automation creates external resources (like cloud load balancers), use finalizers to ensure cleanup when a CRD is deleted.
  • Watch Dependent Resources: Use builder.Owns(&appsv1.Deployment{}) in your controller setup to trigger a reconciliation whenever a managed resource changes.
  • Limit Scope: Keep your controllers focused. One operator per domain is better than a "god-operator" that manages everything.

Summary

Building Kubernetes Operators is the ultimate way to level up your platform engineering game. By leveraging Controller-Runtime and the Go Operator SDK, you move from manual scripts to a declarative, self-healing system. Start small, focus on idempotency, and always prioritize observability to ensure your custom automation stays reliable under pressure.

Back to Blog

Similar Posts

Close-up of a modern control panel in an Istanbul office with buttons and switches.
KubernetesJune 19, 20264 min read

Implementing Kubernetes Admission Controllers with Kubebuilder

Master Kubernetes Admission Controllers with Kubebuilder. Learn how to build custom Validating Admission Webhooks to enforce cluster-wide policy and security.

Read more
KubernetesJune 19, 20263 min read

Kubernetes Logging: Implementing Grafana Loki and Promtail

Master Kubernetes logging by implementing Grafana Loki and Promtail. Learn how to centralize your cluster logs and improve cloud-native observability today.

Read more
Close-up of a modern control panel in an Istanbul office with buttons and switches.
KubernetesJune 19, 20264 min read

Kubernetes ResourceQuotas: Automating Governance with Kyverno

Kubernetes ResourceQuotas and Kyverno are the keys to cluster stability. Learn to automate resource limits and prevent noisy neighbor issues in production.

Read more