AboutBlogContact
Cloud NativeSeptember 5, 2017 2 min read 23

The Operator Pattern: Extending the Kubernetes API (2017)

AunimedaAunimeda
📋 Table of Contents

The Operator Pattern: Extending the Kubernetes API

It’s 2017, and Kubernetes has won the container orchestration wars. But while K8s is great for stateless apps, managing complex stateful systems like databases (Postgres, Cassandra) is still a manual nightmare. Enter the Operator Pattern, coined by the team at CoreOS.

The Control Loop

At its heart, Kubernetes is a collection of control loops. A controller watches the current state of the cluster and makes changes to bring it closer to the "desired state." An Operator is simply a domain-specific controller that knows how to manage a specific application.

Custom Resource Definitions (CRDs)

In 2017, we're moving from ThirdPartyResources to Custom Resource Definitions (CRDs). This allows us to define our own objects in the K8s API.

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: databases.example.com
spec:
  group: example.com
  version: v1
  scope: Namespaced
  names:
    plural: databases
    singular: database
    kind: Database
    shortNames:
    - db

Now, a user can run kubectl apply -f my-db.yaml just like they would for a Deployment.

The Controller Logic

The "Operator" is a pod running in your cluster that watches for events on your new Database resource. When it sees a new one, it doesn't just spawn a pod; it might:

  1. Provision a Persistent Volume.
  2. Start a primary database pod.
  3. Wait for the primary to be ready, then start replicas.
  4. Configure replication.
  5. Setup automated backups.

Implementing in Go

Most operators are written in Go using client-go or the controller-runtime library.

func (r *ReconcileDatabase) Reconcile(request reconcile.Request) (reconcile.Result, error) {
    // Fetch the Database instance
    db := &examplev1.Database{}
    err := r.client.Get(context.TODO(), request.NamespacedName, db)
    if err != nil {
        return reconcile.Result{}, err
    }

    // Define the desired state (e.g., a StatefulSet)
    found := &appsv1.StatefulSet{}
    err = r.client.Get(context.TODO(), types.NamespacedName{Name: db.Name, Namespace: db.Namespace}, found)
    
    if err != nil && errors.IsNotFound(err) {
        // Create the StatefulSet
        dep := r.deploymentForDatabase(db)
        err = r.client.Create(context.TODO(), dep)
        return reconcile.Result{Requeue: true}, nil
    }

    return reconcile.Result{}, nil
}

The Operator pattern turns "Operations Knowledge" (how to scale a DB, how to handle a failover) into Code. This is the ultimate realization of Infrastructure as Code.

Read Also

Beyond Zero-Downtime: Mastering State Persistence in Distributed Deploymentsaunimeda
DevOps

Beyond Zero-Downtime: Mastering State Persistence in Distributed Deployments

Zero-downtime deployment was the goal in 2018. In 2026, the challenge is 'State Continuity.' We explore how to manage database migrations and persistent WebSocket connections without dropping a single user session.

SWC and esbuild: The End of Slow Bundling (2021)aunimeda
Frontend

SWC and esbuild: The End of Slow Bundling (2021)

Babel and Webpack have served us well, but the performance ceiling of JavaScript is real. In 2021, Rust and Go are rebuilding our toolchains.

Building Custom HCL Providers with the Terraform Go SDK (2019)aunimeda
DevOps

Building Custom HCL Providers with the Terraform Go SDK (2019)

Infrastructure as Code is eating the world. Here is how to build your own Terraform provider using the Go-based Plugin SDK in 2019.

Need IT development for your business?

We build websites, mobile apps and AI solutions. Free consultation.

Get Consultation All articles