DEV Community

Alain Airom (Ayrom)
Alain Airom (Ayrom)

Posted on • Originally published at alain-airom.Medium

Book Review & Technical Implementation: Kubernetes in Action, Second Edition

Book review: Kubernetes in Action, Second Edition from Manning

πŸš€ Introduction

Back to back to some of my initial technical interests, I think this book deserves a fine review. This book took very long to be published from MEAP to completion, and it was probably worth it!

When Marko LukΕ‘a released the first edition of Kubernetes in Action back in 2017, it rapidly established itself as the gold standard text for mastering container orchestration. However, over the past decade, the Kubernetes ecosystem has undergone significant evolution: legacy container engines yielded to OCI standards via containerd and CRI-O, standard Ingress resources expanded into the modular Gateway API, storage plugins consolidated around the Container Storage Interface (CSI), and sidecar helper patterns evolved into first-class native primitives.

Enter the Second Edition, co-authored by Marko LukΕ‘a alongside Red Hat engineering leader Kevin Conner. Spanning 18 chapters across 5 cohesive parts, this edition does not merely refresh code samples β€” it completely rebuilds the narrative around modern development patterns on modern Kubernetes.

Quick Disclaimers:
No Sponsorship: I’m not affiliated with Manning or the authors in any way β€” just sharing a review.
Fun Note: Big fan of the original illustrations in the book β€” always refreshing to see real artwork instead of AI-generated visuals!


Following the initial deep-dive analysis of the book per se, I tasked Bob with digesting the material, mapping out an architectural diagram of its structure, and building a full end-to-end demo application based on the code from the book’s official GitHub repository (Image blow provided by Bob).


πŸ—οΈ Part 1-Chapter Analysis & Breakdown

Getting Started & Core Architecture (Chapters 1–4)

What sets this book apart right from the opening pages is how the authors refuse to treat Kubernetes as a black box. Instead of just giving you commands to run, they take you back to Google’s Borg origins and walk you through how the system is actually wired under the hood.

  • Chapter 1: Introducing Kubernetes β€” The authors unpack cluster topology by showing how Kubernetes cleanly splits responsibilities. The Control Plane handles intelligence (kube-apiserver, etcd, kube-scheduler, and kube-controller-manager), while the Workload Plane does the actual heavy lifting via worker nodes running kubelet, kube-proxy, and an OCI runtime.
+-----------------------------------+
                      |      KUBERNETES CONTROL PLANE     |
                      |  +--------+ +-------------------+ |
                      |  |  etcd  | |  kube-apiserver   | |
                      |  +--------+ +-------------------+ |
                      |  +-----------+ +----------------+ |
                      |  | scheduler | | controllers    | |
                      |  +-----------+ +----------------+ |
                      +------------------+----------------+
                                         | RESTful API
               +-------------------------+-------------------------+
               |                                                   |
  +------------v------------+                         +------------v------------+
  |  WORKER NODE 1          |                         |  WORKER NODE 2          |
  |  +--------------------+ |                         |  +--------------------+ |
  |  |      Kubelet       | |                         |  |      Kubelet       | |
  |  +--------------------+ |                         |  +--------------------+ |
  |  | kube-proxy | CRI   | |                         |  | kube-proxy | CRI   | |
  |  +------------+-------+ |                         |  +------------+-------+ |
  |  [ Pod A ]  [ Pod B ]   |                         |  [ Pod C ]  [ Pod D ]   |
  +-------------------------+-------------------------+-------------------------+
Enter fullscreen mode Exit fullscreen mode
  • Chapter 2: Containers & Linux Primitives β€” I really appreciate that Chapter 2 doesn’t jump straight into Kubernetes abstractions. It grounds you in low-level Linux kernel primitives β€” specifically Namespaces (for process, mount, and network isolation) and Control Groups (cgroups) (for CPU and memory limits). To make everything hands-on, the authors introduce Kiada (Kubernetes in Action Demo Application), a simple Node.js microservice used throughout the book:
