Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Kubernetes Operators: Extend the API

By Kokil Thapa | Last reviewed: September 2026

Kubernetes Operators: Extend the API is how teams turn a generic cluster into a platform that understands your database, queue, or payment service. Native Kubernetes knows Pods, Deployments, and Services. It does not know how to fail over PostgreSQL or rotate TLS certificates for a multi-tenant SaaS. Operators close that gap by registering new object types and running controllers that enforce desired state continuously. If you already run workloads with Laravel on Kubernetes, operators are the next layer that keeps stateful services alive without midnight shell scripts.

What are Kubernetes Operators and how do they extend the API?

An operator is a controller plus one or more Custom Resource Definitions (CRDs). The CRD extends the Kubernetes API. Your team can then create objects like PostgresCluster or Certificate with kubectl, GitOps tools, or client libraries.

The controller watches those objects. It creates underlying Deployments, Services, Secrets, and PersistentVolumeClaims. It also runs domain logic that Helm charts and bash scripts usually leave to humans.

Core resources live in built-in API groups such as apps/v1. Custom resources live under your own group, for example database.example.com/v1. Once installed, they feel native. kubectl get postgresclusters works the same way as kubectl get deployments.

Kubernetes Operators Extend the APIExtended API Layer — CRDs + ControllersCustom ResourcesPostgresClusterOperator ControllerReconcile LoopAdmission WebhooksValidate / MutateCore Kubernetes API — Pod, Deployment, Service, PVCetcd stores both core and custom resource objects
How Kubernetes Operators extend the API: CRDs register new types; controllers and webhooks enforce behaviour on top of core resources.

The official Kubernetes operator pattern documentation describes this as application-specific knowledge encoded in software. That is accurate. The practical win is repeatability. A junior engineer applies a YAML manifest. The operator performs steps that previously required a senior DBA.

On production clusters I help maintain, operators sit alongside GitOps controllers. Argo CD GitOps declares what should exist. Operators decide how to keep complex software healthy after it exists.

API aggregation vs CRDs

Most teams extend the API with CRDs. They are simpler to author and do not require an aggregated API server. API aggregation suits large platforms that expose many resources through a dedicated extension server. CRDs cover the majority of operator use cases in 2026.

How does a Custom Resource Definition work in Kubernetes?

A CRD is a manifest that teaches the API server about a new kind. You define group, version, scope, and an OpenAPI schema. After the CRD is established, users create instances of that kind.

Here is a minimal CRD for a fictional AppRelease resource:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: appreleases.platform.example.com
spec:
  group: platform.example.com
  scope: Namespaced
  names:
    plural: appreleases
    singular: apprelease
    kind: AppRelease
    shortNames:
      - ar
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              required: [image, replicas]
              properties:
                image:
                  type: string
                replicas:
                  type: integer
                  minimum: 1
            status:
              type: object
              properties:
                phase:
                  type: string
                readyReplicas:
                  type: integer
      subresources:
        status: {}
      additionalPrinterColumns:
        - name: Image
          type: string
          jsonPath: .spec.image
        - name: Ready
          type: integer
          jsonPath: .status.readyReplicas

Apply it, then create an instance:

kubectl apply -f apprelease-crd.yaml

apiVersion: platform.example.com/v1
kind: AppRelease
metadata:
  name: billing-api
  namespace: production
spec:
  image: registry.example.com/billing:2.4.1
  replicas: 3

Nothing happens yet except storage in etcd. The CRD alone extends the API surface. It does not extend behaviour. That requires a controller.

Status subresources and conditions

Well-designed operators write to .status, not .spec. Users own spec. The controller owns status. Use conditions such as Ready, BackupComplete, or FailoverInProgress. This mirrors built-in resources and plays nicely with GitOps. Argo CD should not fight the controller over status fields.

For schema validation during CI, pipe manifests through a JSON formatter and validator in your pipeline. Catch typos before they reach the cluster.

