Why Manual Operator Development Doesn’t Scale

▶ Watch (9:15)

The Atlas team has multiple teams shipping features for customers. The operator team was small. That mismatch created feature lag. The Kubernetes client couldn’t keep pace with new Atlas API capabilities. Multiple developers working on separate resources in parallel introduced inconsistencies in code and user experience. Customers building internal developer platforms needed flexibility the team couldn’t provide with a curated, hand-coded approach. The problem wasn’t effort. It was that the manual workflow didn’t scale.

Flipping the Workflow: API-First Operator Development

▶ Watch (10:26)

The old approach: define Go structs, run kubebuilder to generate CRD YAML, then start coding. The new approach inverts this. Atlas already has an OpenAPI spec. A tool converts that spec into kubectl-applyable CRDs. Those CRDs become the artifact you review with stakeholders. Platform teams, product managers, and community members all sign off on the API shape before a single line of controller code gets written. Once everyone approves, a second tool generates Go types from the CRD YAML automatically.

Three Compile-Time Tools and a Runtime Library

▶ Watch (12:38)

Three tools run at compile time. openapi-to-crd takes an OpenAPI spec and a config YAML (which sets GVK, versioning, and marks sensitive fields as secret references) and outputs CRD YAML. crd-to-go reads those CRDs and generates Go structs with smart type naming. The scaffolder generates reconciliation loop boilerplate, including handler stubs and importers for adopting resources already deployed through the external API. A fourth component, CRAPI (Custom Resource to API translator library), runs at runtime and converts between Kubernetes objects and external API objects in both directions.

Replacing the Reconcile Loop with a State Machine

▶ Watch (15:46)

The classic Reconcile method gives no concrete recipe. The universal state machine replaces it with explicit handler methods: handleInitial, handleCreated, handleDeleting, and others. Each method returns a ResultNextState value, and the library patches status conditions automatically. You never call status updates directly. For resources that apply instantly in external systems, the state machine supports atomic types that skip the intermediate creating and deleting states. The ready condition (true or false) is implied by the current state, not set by hand.

State Machine Behavior in Practice

▶ Watch (25:00)

The demo creates an Atlas project and a flex cluster from autogenerated CRDs. The project CRD includes fields like org ID, name, and region, all pulled from the OpenAPI spec. Applying it triggers the reconciler, which transitions through the state machine. The resource starts in initial state, moves to created, and the ready condition flips to true. The flex cluster starts ready false (creating state) and transitions to true once settled in Atlas. A connection string appears in status fields, returned automatically from the remote API.

Notable Quotes

Okay. So you know the pain. Sergiusz Urbaniak · ▶ 9:06

it didn’t scale. It didn’t scale for us. Jose Vázquez González · ▶ 9:17

clicked in my head why this makes sense. Sergiusz Urbaniak · ▶ 11:40

Key Takeaways

  • Start with the OpenAPI spec to shape the CRD API before writing any controller code.
  • Four generated components (openapi-to-crd, crd-to-go, scaffolder, CRAPI) replace hand-coded operator boilerplate.
  • The universal state machine turns the opaque Reconcile method into typed, per-state handler functions.

About the Speaker(s)

Sergiusz Urbaniak is a Kubernetes Team Lead at MongoDB. He has worked on Mesos, container runtimes, Prometheus Operator, Thanos, upstream Kubernetes, and Operators, and brings a fondness for minimalistic networking techniques including morse code.

Jose Vázquez González is a Senior Software Engineer at MongoDB with more than 20 years in software development. He has worked on distributed systems at HP Labs, AWS, and VMware before joining MongoDB.