# Chapter 2: Minimal Dockerfile for Kiada Demo Application
FROM node:23-alpine
COPY app.js /app.js
COPY html/ /html
ENTRYPOINT ["node", "app.js"]
Enter fullscreen mode Exit fullscreen mode
  • Chapter 3: First Deployments β€” Here, you get your hands dirty spinning up local environments like Kind or Minikube before moving toward cloud clusters like GKE or EKS. You learn how kubectl interacts imperatively with the cluster before diving into declarative files (images from the book):


# Imperatively creating a Pod and exposing it via a Service
kubectl run kiada --image=luksa/kiada:0.1 --port=8080
kubectl expose pod kiada --type=NodePort --port=8080
Enter fullscreen mode Exit fullscreen mode

  • Chapter 4: API & Object Model β€” This chapter hits on a fundamental mental model shift: understanding the REST API structure and the core distinction between the desired state (spec) and the observed state (status).
# Chapter 4: Declarative Object Manifest Structure
apiVersion: v1
kind: Pod
metadata:
  name: kiada-demo
  labels:
    app: kiada
spec:
  containers:
  - name: kiada-container
    image: luksa/kiada:0.1
Enter fullscreen mode Exit fullscreen mode

Running Applications in Kubernetes (Chapters 5–7)

Once you understand the API, Part 2 dives into the atom of Kubernetes: the Pod.

  • Chapter 5: Pods β€” Instead of viewing containers as isolated units, the authors illustrate why containers inside the same Pod share the net and ipc namespaces. This enables tight co-location, shared localhost networking, and multi-container patterns like helper sidecars or init containers:
# Chapter 5: Multi-Container Pod with an Init Container and Main App
apiVersion: v1
kind: Pod
metadata:
  name: kiada-init-demo
spec:
  initContainers:
  - name: init-html
    image: busybox:1.36
    command: ['sh', '-c', 'echo "<h1>Welcome to Kiada</h1>" > /usr/share/nginx/html/index.html']
    volumeMounts:
    - name: html-vol
      mountPath: /usr/share/nginx/html
  containers:
  - name: web-server
    image: nginx:alpine
    volumeMounts:
    - name: html-vol
      mountPath: /usr/share/nginx/html
  volumes:
  - name: html-vol
    emptyDir: {}
Enter fullscreen mode Exit fullscreen mode
  • Chapter 6: Pod Lifecycle & Health β€” This chapter is absolute gold for anyone who has ever debugged cascading failures in production. It covers the exact mechanics of Startup, Liveness, and Readiness probes, ensuring your app doesn’t receive traffic until it’s ready and gets restarted if it deadlocks:
# Chapter 6: Pod Manifest with Liveness, Readiness, and Startup Probes
apiVersion: v1
kind: Pod
metadata:
  name: kiada-healthy
  labels:
    app: kiada
    env: production
spec:
  containers:
  - name: kiada
    image: luksa/kiada:0.2
    ports:
    - containerPort: 8080
    startupProbe:
      httpGet:
        path: /
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /readiness
        port: 8080
      periodSeconds: 5
Enter fullscreen mode Exit fullscreen mode
  • Chapter 7: Organization β€” As the clusters grows, keeping things organized becomes critical. This chapter explains how to group objects logically using Namespaces and query them cleanly using key-value Labels and Selectors (image from the book):
# Querying pods dynamically using label selectors
kubectl get pods -l app=kiada,env=production --namespace=default

Enter fullscreen mode Exit fullscreen mode

Application Configuration & Storage (Chapters 8–10)

Building cloud-native apps means keeping them stateless and configuration-agnostic. Part 3 walks through how Kubernetes lets you inject configuration and attach storage seamlessly.

  • Chapter 8: Configuration β€” Here we learn how to decouple application logic from environment specifics using ConfigMap, inject sensitive items with Secret, and expose runtime cluster metadata back to the container via the Downward API (images from the book):


