Skip to content
advanced Phase 11 · Operators & Custom Resources

Operator SDK & Kubebuilder

Build Kubernetes operators using Operator SDK and Kubebuilder frameworks.

1h 30m
0 problems
Topic Progress 0%

Scaffolding the Project

Scaffolding the Project

Operator SDK builds on Kubebuilder and controller-runtime. A typical session:

kubebuilder init --domain example.com --repo github.com/acme/db-operator
kubebuilder create api --group db --version v1 --kind Database

This generates the API types (api/v1/database_types.go with Spec, Status, and +kubebuilder:object:root markers), a stub internal/controller/database_controller.go, CRD/RBAC/webhook manifests under config/, and Makefile targets. make generate runs controller-gen for DeepCopy methods; make manifests renders CRDs and RBAC from markers — both are mandatory after every type or permission change.

Writing the Reconciler

Writing the Reconciler

// +kubebuilder:rbac:groups=db.example.com,resources=databases,verbs=get;list;watch
// +kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;create;update

func (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    var db dbv1.Database
    if err := r.Get(ctx, req.NamespacedName, &db); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }
    // converge: create/update the StatefulSet, then...
    return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}

The manager registers the controller with SetupWithManager, wiring watches back to the CR. The client reads come from an informer cache (cheap, eventually consistent); writes go straight to the API server. Update db.Status through the status subresource and return errors so the workqueue applies exponential backoff.

Pitfalls and Interview Angles

Pitfalls and Interview Angles

Stale generated code. Adding a spec field without make generate leaves DeepCopy blind to it — fields silently vanish on serialization.

RBAC drift. Developing with an admin kubeconfig hides missing permissions; run as the restricted ServiceAccount from config/rbac before shipping, or the operator 403s in production.

Status conflicts. Two writers to status cause the object has been modified; patch or re-fetch and retry instead of blind Update.

Hot reconcile loops. Mutating status unconditionally, or comparing cache data that lags, produces endless work — guard writes with equality checks.

Interview angle: describe controller-runtime's split (manager, controller, cached client, workqueue) and explain why your operator still needs its own RBAC manifests.

Quiz

1. Which command pair regenerates code and manifests after a type change?

Question 1 options

2. Why might a locally working operator fail with 403 in-cluster?

Question 2 options

3. Where do controller-runtime client reads come from?

Question 3 options

Flashcards

Question

kubebuilder create api

Answer

Scaffolds types + controller + manifests for a new CRD kind; domain/repo flags fix group paths.

Question

RBAC markers

Answer

// +kubebuilder:rbac:... comments compiled by controller-gen into config/rbac Role rules.

Question

Reconcile return contract

Answer

Return error to requeue with backoff; RequeueAfter for timed follow-ups; zero values mean done until the next event.

Question

envtest

Answer

Starts a real API server (no controllers) so you can test reconciliation logic without a full cluster.

Revision Notes

Key Takeaways

  • 1. Scaffold with Kubebuilder, regenerate with make generate/manifests after every schema change
  • 2. Reconcilers are idempotent, use the cached client for reads, and report status through the subresource
  • 3. Test RBAC and behavior under the real ServiceAccount — admin kubeconfigs hide failures

Interview Tips

  • • Explain controller-runtime's manager/controller/cache/workqueue architecture in one breath
  • • Name the exact failure you hit when markers or generated code fall behind the types

Cheat Sheet

kubebuilder init/create api → types + controller + config/. After edits: make generate && make manifests. RBAC from markers; cached reads, direct writes; envtest/make run; requeue with backoff.

Continue Learning