How does the operator reconciliation loop work?

Every controller follows the same loop. Watch events. Fetch the object. Compare desired spec with observed state. Act. Requeue if work remains.

Operator Reconciliation LoopWatch CR EventsFetch ObjectGet latest specCompare StateSpec vs observedAct / PatchCreate child resourcesUpdate .status conditionsSet Ready=False until work completesRequeue with backoff
The reconciliation loop that makes Kubernetes Operators extend the API with automated, continuous control.

Idempotency matters. The same event may arrive twice. Network partitions happen. The controller must tolerate partial failure and resume safely.

Finalizers prevent orphan resources. Add a finalizer on the custom resource. When a user deletes it, the controller runs cleanup—remove cloud load balancers, drop S3 buckets, revoke certificates—then removes the finalizer.

Leader election is required when you run multiple operator replicas. Without it, two controllers might fight over the same database failover. The Operator SDK client documentation covers manager options including leader election flags.

Owner references and garbage collection

Set ownerReferences on child objects. Kubernetes garbage-collects dependents when the parent custom resource disappears. This keeps the cluster tidy. I have seen hand-rolled scripts leave orphaned PVCs after app deletion. Operators should not repeat that mistake.

How do you build a Kubernetes Operator with Kubebuilder?

Kubebuilder and the Operator SDK are the standard Go scaffolds in 2026. They generate CRD manifests, RBAC, and controller stubs. You fill in reconcile logic.

  1. Install Go 1.22+ and the Kubebuilder CLI.
  2. Scaffold a project with kubebuilder init --domain example.com --repo github.com/you/operator.
  3. Create an API with kubebuilder create api --group platform --version v1 --kind AppRelease.
  4. Implement the Reconcile method in controllers/apprelease_controller.go.
  5. Generate manifests with make manifests install.
  6. Deploy the manager Deployment to the target cluster.

A simplified reconcile skeleton:

func (r *AppReleaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    var app platformv1.AppRelease
    if err := r.Get(ctx, req.NamespacedName, &app); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    deploy := deploymentForApp(&app)
    if err := controllerutil.SetControllerReference(&app, deploy, r.Scheme); err != nil {
        return ctrl.Result{}, err
    }

    found := &appsv1.Deployment{}
    err := r.Get(ctx, types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found)
    if err != nil && errors.IsNotFound(err) {
        if err := r.Create(ctx, deploy); err != nil {
            return ctrl.Result{}, err
        }
    } else if err != nil {
        return ctrl.Result{}, err
    } else if !reflect.DeepEqual(found.Spec, deploy.Spec) {
        found.Spec = deploy.Spec
        if err := r.Update(ctx, found); err != nil {
            return ctrl.Result{}, err
        }
    }

    app.Status.ReadyReplicas = found.Status.ReadyReplicas
    app.Status.Phase = "Running"
    if err := r.Status().Update(ctx, &app); err != nil {
        return ctrl.Result{}, err
    }

    return ctrl.Result{RequeueAfter: time.Minute}, nil
}

Test with envtest or kind before production. Pair operator development with debugging CrashLoopBackOff pods skills. Your controller bugs often surface as failing manager pods first.

RBAC the operator needs

Grant least privilege. The controller needs read/write on its CRD, status subresource updates, and create/update/delete on child types it manages. Over-broad ClusterRole bindings are a common audit finding.

rules:
  - apiGroups: ["platform.example.com"]
    resources: ["appreleases", "appreleases/status"]
    verbs: ["get", "list", "watch", "update", "patch"]
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

For teams shipping Laravel APIs on Kubernetes, operators can manage Redis, queue workers, and scheduled Jobs and CronJobs as a single custom resource. That reduces YAML sprawl across namespaces.

When should you use an Operator instead of Helm or plain manifests?

Helm installs templates. Operators maintain state over time. Choose based on operational complexity, not hype.