# Chapter 8: Injecting ConfigMap and Secret values as Environment Variables
apiVersion: v1
kind: Pod
metadata:
  name: kiada-config-demo
spec:
  containers:
  - name: kiada
    image: luksa/kiada:0.3
    env:
    - name: INITIAL_STATUS
      valueFrom:
        configMapKeyRef:
          name: kiada-config
          key: status.message
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: kiada-secret
          key: password
Enter fullscreen mode Exit fullscreen mode
  • Chapter 9: Volumes β€” This chapter covers temporary volume types like emptyDir, host filesystem access with hostPath, and mounting configuration maps directly as filesystem files (image from the book):


# Chapter 9: Mounting a ConfigMap as a Volume
apiVersion: v1
kind: Pod
metadata:
  name: kiada-volume-demo
spec:
  containers:
  - name: kiada
    image: luksa/kiada:0.3
    volumeMounts:
    - name: config-volume
      mountPath: /etc/kiada
  volumes:
  - name: config-volume
    configMap:
      name: kiada-config
Enter fullscreen mode Exit fullscreen mode
  • Chapter 10: Persistent Storage β€” The authors unpack the separation between persistent storage requests (PersistentVolumeClaim) and actual cluster storage backends (PersistentVolume) backed by CSI drivers:
[ Pod Spec ] ──( PVC Reference )──> [ PersistentVolumeClaim ]
                                           β”‚ (Dynamic Provisioning)
                                           β–Ό
                                 [ PersistentVolume ] ──> [ Physical / Cloud Storage (CSI) ]
Enter fullscreen mode Exit fullscreen mode
# Chapter 10: Dynamically Provisioned Storage via PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: quiz-data-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName: standard
Enter fullscreen mode Exit fullscreen mode

Connecting & Exposing Applications (Chapters 11–13)

Part 4 is one of the most rewarding parts of the book, taking you step-by-step from internal pod communication all the way to modern traffic management.

  • Chapter 11: Services β€” Pods are ephemeral, meaning their IP addresses change constantly. Services provide a stable virtual IP (ClusterIP), NodePort bindings, or cloud LoadBalancers to front your workloads, powered by internal DNS:
# Chapter 11: Service Manifest for Internal Cluster Routing
apiVersion: v1
kind: Service
metadata:
  name: kiada-service
spec:
  type: ClusterIP
  selector:
    app: kiada
  ports:
  - port: 80
    targetPort: 8080
Enter fullscreen mode Exit fullscreen mode
  • Chapter 12: Ingress β€” When Layer 7 HTTP routing is needed, path matching, and SSL termination, standard Ingress steps in:
# Chapter 12: Classic Ingress Resource Manifest
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kiada-ingress
spec:
  rules:
  - host: kiada.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: kiada-service
            port:
              number: 80
Enter fullscreen mode Exit fullscreen mode
  • Chapter 13: Gateway API β€” This is a standout chapter! The authors provide an extensive, modern guide to the Gateway API (GatewayClass, Gateway, HTTPRoute), explaining why it cleanly separates infrastructure owner roles from application developer routing needs:
[ External Client ]
         β”‚
         β–Ό
[ Gateway: prod-gateway ] ◄── (GatewayClass: istio / envoy)
         β”‚
         β”œβ”€β”€β”€ (HTTPRoute: kiada-route)  ──► [ Service: kiada-service ]
         β”‚
         └─── (HTTPRoute: quote-route)  ──► [ Service: quote-service ]
Enter fullscreen mode Exit fullscreen mode
# Chapter 13: Modern Traffic Split using Gateway API (HTTPRoute)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: kiada-route
  namespace: default
spec:
  parentRefs:
  - name: prod-gateway
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api/v1/quotes
    backendRefs:
    - name: quote-service-v1
      port: 8080
      weight: 80
    - name: quote-service-v2
      port: 8080
      weight: 20
