Kubernetes Operators Best Practices
Idempotent reconcilers, level-driven design, and production operator checklist.
Search across all documentation pages
Idempotent reconcilers, level-driven design, and production operator checklist.
These rules turn recurring operator sharp edges into review habits, CI gates, and packaging choices that keep controllers safe at scale.
operator-sdk bundle validate in CI on every release tag.client.IgnoreNotFound on deleted primary objects. Avoid error metrics for races between delete and final reconcile.Status().Update for conditions and readiness. Never patch status fields through generic Update on the full object.RequeueAfter for expected waiting. Reserve returned errors for genuine failures worth alerting.Owns watches without label-only glue.failurePolicy: Fail for security-critical validation. Pair with HA webhook pods and cert monitoring.config/crd/bases without syncing Go types.kubectl get columns. Support engineers should see phase and readiness without YAML dumps.Terminating signal missing teardown logic.Owns traffic drive readiness updates.workqueue_retries_total spikes precede incident pages.ctrl.SetupSignalHandler. Release leases promptly on rolling upgrades.AllNamespaces without cluster RBAC blocks security review.--leader-elect and resource limits in CSV Deployment. HA without election duplicates external side effects.operator-sdk bundle validate catches missing owned CRD descriptors.replaces and skips in CSV metadata.Idempotent reconcile, owner references on children, finalizers for external resources, leader election with 2 replicas, and envtest coverage for create/delete paths.
Use section A and D on every controller change.
Reserve OLM and multi-tenant sections for release and packaging PRs.
Level-driven reconcile reads current spec and cluster state each pass.
Event handlers that only append side effects miss drift and periodic resync.
When validation spans multiple spec fields or depends on admission-only context.
Simple min/max bounds belong in CRD markers first.
Multiple active reconcilers without leader election mutating the same external system, or finalizers never cleared after failed teardown.
Run make test, make manifests diff check, bundle validate, and golangci-lint on controller packages.
Block merges when RBAC markers change without regenerated YAML.
Only when customers explicitly need cluster-wide CR instances and accept cluster-scoped RBAC.
Otherwise OwnNamespace or SingleNamespace reduces blast radius.
Built-in controller-runtime workqueue metrics plus one or two domain counters (reconcile result, external API latency) per controller.
Ready, progressing, degraded, and terminating states with Kubernetes meta condition conventions and clear reason codes.
When unrelated CRDs have independent failure domains or different RBAC needs.
A single Manager is fine for one product domain with shared caches.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 18, 2026