CriteriaPlain Manifests / KustomizeHelmOperator (CRD + Controller)
Install once, rarely changeGood fitGood fitOverkill
Parameterized releasesAwkwardStrong fitPossible but heavy
Day-2 ops: backup, failover, upgradeManual runbooksHooks help; still manualStrong fit
Stateful clustered softwareRiskyRisky at scaleStrong fit
Team skill requirementLowLow–mediumHigh (Go, K8s internals)
GitOps compatibilityExcellentExcellentGood with status separation

Install Postgres once with Helm. Run a three-node HA cluster with automated backup and version upgrades? Use the Crunchy Postgres Operator, CloudNativePG, or similar. The same logic applies to cert-manager for TLS and the External Secrets Operator with Vault.

Operator vs Helm DecisionNeed ongoing ops automation?No — one-time installYes — day-2 tasksHelm or KustomizeStatic templatesVendor OperatorPostgres, certs, secretsCustom OperatorYour domain logicRule: build custom operators only when no mature upstream existsPrefer CNCF or vendor-maintained operators first
Choosing between Helm and Kubernetes Operators when you extend the API for operational automation.

Crossplane is a related pattern. It extends the API to manage cloud infrastructure itself—RDS instances, S3 buckets, DNS records—not just in-cluster workloads. Platform teams often run Crossplane alongside application operators.

How do Operators fit into production clusters and GitOps workflows?

Production adoption starts with proven upstream operators. cert-manager, External Secrets, and Prometheus Operator are mature. Install them cluster-wide. Document version pins and upgrade windows.

GitOps tools sync custom resources like any other manifest. Store Certificate, ExternalSecret, or PostgresCluster YAML in Git. Argo CD applies it. The operator reconciles it. Keep spec in Git. Never commit status.

Watch for common production failures:

  • Operator manager pod lacks RBAC for new API versions after upgrade.
  • CRD schema changes break existing objects without a conversion webhook.
  • Two controllers fight over the same labels on shared resources.
  • Webhook timeouts block all creates when the operator is down.
  • Resource limits on the manager cause OOMKill during bulk reconciles.

Set resource requests and limits on operator Deployments. They are control-plane-adjacent software. An OOMKill during certificate renewal is a bad day.

GitOps + Operator Production FlowGit RepoCR manifests in GitArgo CDSync + drift detectCustom Resourcespec only in GitOperatorReconcileManaged Workloads — Deployments, PVCs, Services, IngressLaravel app, Redis, MySQL, TLS certificatesstatus.conditions updated by operator — not stored in GitEngineers read Ready / BackupComplete before cutover
Production pattern: GitOps declares custom resources; Kubernetes Operators extend the API with automated lifecycle management.

For edge or small clusters, K3s lightweight Kubernetes runs the same operator model. Resource budgets are tighter. Prefer single-replica operators with leader election disabled only when you accept the availability trade-off.

On a booking platform like Adventure Third Pole Trek, persistent storage and TLS are not optional. Operators reduce manual toil so the team focuses on application code rather than certificate expiry panics.

Platform work ties directly to Linux system administration and enterprise application development. Operators sit at the intersection. They are infrastructure code with application awareness.

Monitor operator health with Prometheus metrics. Track reconcile duration, error counts, and workqueue depth. Alert when errors spike after a cluster upgrade. Pair this with Horizontal Pod Autoscaling for the apps the operator manages—not always for the operator itself.

Upgrade strategy for CRD schema changes

Version CRD APIs carefully. Add a new version, mark the old one deprecated, run conversion webhooks, then remove the old version in a later release. Skipping conversion breaks existing objects silently. Test upgrades on a staging cluster that mirrors production CR counts.

Storage lifecycle matters too. Operators that manage databases depend on PersistentVolume lifecycle behaviour. Understand reclaim policies before you automate failover.