Enter fullscreen mode Exit fullscreen mode

Managing Applications at Scale (Chapters 14–18)

The final part transitions from running single pods to orchestrating complex, self-healing, scalable application stacks in production.

  • Chapter 14: ReplicaSets β€” What is the core reconciliation loop β€” how Kubernetes continuously compares desired replica counts against actual running pods and creates or deletes pods to match? Hereafter the path;
# Chapter 14: Declarative ReplicaSet Manifest
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: kiada-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kiada
  template:
    metadata:
      labels:
        app: kiada
    spec:
      containers:
      - name: kiada
        image: luksa/kiada:0.1
Enter fullscreen mode Exit fullscreen mode
  • Chapter 15: Deployments β€” Deployments build on top of ReplicaSets to offer zero-downtime rolling updates, canary rollouts, quick rollbacks, and blue/green deployments:
# Chapter 15: Deployment Manifest with RollingUpdate Strategy
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kiada-deployment
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: kiada
  template:
    metadata:
      labels:
        app: kiada
    spec:
      containers:
      - name: kiada
        image: luksa/kiada:0.2
Enter fullscreen mode Exit fullscreen mode
  • Chapter 16: StatefulSets β€” When dealing with databases or distributed stateful systems, pods need unique, predictable identities (pod-0, pod-1) and dedicated persistent storage claims:
# Chapter 16: StatefulSet with VolumeClaimTemplates
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: quiz-db
spec:
  serviceName: "quiz-db-headless"
  replicas: 3
  selector:
    matchLabels:
      app: quiz-db
  template:
    metadata:
      labels:
        app: quiz-db
    spec:
      containers:
      - name: mongo
        image: mongo:7.0
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: data
          mountPath: /data/db
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 5Gi
Enter fullscreen mode Exit fullscreen mode
  • Chapter 17: DaemonSets β€” Covering how to run exact per-node daemon copies across your cluster for log collection, node monitoring, or network plugin management:
# Chapter 17: DaemonSet for Cluster-Wide Log Collector
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
Enter fullscreen mode Exit fullscreen mode
  • Chapter 18: Batch Processing β€” Finally, the authors cover short-lived, completable workloads via Job and scheduled periodic executions with CronJob:
# Chapter 18: Scheduled Workload using CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
  name: kiada-backup-job
spec:
  schedule: "0 2 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: luksa/kiada-backup:1.0
          restartPolicy: OnFailure
Enter fullscreen mode Exit fullscreen mode

Throughout the chapters of the book, a demo application named Kiada is progressively built. In Part 2, IBM Bob takes those concepts a step further by implementing a brand-new β€˜Kiada’ *application built entirely from scratch, using the original code excerpts from the book as a foundation (schema provided by Bob).


Part 2-Putting the book’s knwoledge in Pactice

Beyond analyzing the theoretical concepts of Kubernetes in Action, 2nd Edition per se, I worked with Bob to translate those patterns into a tangible, production-ready implementation.

Instead of leaving the book’s learnings as static code snippets, Bob built kiada-goβ€”a complete Go re-implementation of the author's Node.js Kiada demo applicationβ€”and deployed it to a local kind Kubernetes cluster following the exact architecture, health-probe, configuration, and networking patterns taught throughout the 18 chapters.

πŸ› οΈ Application Architecture & Deployment Flow

The target system is structured into a multi-tiered Kubernetes architecture running inside an isolated kiada namespace. It demonstrates external traffic ingress, service abstraction, dynamic scaling, and environmental metadata injection (schema provided by Bob).

πŸ—οΈ Key Components & Applied Patterns

Application Layer (kiada-go)


