Extending Kubernetes

Back

Loading concept...

🏗️ Extending Kubernetes: Building Your Own Superpowers

Imagine Kubernetes is like a giant LEGO castle. It’s already amazing! But what if you could create your own special LEGO pieces that do exactly what you want? That’s what “Extending Kubernetes” is all about!


🎭 The Story: The Magic Kingdom of K8s

Once upon a time, there was a magical kingdom called Kubernetes. The kingdom had guards (controllers), messengers (the API), and rulebooks (resources). But the wise rulers knew something important: every kingdom has different needs.

So they created a way for anyone to add new magic spells to the kingdom. Let’s learn how!


📦 Custom Resource Definitions (CRDs)

What is a CRD?

Think of Kubernetes like a toy box. It comes with standard toys: Pods, Services, Deployments. But what if you want a toy that doesn’t exist yet?

A Custom Resource Definition (CRD) is like drawing a blueprint for a brand new toy. Once you create the blueprint, Kubernetes knows how to handle your new toy!

Real-Life Example

Let’s say you run a pizza shop. Kubernetes doesn’t know what a “Pizza” is. But YOU can teach it!

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: pizzas.food.example.com
spec:
  group: food.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                toppings:
                  type: array
                  items:
                    type: string
                size:
                  type: string
  scope: Namespaced
  names:
    plural: pizzas
    singular: pizza
    kind: Pizza

Now you can create pizzas in Kubernetes!

apiVersion: food.example.com/v1
kind: Pizza
metadata:
  name: margherita
spec:
  toppings:
    - cheese
    - tomato
    - basil
  size: large

Why CRDs Matter

Without CRDs With CRDs
Only use built-in resources Create ANY resource you need
Limited flexibility Unlimited possibilities
One-size-fits-all Custom-fit for YOUR app

🤖 Custom Controllers

What is a Controller?

Imagine you have a robot helper. You tell it: “Always make sure there are 3 cookies on the plate.” If someone eats a cookie, the robot bakes a new one!

A Controller is that robot. It watches something and takes action to keep things the way they should be.

The Control Loop

graph TD A["👀 Watch"] --> B["🔍 Compare"] B --> C{Match?} C -->|No| D["🔧 Act"] C -->|Yes| E["😊 Happy"] D --> A E --> A

Every controller does this dance:

  1. Watch - See what’s happening
  2. Compare - Is it what we want?
  3. Act - Fix it if needed
  4. Repeat - Forever!

Simple Controller Example

// Simplified controller logic
func (c *PizzaController) Reconcile(
    ctx context.Context,
    req Request) (Result, error) {

    // 1. Get the Pizza resource
    pizza := &Pizza{}
    err := c.Get(ctx, req.NamespacedName, pizza)

    // 2. Check: Does it have sauce?
    if !pizza.HasSauce() {
        // 3. Act: Add sauce!
        pizza.AddSauce()
        c.Update(ctx, pizza)
    }

    return Result{}, nil
}

🎩 The Operator Pattern

What is an Operator?

Remember CRDs (the blueprint) and Controllers (the robot)? An Operator is both together! It’s the complete package.

Think of it like this:

  • CRD = Recipe card for a cake
  • Controller = Baker who follows the recipe
  • Operator = Recipe card + Baker = Complete bakery!

Why Operators are Magical

Operators encode human knowledge into software. Instead of a person manually setting up a database, the Operator does it automatically!

graph TD A["Human Expert"] -->|Teaches| B["Operator"] B -->|Manages| C["Complex App"] C -->|Reports to| B B -->|Heals| C

Real Operator Example: Database

Without Operator:

  1. Human creates Pod
  2. Human configures storage
  3. Human sets up replication
  4. Human handles backups
  5. Human fixes problems at 3 AM 😴

With Operator:

  1. Create one “Database” resource
  2. Operator handles EVERYTHING! 🎉
apiVersion: databases.example.com/v1
kind: PostgresCluster
metadata:
  name: my-database
spec:
  replicas: 3
  storage: 100Gi
  backups:
    schedule: "0 2 * * *"

🌐 Kubernetes API Fundamentals

The API is the Heart

Everything in Kubernetes talks through the API. It’s like the main post office of our kingdom. Every letter (request) goes through it!

How the API Works

graph TD A["You"] -->|kubectl| B["API Server"] C["Controller"] -->|Watch| B D["Scheduler"] -->|Query| B E["Kubelet"] -->|Report| B B -->|Store| F["etcd"]

API Request Example

When you run kubectl get pods, here’s what happens:

  1. Request goes to API Server
  2. API Server checks: “Are you allowed?” (Authentication)
  3. API Server checks: “Can you do this?” (Authorization)
  4. API Server checks: “Is this valid?” (Admission)
  5. API Server returns the answer!

RESTful Magic

The API uses REST. Think of it like addresses:

Action HTTP Method URL
List pods GET /api/v1/pods
Create pod POST /api/v1/pods
Get one pod GET /api/v1/pods/my-pod
Update pod PUT /api/v1/pods/my-pod
Delete pod DELETE /api/v1/pods/my-pod

📚 API Groups and Versions

Why Groups?

Imagine a huge library. If ALL books were in one pile, finding anything would be impossible! So we organize them into sections.

API Groups are like library sections:

Group What’s Inside
core (no group) Pods, Services, ConfigMaps
apps Deployments, StatefulSets
batch Jobs, CronJobs
networking.k8s.io Ingress, NetworkPolicy
your.company.com Your custom stuff!

API Versions

Software changes! Versions help manage this:

  • v1alpha1 - “Just testing this idea” 🧪
  • v1beta1 - “Pretty good, try it!” 🔬
  • v1 - “Rock solid, use it!” 💎

Reading an API Path

/apis/apps/v1/namespaces/default/deployments/nginx
  │    │   │      │         │         │        │
  │    │   │      │         │         │        └─ Resource name
  │    │   │      │         │         └─ Resource type
  │    │   │      │         └─ Namespace name
  │    │   │      └─ "namespaces" keyword
  │    │   └─ API version
  │    └─ API group
  └─ API prefix

👁️ Watch and Informers

The Watch Mechanism

Instead of asking “Any changes?” every second (polling), Kubernetes uses Watch. It’s like subscribing to notifications!

Polling (Bad):

You: "Any new emails?"
Server: "No"
(1 second later)
You: "Any new emails?"
Server: "No"
(Forever...)

Watch (Good):

You: "Tell me when there's a new email"
Server: "OK! *ding* You have mail!"

What are Informers?

An Informer is a smart helper that:

  1. Watches resources for changes
  2. Caches data locally (super fast lookups!)
  3. Notifies your code when things change
graph TD A["API Server"] -->|Watch Stream| B["Informer"] B -->|Store| C["Local Cache"] B -->|Notify| D["Your Code"] D -->|Fast Read| C

Informer Example

// Create an informer for Pods
informer := cache.NewSharedInformer(
    &cache.ListWatch{
        ListFunc: func(options v1.ListOptions) {
            return client.CoreV1().
                Pods("").List(options)
        },
        WatchFunc: func(options v1.ListOptions) {
            return client.CoreV1().
                Pods("").Watch(options)
        },
    },
    &corev1.Pod{},
    time.Minute,
)

// Add event handlers
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) {
        fmt.Println("New pod created!")
    },
    UpdateFunc: func(old, new interface{}) {
        fmt.Println("Pod updated!")
    },
    DeleteFunc: func(obj interface{}) {
        fmt.Println("Pod deleted!")
    },
})

🚪 Admission Webhooks

What are Admission Webhooks?

Imagine a bouncer at a club. Before you enter, they check:

  1. Are you on the list? (Authentication - already done)
  2. Are you dressed properly? (Admission!)

Admission Webhooks are custom bouncers you create!

Two Types of Webhooks

graph LR A["Request"] --> B["Validating"] B -->|OK/Reject| C{Pass?} C -->|Yes| D["Mutating"] D -->|Modify| E["Save to etcd"] C -->|No| F["Rejected!"]

1. Validating Webhook - Says YES or NO

  • “Is this Pod request valid?”
  • “Does it follow our rules?”
  • Cannot change the request

2. Mutating Webhook - Changes things

  • “Let me add a label to this Pod”
  • “Let me inject a sidecar container”
  • Modifies before saving

Real Example: Validating Webhook

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: pod-validator
webhooks:
  - name: validate.pods.example.com
    rules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE"]
        resources: ["pods"]
    clientConfig:
      service:
        name: webhook-service
        namespace: webhook-system
        path: "/validate-pods"
    admissionReviewVersions: ["v1"]
    sideEffects: None

Real Example: Mutating Webhook

// Webhook handler that adds labels
func mutatePod(
    ar *admissionv1.AdmissionReview,
) *admissionv1.AdmissionResponse {

    pod := &corev1.Pod{}
    json.Unmarshal(ar.Request.Object.Raw, pod)

    // Add a label
    patch := []map[string]interface{}{{
        "op":    "add",
        "path":  "/metadata/labels/injected",
        "value": "true",
    }}

    patchBytes, _ := json.Marshal(patch)

    return &admissionv1.AdmissionResponse{
        Allowed: true,
        Patch:   patchBytes,
        PatchType: func() *admissionv1.PatchType {
            pt := admissionv1.PatchTypeJSONPatch
            return &pt
        }(),
    }
}

🎛️ Dynamic Admission Control

What Makes it “Dynamic”?

Regular admission happens inside the API server. Dynamic means you can add or remove admission rules WITHOUT restarting anything!

The Admission Flow

graph TD A["API Request"] --> B["Authentication"] B --> C["Authorization"] C --> D["Mutating Webhooks"] D --> E["Schema Validation"] E --> F["Validating Webhooks"] F --> G["Persist to etcd"]

Why Dynamic is Powerful

Static (Old Way) Dynamic (New Way)
Compile into API server Deploy as separate service
Restart to change Change anytime
Same for all clusters Customize per cluster

Common Use Cases

1. Policy Enforcement

"All Pods MUST have resource limits"
"No containers can run as root"
"Images must come from our registry"

2. Automatic Injection

"Add logging sidecar to all Pods"
"Inject environment variables"
"Add default security settings"

3. Validation

"Database names must match pattern"
"Storage requests can't exceed 1TB"
"Labels must include 'team' and 'env'"

Simple Policy Example

# Using a policy engine like Kyverno
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-team-label
      match:
        resources:
          kinds:
            - Pod
      validate:
        message: "Pods must have 'team' label"
        pattern:
          metadata:
            labels:
              team: "?*"

🎯 Putting It All Together

Here’s how all the pieces connect:

graph TD A["You Create CRD"] --> B["CRD Defines New Resource"] B --> C["You Write Controller"] C --> D["Controller + CRD = Operator"] D --> E["Operator Watches via Informers"] E --> F["API Server Processes Requests"] F --> G["Admission Webhooks Validate/Mutate"] G --> H["Resource Saved!"]

The Complete Picture

  1. CRDs - Define what new things exist
  2. Controllers - Make things happen automatically
  3. Operators - Package CRDs + Controllers together
  4. API - How everyone communicates
  5. Groups/Versions - Organize and evolve the API
  6. Watch/Informers - Efficiently track changes
  7. Admission Webhooks - Enforce rules and inject defaults
  8. Dynamic Admission - Change rules without restarts

🚀 You Did It!

You now understand how to extend Kubernetes! You can:

✅ Create custom resources with CRDs ✅ Build controllers that act automatically ✅ Package them as Operators ✅ Understand the API structure ✅ Use Watch and Informers efficiently ✅ Create admission webhooks for validation ✅ Implement dynamic admission control

Remember: Kubernetes is DESIGNED to be extended. The creators wanted you to build on top of it. So go create something amazing! 🎉


“The best way to predict the future is to invent it.” - Alan Kay

In Kubernetes, you don’t just predict what resources you need - you INVENT them!

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.