Operator Framework vs. Kubebuilder: What Is the Difference?

advanced|operatorssreplatform engineerCKA
TL;DR

Kubebuilder is a Go framework for building Kubernetes controllers and Operators. The Operator SDK (part of the Operator Framework) wraps Kubebuilder and adds support for Ansible and Helm-based Operators, plus OLM integration for lifecycle management.

Detailed Answer

The Kubernetes Operator ecosystem has two primary frameworks for building Operators: Kubebuilder and the Operator SDK (part of the Operator Framework). Understanding how they relate helps you choose the right tool for your project.

The Relationship

controller-runtime (Go library)
    ↑
Kubebuilder (Go scaffolding framework)
    ↑
Operator SDK (wraps Kubebuilder + adds Helm/Ansible + OLM)

Both Kubebuilder and Operator SDK use controller-runtime under the hood. Operator SDK actually embeds Kubebuilder's scaffolding and extends it.

Feature Comparison

| Feature | Kubebuilder | Operator SDK | |---------|------------|--------------| | Go-based Operators | Yes | Yes (uses Kubebuilder) | | Helm-based Operators | No | Yes | | Ansible-based Operators | No | Yes | | CRD generation | Yes | Yes | | RBAC scaffolding | Yes | Yes | | Testing framework | envtest | envtest + scorecard | | OLM integration | Manual | Built-in | | Bundle/catalog generation | No | Yes | | Project scaffolding | kubebuilder init | operator-sdk init | | Maintained by | Kubernetes SIG | Operator Framework (Red Hat) |

Kubebuilder

Kubebuilder is the standard Go framework maintained by Kubernetes SIG API Machinery:

# Initialize project
kubebuilder init --domain example.com --repo github.com/myorg/operator

# Create API
kubebuilder create api --group cache --version v1 --kind Redis

# Generate manifests
make manifests

# Run locally
make run

# Deploy
make deploy IMG=myorg/operator:v1

Kubebuilder generates a clean, idiomatic Go project that uses controller-runtime directly.

Operator SDK (Go Type)

The Operator SDK's Go type is essentially Kubebuilder with extra features:

# Initialize project (same flags as Kubebuilder)
operator-sdk init --domain example.com --repo github.com/myorg/operator

# Create API (same as Kubebuilder)
operator-sdk create api --group cache --version v1 --kind Redis

# Additional features:
# Generate OLM bundle
make bundle

# Run scorecard tests
operator-sdk scorecard ./bundle

# Create catalog for OLM
operator-sdk run bundle myorg/operator-bundle:v1

Operator SDK (Helm Type)

For teams that want an Operator without writing Go — just wrap an existing Helm chart:

# Scaffold a Helm-based Operator
operator-sdk init --plugins helm --domain example.com

# Create API from a Helm chart
operator-sdk create api \
  --helm-chart=bitnami/redis \
  --helm-chart-version=17.0.0 \
  --group cache --version v1 --kind Redis

This generates an Operator that:

  • Creates a Redis CRD
  • Maps CRD spec fields to Helm values
  • Runs helm install/upgrade/delete in response to CR changes
# Users create this CR instead of running helm install
apiVersion: cache.example.com/v1
kind: Redis
metadata:
  name: my-redis
spec:
  # These map directly to Helm values
  architecture: replication
  replica:
    replicaCount: 3
  auth:
    enabled: true

Operator SDK (Ansible Type)

For teams with Ansible expertise:

operator-sdk init --plugins ansible --domain example.com
operator-sdk create api --group cache --version v1 --kind Redis

This generates an Operator that runs Ansible playbooks/roles when CRs are created, updated, or deleted:

# watches.yaml — maps CRDs to Ansible roles
- version: v1
  group: cache.example.com
  kind: Redis
  role: redis
  reconcilePeriod: 30s
# roles/redis/tasks/main.yml
- name: Create Redis Deployment
  kubernetes.core.k8s:
    state: present
    definition:
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: "{{ ansible_operator_meta.name }}-redis"
        namespace: "{{ ansible_operator_meta.namespace }}"
      spec:
        replicas: "{{ replicas | default(1) }}"
        selector:
          matchLabels:
            app: redis
        template:
          metadata:
            labels:
              app: redis
          spec:
            containers:
              - name: redis
                image: "redis:{{ redis_version | default('7') }}"

OLM (Operator Lifecycle Manager)

OLM manages Operators like a package manager:

# Install OLM
operator-sdk olm install

# Create an OLM bundle
make bundle IMG=myorg/operator:v1

# Build and push the bundle image
make bundle-build bundle-push BUNDLE_IMG=myorg/operator-bundle:v1

# Deploy via OLM
operator-sdk run bundle myorg/operator-bundle:v1

OLM provides:

  • CatalogSource: A repository of available Operators
  • Subscription: Automatic updates for installed Operators
  • InstallPlan: Approval workflow for Operator installations
  • CSV (ClusterServiceVersion): Rich metadata about the Operator

Decision Matrix

| Scenario | Recommended Tool | |----------|-----------------| | Full-featured Go Operator with custom logic | Kubebuilder | | Go Operator with OLM distribution | Operator SDK (Go) | | Wrap an existing Helm chart as an Operator | Operator SDK (Helm) | | Team knows Ansible, not Go | Operator SDK (Ansible) | | Simple CRUD Operator | Operator SDK (Helm) | | Complex stateful application management | Kubebuilder or Operator SDK (Go) | | Enterprise distribution via OperatorHub | Operator SDK (any type) + OLM |

Migration Between Frameworks

Since both frameworks use controller-runtime, migration is straightforward:

# Kubebuilder → Operator SDK: re-scaffold and copy controller code
operator-sdk init --domain example.com --repo github.com/myorg/operator
# Copy api/ and internal/controller/ directories

# Operator SDK → Kubebuilder: re-scaffold and copy controller code
kubebuilder init --domain example.com --repo github.com/myorg/operator
# Copy api/ and internal/controller/ directories

Best Practices

  1. Choose Go for complex Operators — Helm and Ansible types are limited in what they can reconcile
  2. Start with Kubebuilder if you do not need OLM or Helm/Ansible support
  3. Use Operator SDK if you plan to publish on OperatorHub.io
  4. Test with scorecard (Operator SDK) for conformance validation
  5. Consider Helm Operators for Day 1 tasks and graduate to Go for Day 2 operations
  6. Do not over-engineer — if a Helm chart suffices, use a Helm Operator rather than writing Go

Why Interviewers Ask This

Teams starting an Operator project need to choose a framework. This question tests your understanding of the ecosystem and ability to make practical tooling decisions.

Common Follow-Up Questions

Can you build an Operator without Go?
Yes — Operator SDK supports Helm-based (YAML only), Ansible-based (playbooks), and Go-based Operators. For simple use cases, a Helm Operator requires zero programming.
What is OLM (Operator Lifecycle Manager)?
OLM manages the lifecycle of Operators themselves — installation, updates, dependency resolution, and catalog management. It is optional but useful for distributing Operators in multi-tenant environments.
Which should I choose for a new project?
If you need full control and write Go, use Kubebuilder directly. If you want Helm/Ansible support, OLM integration, or simplified scaffolding, use Operator SDK.

Key Takeaways

  • Kubebuilder is the foundation — both Kubebuilder and Operator SDK use controller-runtime under the hood.
  • Operator SDK adds Helm and Ansible Operator types for teams that do not write Go.
  • OLM is a separate component for managing Operator installations and upgrades in production.

Related Questions

You Might Also Like