Kubernetes operators
Skill Goodsmileduck/claude-registry/plugins/kubernetes-skills/skills/kubernetes-operators
Community marketplace of Claude Code plugins: DevOps skill packs (Terraform, Kubernetes, CI/CD, cloud platforms, DigitalOcean), CLAUDE.md optimization, and diagramming — gated by a best-practices lint + security-audit CI.
npx -y skills add Goodsmileduck/claude-registry --skill kubernetes-operatorsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Designs and audits Kubernetes Operators — CRD shape, reconcile-loop correctness, finalizer and status-subresource handling, OperatorHub capability levels, framework choice. Use when building a controller for a CRD, reviewing an operator for capability gaps, or designing the API surface of a Custom Resource. Not for general pod debugging — see kubernetes-operations.
SKILL.md
8.1 KB, as published. Nobody here has run it
Kubernetes Operators — CRD and reconcile review
For pod-level debugging (CrashLoopBackOff, ImagePullBackOff, scheduling failures) see the kubernetes-operations skill. For Argo-managed deployments see argocd-operations.
Most "operator bugs" are reconcile-loop bugs, not Kubernetes bugs: missing finalizers, blocking calls, no requeue on transient error, status drift, RBAC over-grant. The three Python scripts shipped here catch the deterministic subset before code reaches a cluster.
When to invoke
Run the analyzers first — they're stdlib Python, fast, and surface most routine issues:
SKILL=plugins/kubernetes-skills/skills/kubernetes-operators
python3 "$SKILL/scripts/crd_validator.py" --crd config/crd/
python3 "$SKILL/scripts/reconcile_lint.py" --controller controllers/
python3 "$SKILL/scripts/operator_capability_audit.py" --operator-dir .
All three accept --format json. Triage by severity: FAIL blocks merge, WARN files an issue.
Pre-flight: is an operator the right shape?
Operators are for stateful, lifecycle-managed workloads. Reach for one when:
- The thing being managed has an external API (RDS, Kafka topics, GitHub repos).
- Day-2 operations are non-trivial (backup, restore, version upgrade, failover).
- A Helm chart + bash isn't enough — you need a controller that observes and re-acts.
Don't reach for an operator when:
| Want | Better tool |
|---|---|
| Run a workload | Deployment / StatefulSet / Job |
| Package + parameterize manifests | Helm chart or Kustomize |
| Sync repo → cluster | ArgoCD / Flux |
| External-resource lifecycle, no day-2 complexity | Terraform / Crossplane composition |
Core principle: reconcile is declarative, not imperative
The wrong shape:
if creating: do A
elif updating: do B
elif deleting: do C
The right shape:
desired = read(spec)
actual = observe(world)
diff = compare(desired, actual)
for change in diff: apply(change) # idempotently
update_status()
Reconcile must be safe to run twice in a row with no spec change → same result, zero side effects. If your function isn't idempotent, your operator will fight itself.
CRD design — the non-negotiables
crd_validator.py checks these. The list is short on purpose; each item exists because skipping it produces a specific class of bug.
| Rule | Reason it matters |
|---|---|
| Status subresource enabled | Without it, Status().Update() re-triggers the spec watcher → infinite reconcile loop |
scope: Namespaced unless cluster-scoped is justified | Cluster-scoped CRDs leak across tenants and complicate RBAC |
served: true AND storage: true on exactly one version | Multiple storage: true is invalid; missing it breaks reads |
| OpenAPI v3 schema with typed properties | x-kubernetes-preserve-unknown-fields: true at the root defeats validation; users send garbage, controller crashes |
conditions array in schema (for metav1.Conditions) | Standard way to communicate state; tooling and humans both read it |
additionalPrinterColumns include Age + Status/Phase | kubectl get becomes useful without -o yaml |
| Singular + listKind defined | kubectl get singular works |
Beyond the validator: version your CRD from day 1 (v1alpha1 → v1beta1 → v1) and plan a conversion webhook before you ship v1. Migrating storage versions later is painful.
Reconcile loop — the non-negotiables
reconcile_lint.py checks Go reconcile functions for these. Regex-based, so false positives happen — read the source after a flag.
| Rule | Why |
|---|---|
Return shape is (ctrl.Result, error) | controller-runtime contract |
Errors return RequeueAfter or non-nil error | Otherwise transient failures wedge silently |
Status updates use Status().Update(), not Update() | Updating spec bumps generation; users see "ghost" changes |
No time.Sleep inside reconcile | Blocks the workqueue → other CRs stall. Use RequeueAfter |
HTTP calls take a context.Context and respect it | Otherwise reconciles can't be cancelled on shutdown |
| Finalizer added before any external-resource create | Missing finalizer → user deletes CR → external resource orphans |
Conditions set via meta.SetStatusCondition when CRD declares them | Hand-rolled condition munging drops LastTransitionTime |
| Reconcile function under ~80 lines | Extract reconcileXxx subroutines per concern |
OperatorHub capability levels
operator_capability_audit.py scores against the OperatorHub 5-level rubric. Use it as a progression plan, not a checklist for one PR.
| Level | What it means | Realistic milestone |
|---|---|---|
| L1 Basic Install | CRD defined, controller deploys it | Same PR as the first reconcile |
| L2 Seamless Upgrades | PDB, conversion webhook, version skew strategy | Before first external user |
| L3 Full Lifecycle | Backup, restore, failure recovery | Before public release |
| L4 Deep Insights | /metrics endpoint, Prometheus rules, alerts | After L3 in production for ~1 quarter |
| L5 Auto Pilot | Auto-scaling, auto-tuning, anomaly detection | Mature operators only |
Aim for L3 before public release. L4/L5 are nice-to-have unless the operator manages something high-stakes.
Framework choice
| Framework | Language | When to pick |
|---|---|---|
| kubebuilder | Go | Default for Go shops. Most opinionated scaffolding, aligned with SIGs |
| controller-runtime | Go | When kubebuilder's scaffolding is in the way (large existing codebase) |
| operator-sdk | Go / Helm / Ansible | Targeting OpenShift, or mixed-paradigm teams |
| KOPF | Python | Python shops; great for prototypes and async-heavy operators |
| metacontroller | Any (webhook) | Polyglot team that cannot pick a single language |
| java-operator-sdk | Java | JVM-only shops |
Rule of thumb: Go shop → kubebuilder. Python shop → KOPF. Build a one-week proof-of-concept before committing the design.
Workflows
Bootstrap a new operator (Go + kubebuilder)
- Pick Group/Version/Kind:
apps.example.com/v1alpha1,kind=MyApp. kubebuilder init --domain example.com --repo github.com/org/myapp-operator.kubebuilder create api --group apps --version v1alpha1 --kind MyApp.- Run
crd_validator.pyon the generated CRD. Fix every FAIL before writing controller code. - Implement reconcile — start with the simplest correct version (no finalizers, no conditions). Add complexity only when a test fails without it.
- Run
reconcile_lint.pyon the controller. - Run
operator_capability_audit.py --operator-dir .— confirm L1. - Test in a
kindcluster:kubectl apply -f config/samples/. - Add status conditions + finalizers; aim for L2 in the same PR.
Audit an existing operator
- Run all three scripts.
- Triage: FAIL → block release; WARN → file an issue.
- Record current capability level in the README.
- Plan one level advancement per quarter.
Proactive triggers
- CRD without status subresource → infinite-loop bug waiting to happen. Add
subresources: {status: {}}. time.SleepinsideReconcile→ replace withreturn ctrl.Result{RequeueAfter: X}, nil.- Multi-replica operator without leader election → split-brain. Enable leader election or scale to 1.
- Reconcile mutates
obj.Spec→ controller is fighting users. Move to status or admission webhook. - No finalizer + external resource (cloud API, DB) → orphaned resources on CR deletion. Add finalizer.
x-kubernetes-preserve-unknown-fields: trueat schema root → defeats validation. Type the schema.
Asset templates
assets/crd_template.yaml— CRD with status subresource, conditions, printer columnsassets/reconcile_skeleton.go— Go reconcile function with idempotency, finalizer, condition patterns