Key Takeaways

  • Kubernetes Operators extend the API by registering CRDs and running controllers that reconcile spec with cluster state.
  • CRDs alone add types; controllers add behaviour—both are required for a working operator.
  • Prefer mature upstream operators (cert-manager, External Secrets, database operators) before writing custom Go controllers.
  • Separate spec (GitOps-owned) from status (controller-owned) to avoid sync conflicts.
  • Use finalizers, owner references, and leader election to prevent orphaned resources and split-brain failures.
  • Build custom operators only when day-2 operational complexity justifies the engineering cost.

People Also Ask

What is the difference between a CRD and an Operator?

A CRD extends the Kubernetes API with a new object type. An operator is the running controller software plus that CRD. The CRD is the schema. The operator is the brain that watches instances and performs actions.

Do Kubernetes Operators replace Helm charts?

No. Helm excels at packaging and installing parameterized manifests. Operators excel at ongoing reconciliation—backups, upgrades, failover. Many teams use Helm to install the operator itself, then manage custom resources separately.

What language are Kubernetes Operators written in?

Most production operators use Go with Kubebuilder or Operator SDK. Go client libraries are first-class. Python and Java operators exist, but the ecosystem defaults to Go for performance and compiled single-binary deployment.

Can Operators manage resources outside the cluster?

Yes. Operators commonly call cloud APIs, DNS providers, and vault systems. Crossplane formalizes this for infrastructure. Application operators might rotate external API keys or provision managed database instances via cloud SDKs.

Ship platforms, not just manifests

Kubernetes Operators: Extend the API so your cluster understands operational work, not just container scheduling. Start with proven operators for TLS, secrets, and databases. Add custom CRDs only when your domain logic is unique and stable enough to encode.

If you are moving a Laravel or eCommerce workload onto Kubernetes and need help choosing operators, GitOps layout, or API integration patterns, contact us for a practical architecture review. You can also browse the portfolio for platforms already running on managed infrastructure, or read more on Ingress controllers and ongoing cluster maintenance.

Frequently Asked Questions

A Kubernetes Operator is a controller plus one or more Custom Resource Definitions. The CRD registers a new object type with the API server under your own group, such as database.example.com/v1. The controller watches those objects, compares spec to cluster reality, and reconciles differences by creating Deployments, Services, Secrets, and PVCs while running domain logic like backup, upgrade, and failover. Native Kubernetes knows Pods and Deployments; operators teach the cluster how to keep PostgreSQL, queues, or TLS healthy without manual runbooks.

A CRD is the schema that extends the API surface. An operator is the running controller software plus that CRD. The CRD alone stores objects in etcd; nothing happens until a controller watches them and acts.

A CRD is a manifest that teaches the API server about a new kind. You define group, version, scope, and an OpenAPI schema. After it is established, users create instances with kubectl or GitOps tools. Well-designed CRDs expose a status subresource so controllers write to .status while users own .spec. Conditions such as Ready or BackupComplete mirror built-in resources. Validate manifests in CI with a JSON formatter before apply to catch schema typos early.

Every controller follows the same loop: watch events, fetch the object, compare desired spec with observed state, act, and requeue if work remains. Idempotency is critical because the same event may arrive twice or after a network partition. The controller must tolerate partial failure and resume safely. Pair this loop with finalizers for cleanup on delete, owner references for garbage collection of child objects, and leader election when running multiple operator replicas to prevent split-brain failover on stateful services.

Kubebuilder and Operator SDK are the standard Go scaffolds in 2026. Install Go 1.22+ and the Kubebuilder CLI, then run kubebuilder init with your domain and repo. Create an API with kubebuilder create api, implement the Reconcile method in the generated controller, and run make manifests install to generate CRD and RBAC YAML. Deploy the manager Deployment to the cluster. Test with envtest or kind before production. Controller bugs often surface first as CrashLoopBackOff on the manager pod, so treat operator debugging like any other failing workload.