Minimalist Container Footprint: Compiled using a multi-stage Docker build (golang:1.21-alpine β†’ alpine:3.19) into a lightweight binary running as an unprivileged system user (appuser).​
# - - - - - build stage - - - - - 
FROM golang:1.21-alpine AS builder
WORKDIR /build
COPY go.mod ./
RUN go mod download
COPY *.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -o kiada-go .
​
# - - - - - runtime stage - - - - - 
FROM alpine:3.19
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY - from=builder /build/kiada-go /app/kiada-go
USER appuser
EXPOSE 8080
ENTRYPOINT ["/app/kiada-go"]
Enter fullscreen mode Exit fullscreen mode

This dockerfile is optimized based on my own recommendations for image building to illustrate multi-stage images, and is nit based on the book.

  • Graceful Termination (Chapter 6): Implements explicit SIGTERM / SIGINT signal catching in Go, giving active HTTP requests a 10-second grace window to finalize during rolling updates or pod teardowns.
  • Service Proxying (Chapter 11): Includes /proxy/quote and /proxy/quiz endpoints that forward requests to internal cluster microservices via DNS service discovery.
// main.go
package main
​
import (
  "context"
  "fmt"
  "log"
  "net/http"
  "os"
  "os/signal"
  "syscall"
  "time"
)
​
const appName = "kiada-go"
const version = "1.0"
​
func main() {
  listenPort := getEnv("LISTEN_PORT", "8080")
  addr := fmt.Sprintf(":%s", listenPort)
​
  logStartup(addr)
​
  srv := &http.Server{
    Addr:         addr,
    Handler:      newRouter(),
    ReadTimeout:  10 * time.Second,
    WriteTimeout: 15 * time.Second,
    IdleTimeout:  60 * time.Second,
  }
​
  // Run server in goroutine so shutdown handling works
  go func() {
    log.Printf("%s v%s listening on %s", appName, version, addr)
    if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
      log.Fatalf("ListenAndServe error: %v", err)
    }
  }()
​
  // Graceful shutdown on SIGTERM / SIGINT (matches Ch 6 SIGTERM handler pattern)
  quit := make(chan os.Signal, 1)
  signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
  <-quit
​
  log.Printf("Received shutdown signal. Shutting down %s...", appName)
  ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  defer cancel()
​
  if err := srv.Shutdown(ctx); err != nil {
    log.Fatalf("Server shutdown error: %v", err)
  }
  log.Printf("%s shut down cleanly.", appName)
}
​
func logStartup(addr string) {
  hostname, _ := os.Hostname()
  log.Printf("-------------------------------------------")
  log.Printf("%s v%s β€” Kubernetes in Action Demo (Go)", appName, version)
  log.Printf("-------------------------------------------")
  log.Printf("Pod name   : %s", getEnv("POD_NAME", hostname))
  log.Printf("Pod IP     : %s", getEnv("POD_IP", "0.0.0.0"))
  log.Printf("Node name  : %s", getEnv("NODE_NAME", "unknown"))
  log.Printf("Node IP    : %s", getEnv("NODE_IP", "0.0.0.0"))
  log.Printf("QUOTE_URL  : %s", getEnv("QUOTE_URL", "(not set)"))
  log.Printf("QUIZ_URL   : %s", getEnv("QUIZ_URL", "(not set)"))
  log.Printf("Listen addr: %s", addr)
}
Enter fullscreen mode Exit fullscreen mode

​

Kubernetes Resource Mapping

The implementation translates key book chapters directly into declarative Kubernetes manifests:



| Manifest File        | Book Chapter(s)            | Architectural Function                                       |
| -------------------- | -------------------------- | ------------------------------------------------------------ |
| `00-namespace.yaml`  | **Chapter 7**              | Creates an isolated `kiada` namespace boundary for resource allocation and security scoping. |
| `01-configmap.yaml`  | **Chapter 8**              | Decouples non-sensitive settings (port bindings, status messages) from container images. |
| `02-deployment.yaml` | **Chapters 6, 8, 14 & 15** | Manages 3 pod replicas with zero-downtime `RollingUpdate`, `liveness`/`readiness` probes, and **Downward API** field refs (`POD_NAME`, `POD_IP`, `NODE_NAME`). |
| `03-service.yaml`    | **Chapter 11**             | Exposes stable internal IP routing via `ClusterIP` on port 80 and direct developer access via `NodePort` on 30880. |
| `04-ingress.yaml`    | **Chapter 12**             | Provides Layer 7 domain-based HTTP routing to internal services. |
| `05-hpa.yaml`        | **Chapters 14–15**         | Dynamically scales pod replicas between 2 and 10 based on CPU utilization metrics. |
Enter fullscreen mode Exit fullscreen mode

Downward API & Runtime Injection (Chapter 8)

To allow the application to remain self-aware of its placement in the cluster without depending on direct API server queries, the deployment injects runtime metadata directly through environment variables:

# ── Deployment: kiada-go ──────────────────────────────────────────────────────
# Implements patterns from Chapters 8, 11, 15:
#   - Downward API env vars (Ch 8)
#   - ConfigMap env injection (Ch 8)
#   - Readiness probe /healthz/ready (Ch 6/11)
#   - Rolling update strategy (Ch 15)
#   - 3 replicas (Ch 14)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kiada-go
  namespace: kiada
  labels:
    app: kiada-go
    rel: stable
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kiada-go
      rel: stable
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: kiada-go
        rel: stable
        ver: "1.0"
    spec:
      terminationGracePeriodSeconds: 30
      containers:
      - name: kiada-go
        image: ${REGISTRY}/kiada-go:1.0
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        env:
        # Downward API β€” injects pod/node metadata (Chapter 8)
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: NODE_IP
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        # Service URLs injected via ConfigMap (Chapter 8)
        - name: QUOTE_URL
          value: "http://quote.kiada.svc.cluster.local/quote"
        - name: QUIZ_URL
          value: "http://quiz.kiada.svc.cluster.local"
        # Status message from ConfigMap (Chapter 8)
        - name: INITIAL_STATUS_MESSAGE
          valueFrom:
            configMapKeyRef:
              name: kiada-go-config
              key: INITIAL_STATUS_MESSAGE
        # Liveness probe β€” restart container if it stops responding (Chapter 6)
        livenessProbe:
          httpGet:
            path: /healthz/ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
          failureThreshold: 3
        # Readiness probe β€” only route traffic when ready (Chapter 6/11)
        readinessProbe:
          httpGet:
            path: /healthz/ready
            port: 8080
          initialDelaySeconds: 3
          periodSeconds: 5
          failureThreshold: 1
        resources:
          requests:
            cpu: "50m"
            memory: "32Mi"
          limits:
            cpu: "200m"
            memory: "64Mi"
Enter fullscreen mode Exit fullscreen mode

​

# ── Ingress: kiada-go ─────────────────────────────────────────────────────────
# Routes external traffic to the kiada-go service (Chapter 12 Ingress pattern)
# Requires an IngressController (e.g. nginx-ingress) to be installed.
#
# Access via:
#   curl -H "Host: kiada-go.example.com" http://<node-ip>
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kiada-go
  namespace: kiada
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: kiada-go.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: kiada-go
            port:
              name: http
Enter fullscreen mode Exit fullscreen mode

​

⚑ Quick Verification

Once launched locally, the implementation can be queried to confirm proper pod self-awareness and readiness checks:

Deploy the application
#!/usr/bin/env bash
# ──────────────────────────────────────────────────────────────
# launch.sh β€” Build and deploy kiada-go to a local kind cluster
# Usage:  ./scripts/launch.sh [REGISTRY] [IMAGE_TAG]
# ──────────────────────────────────────────────────────────────
set -euo pipefail

REGISTRY="${1:-$(id -un)/kiada-go}"
IMAGE_TAG="${2:-1.0}"
IMAGE="${REGISTRY}:${IMAGE_TAG}"
CLUSTER_NAME="kiada"
PORT=30880

echo "==> Building kiada-go Docker image: ${IMAGE}"
docker build -t "${IMAGE}" ./kiada-go

echo "==> Loading image into kind cluster '${CLUSTER_NAME}'"
if ! kind get clusters 2>/dev/null | grep -q "^${CLUSTER_NAME}$"; then
  echo "==> Creating kind cluster '${CLUSTER_NAME}'"
  kind create cluster --name "${CLUSTER_NAME}"
fi
kind load docker-image "${IMAGE}" --name "${CLUSTER_NAME}"

echo "==> Patching deployment image reference"
# Replace the ${REGISTRY}/kiada-go:1.0 placeholder with the real image
sed "s|\${REGISTRY}/kiada-go:1.0|${IMAGE}|g" \
  kiada-go/k8s/02-deployment.yaml > /tmp/kiada-go-deploy-patched.yaml

echo "==> Applying Kubernetes manifests"
kubectl apply -f kiada-go/k8s/00-namespace.yaml
kubectl apply -f kiada-go/k8s/01-configmap.yaml
kubectl apply -f /tmp/kiada-go-deploy-patched.yaml
kubectl apply -f kiada-go/k8s/03-service.yaml

echo "==> Waiting for rollout to complete..."
kubectl rollout status deployment/kiada-go -n kiada --timeout=90s

URL="http://localhost:${PORT}"
echo ""
echo "────────────────────────────────────────────"
echo "  kiada-go is running!"
echo "  NodePort URL : ${URL}"
echo "  Health check : ${URL}/healthz/ready"
echo "  Pod info     : ${URL}/info"
echo "────────────────────────────────────────────"
echo ""
echo "To watch pods:"
echo "  kubectl get pods -n kiada -w"
Enter fullscreen mode Exit fullscreen mode
# Check the application status endpoint
$ curl http://localhost:30880/
​
Hello from kiada-go v1.0!
Pod: kiada-go-7d84f89d97-x9z2l | Node: kind-worker
Pod IP: 10.244.0.5 | Node IP: 172.18.0.2
Status: Welcome to kiada-go on Kubernetes!
​
# Verify health probes
$ curl http://localhost:30880/healthz/ready
{"status":"ready","time":"2026-08-05T12:51:00Z"}
Enter fullscreen mode Exit fullscreen mode

πŸ“™ Conclusion for the Book

For me, Kubernetes in Action, Second Edition is a triumph of technical writing. Marko LukΕ‘a and Kevin Conner have delivered a book that strikes an exquisite balance between low-level system engineering concepts and practical, developer-friendly paradigms.

By building out concepts sequentially β€” starting from bare Linux namespaces up to the Gateway API, StatefulSets, and Custom Operators β€” the authors ensure readers build a deep, intuitive mental model of Kubernetes rather than merely memorizing command-line syntax.

For developers, SREs, and platform architects looking to build resilient cloud-native software on modern Kubernetes, this second edition is essential reading and was undoubtedly worth every bit of the wait!


🎯 Conclusion for the Implementation: From Static Code to Executable Architecture with IBM Bob

What makes this project truly remarkable is that IBM Bob didn’t merely generate boilerplate code β€” it absorbed the foundational knowledge of Kubernetes in Action, 2nd Edition directly from its text and repository code excerpts to engineer a fully realized, operational system. By ingesting the authors’ original patterns across all 18 chapters, IBM Bob autonomously architected, refactored, and deployed kiada-goβ€”complete with graceful signal handling, multi-stage OCI builds, Downward API metadata injection, and zero-downtime rolling updates. This hands-on implementation proves that when advanced developer assistants like IBM Bob are paired with high-quality, production-minded literature, theoretical cloud-native concepts can be instantly transformed into resilient, battle-tested software.

Thanks for reading πŸ˜…

Links

Top comments (0)