Grant least privilege. The controller typically needs get, list, watch, update, and patch on its own CRD and status subresource, plus create, update, patch, and delete on child types it manages such as Deployments. Over-broad ClusterRole bindings are a common audit finding. Scope verbs tightly to the API groups your reconcile loop actually touches. After operator upgrades that introduce new API versions, verify RBAC still covers the new resources or reconciles will fail silently while the manager pod keeps restarting.

No. Helm installs parameterized templates; operators maintain state over time. Many teams install the operator itself with Helm, then manage custom resources separately.

Plain manifests and Kustomize suit install-once workloads with low day-2 complexity. Helm fits parameterized releases. Operators justify their engineering cost when you need ongoing reconciliation: automated backup, failover, version upgrades, and clustered stateful software. Install Postgres once with Helm if operations stay manual. Run a three-node HA cluster with automated backup and upgrades using Crunchy Postgres Operator, CloudNativePG, or similar. cert-manager and External Secrets Operator follow the same logic for TLS and secret sync. Build custom Go controllers only when upstream operators cannot cover your domain.

Most teams extend the API with CRDs because they are simpler to author and do not require an aggregated API server. A CRD manifest registers a new type directly with the built-in API server. API aggregation suits large platforms that expose many resources through a dedicated extension server and need deeper API semantics. In practice, CRDs cover the majority of operator use cases in 2026. Reserve aggregation for platform teams building broad multi-resource APIs rather than a single application controller.

GitOps tools sync custom resources like any other manifest. Store Certificate, ExternalSecret, or PostgresCluster YAML in Git. Argo CD applies spec; the operator reconciles lifecycle behaviour. Keep spec in Git and never commit status, because controllers own status fields and Argo CD should not fight them. Watch for webhook timeouts blocking all creates when the operator is down, and for two controllers fighting over the same labels on shared resources. Production adoption starts with proven upstream operators with documented version pins and upgrade windows.

Most production operators use Go with Kubebuilder or Operator SDK. Go client libraries are first-class and compile to a single binary for deployment.

Yes. Operators commonly call cloud APIs, DNS providers, and vault systems during reconciliation. Crossplane formalizes this pattern for infrastructure such as RDS instances, S3 buckets, and DNS records rather than only in-cluster workloads. Application operators might rotate external API keys or provision managed database instances via cloud SDKs. Platform teams often run Crossplane alongside application operators so GitOps declares both cluster objects and cloud resources through a unified custom resource model.

Typical failures include operator manager pods lacking RBAC for new API versions after upgrade, CRD schema changes breaking existing objects without a conversion webhook, two controllers fighting over the same labels, webhook timeouts blocking all creates when the operator is down, and OOMKill on the manager during bulk reconciles. Set resource requests and limits on operator Deployments because they are control-plane-adjacent. An OOMKill during certificate renewal is a bad day. Monitor reconcile duration, error counts, and workqueue depth with Prometheus and alert when errors spike after cluster upgrades.

Version CRD APIs carefully. Add a new version, mark the old one deprecated, run conversion webhooks, then remove the old version in a later release. Skipping conversion breaks existing objects silently. Test upgrades on a staging cluster that mirrors production CR counts. Storage lifecycle matters for database operators: understand PersistentVolume reclaim policies before automating failover, or you risk orphaned volumes or data loss during controller-driven recovery. Pair schema upgrades with RBAC reviews so the controller retains access to new API versions.

Start with proven upstream operators: cert-manager for TLS, External Secrets Operator with Vault for secret sync, and Prometheus Operator for monitoring. For databases, use Crunchy Postgres Operator or CloudNativePG rather than hand-rolled scripts. Install them cluster-wide, document version pins, and define upgrade windows. On production clusters I help maintain, these sit alongside GitOps controllers. For Laravel APIs on Kubernetes, operators can manage Redis, queue workers, and CronJobs as a single custom resource, reducing YAML sprawl. Add custom CRDs only when day-2 operational complexity justifies the Go engineering cost.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: