1. Introduction to Kubernetes
Kubernetes is the de facto standard for deploying, scaling, and managing containerized applications in production environments. This chapter builds the conceptual foundation you need before touching a single kubectl command — covering why container orchestration exists, where Kubernetes came from, and the core vocabulary and mental models that underpin everything else in the platform.
1.1 Container Orchestration Fundamentals
Container orchestration is the discipline of automating the lifecycle of containers at scale. Before diving into Kubernetes specifically, this subchapter explains the problem space it was built to solve and how we arrived here historically.
What is Container Orchestration
Theory
A container is a lightweight, isolated unit of software that packages an application together with everything it needs to run: its runtime, libraries, and configuration. Running one container on one machine is trivial. Running hundreds or thousands of containers across dozens of machines — reliably, efficiently, and continuously — is not.
Container orchestration is the automated management of that complexity. An orchestration system is responsible for:
- Deciding where each container runs (scheduling)
- Ensuring containers that crash are restarted (self-healing)
- Distributing network traffic across healthy container instances (load balancing)
- Scaling the number of containers up or down based on demand
- Rolling out updates without causing downtime
- Providing containers a way to discover and communicate with each other
A useful analogy: think of an orchestrator as an air traffic controller. Individual planes (containers) know how to fly, but the controller manages the overall system — assigning runways (nodes), redirecting traffic around problems, and ensuring the whole airport (cluster) operates without collision.
Example
Without orchestration, a simple deployment might look like this manual process:
# Without orchestration: manually SSH into each machine and run containers
ssh user@server-01 "docker run -d --name api-v2 my-api:2.0"
ssh user@server-02 "docker run -d --name api-v2 my-api:2.0"
ssh user@server-03 "docker run -d --name api-v2 my-api:2.0"
# If server-02 goes down, you must notice it yourself and intervene manually
ssh user@server-04 "docker run -d --name api-v2 my-api:2.0"
With orchestration (Kubernetes), you declare what you want and the system handles it:
# With orchestration: declare desired state, let the system manage reality
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3 # "I want 3 copies running at all times"
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: my-api:2.0
The orchestrator reads this file, places containers on available nodes, monitors them continuously, and replaces any that fail — without further human input.
Exercises
- (Beginner) Name three responsibilities of a container orchestration system without looking back at the text.
- (Beginner) In your own words, explain the difference between a container and a container orchestration system.
- (Intermediate) A web service runs as 10 container instances across 5 nodes. One node loses power. Describe, step by step, what an orchestration system should do automatically in response.
- (Interview) "Why can't we just use a shell script to restart failed containers?" — What limitations does this approach have at scale? (Hint: think about state tracking, distributed coordination, and network topology.)
Answers
- Any three from: scheduling, self-healing/restart, load balancing, scaling, rolling updates, service discovery. Full list: deciding where containers run, restarting crashed containers, distributing traffic, scaling up/down, rolling out updates, service discovery.
- A container packages an application and its dependencies into an isolated, portable unit. A container orchestration system manages the lifecycle of many containers across many machines — handling placement, scaling, health, and networking — so operators do not have to do this manually.
- The orchestrator detects the node is unreachable (via health checks). It marks that node as
NotReady. It identifies the 2 container instances that were running on the failed node. It schedules 2 replacement instances on the remaining 4 healthy nodes. The load balancer is updated to remove the failed node's IP from the pool and add the new instances' IPs. End users experience no interruption (assuming the rollout of replacements is fast enough).- Shell scripts are single-point solutions: they run on one machine and have no awareness of other machines. Limitations include: (a) they cannot detect failures on remote hosts without complex polling logic; (b) they have no consistent view of global state across nodes; (c) they cannot make scheduling decisions based on available resources; (d) they do not handle network reconfiguration; (e) concurrent execution across nodes leads to race conditions; (f) they provide no audit trail or rollback mechanism.
Problems Solved by Orchestration
Theory
To appreciate orchestration, it helps to enumerate the concrete operational problems that arise when running containers in production without it.
| Problem | Without Orchestration | With Orchestration |
|---|---|---|
| Container crash | Manual restart by an operator | Automatic restart by the system |
| Node failure | Manual rescheduling to other machines | Automatic rescheduling |
| Traffic spikes | Manual scaling (more containers by hand) | Automatic horizontal scaling |
| Deployment update | Manual, often requires downtime | Rolling update with zero downtime |
| Service discovery | Hardcoded IPs or manual DNS updates | Dynamic service registry |
| Resource waste | Containers placed arbitrarily, nodes over/under-used | Bin-packing based on CPU/memory requests |
| Secret management | Passed as environment variables in scripts | Encrypted secrets injected at runtime |
| Configuration drift | Config files diverge across machines over time | Declarative config enforced continuously |
Each of these problems is manageable with one or two services. At hundreds of services and thousands of containers, manual management is not operationally viable.
Example
Consider the bin-packing problem. Without orchestration, you might manually assign containers to nodes without considering resource utilization:
Node A (8 CPU, 16GB RAM) — used manually:
[Container: 4 CPU] [Container: 4 CPU] [empty 8GB RAM wasted]
Node B (8 CPU, 16GB RAM) — used manually:
[Container: 2 CPU] [empty 6 CPU wasted] [Container: 8GB]
Total waste: 6 idle CPUs, 8GB idle RAM across 2 nodes
An orchestrator uses resource requests to pack containers efficiently:
Node A (8 CPU, 16GB RAM) — after orchestrator placement:
[4 CPU / 4GB] [2 CPU / 4GB] [2 CPU / 8GB] <- fully utilized
Node B is now free for other workloads or can be decommissioned,
saving cloud infrastructure cost.
Exercises
- (Beginner) What is "service discovery" and why does it become a problem at scale without orchestration?
- (Beginner) Match each problem to the orchestration feature that solves it: (a) container crash, (b) traffic spike, (c) deployment update. Features: rolling update, self-healing, autoscaling.
- (Intermediate) Explain "configuration drift" with a concrete example involving three servers and a configuration file.
- (Interview) Your team argues that since you only have 5 microservices, you don't need Kubernetes. What are the strongest arguments for and against adopting it at this scale? (Hint: consider operational overhead vs. future growth and team learning curve.)
Answers
- Service discovery is the mechanism by which one service finds the network address (IP and port) of another. Without orchestration, containers may be assigned dynamic IPs when restarted or moved. Hardcoding IPs breaks whenever a container moves. At scale, with hundreds of services restarting frequently, keeping IP mappings current manually is impossible. Orchestrators provide a stable DNS name or virtual IP that always resolves to healthy instances.
- (a) crash -> self-healing; (b) traffic spike -> autoscaling; (c) deployment update -> rolling update.
- Example: three servers initially all have
config.yamlwithlog_level: INFO. An operator SSHes into server-1 to debug an issue and changes it tolog_level: DEBUG, then forgets to revert. A week later, another operator SSHes into server-2 and adds a new database connection string. Server-3 remains at the original config. Now all three servers have different configurations, causing inconsistent behavior that is hard to diagnose. Orchestration solves this by enforcing a single source of truth: the declared config in the cluster's API is applied to all instances continuously.- Arguments for: (a) Kubernetes skills are valuable and the team learns on a smaller, lower-risk system before it becomes critical; (b) growth from 5 to 50 services is easier if the infrastructure is already in place; (c) rolling updates, health checks, and self-healing are valuable even at small scale. Arguments against: (a) Kubernetes has significant operational overhead — the control plane itself must be maintained; (b) simpler tools (Docker Compose, a single VM with systemd) may suffice; (c) debugging Kubernetes networking and scheduling adds cognitive complexity; (d) small teams may find the learning curve slows delivery.
Evolution from VMs to Containers to Orchestration
Theory
Modern container orchestration did not appear in isolation — it is the product of decades of progress in how we isolate and deploy software. Understanding this lineage clarifies why each layer of the stack exists.
Physical Servers (pre-2000s)
Early software ran directly on physical hardware. One application per server was common, because applications often conflicted in their library versions and OS dependencies. Utilization was poor — a server bought for peak load sat idle most of the time.
Virtual Machines (2000s)
Hypervisors (VMware, KVM, Xen) allowed a single physical machine to host multiple isolated virtual machines, each with its own OS. This improved utilization and allowed different applications with conflicting dependencies to coexist. However, VMs are heavyweight: each carries a full OS kernel (gigabytes of disk, hundreds of megabytes of RAM), and boot times are measured in minutes.
Containers (2010s)
Containers use Linux kernel features — namespaces (for isolation) and cgroups (for resource limiting) — to create isolated environments that share the host OS kernel. This eliminates the overhead of a full OS per unit: containers are megabytes in size and start in milliseconds. Docker (2013) made containers accessible to developers by providing a simple toolchain and a public image registry.
Container Orchestration (mid-2010s onward)
As organizations adopted containers at scale, the need to manage them systematically became acute. Running 10 containers manually is feasible. Running 10,000 across a dynamic fleet of machines is not. Orchestration platforms emerged to automate the placement, scaling, networking, and lifecycle management of containers across clusters.
Timeline of the evolution:
Physical Server
|
| Problem: resource waste, conflicts, slow provisioning
v
Virtual Machine (VMware, KVM)
|
| Problem: heavyweight (full OS per VM), slow boot, large footprint
v
Container (Docker, runc, OCI standard)
|
| Problem: managing thousands of containers manually doesn't scale
v
Container Orchestration (Kubernetes, Docker Swarm, Nomad)
Example: Comparing Resource Footprints
+------------------+------------------+------------------+
| Physical Server | Virtual Machine | Container |
+------------------+------------------+------------------+
| Full hardware | Virtualized HW | Process + libs |
| One OS | Own OS kernel | Shared OS kernel |
| Days to reprovision| Minutes to boot| Milliseconds |
| GB of overhead | 1-4 GB overhead | 10-200 MB image |
| Near-zero density| ~10-20 VMs/host | 100s/host |
+------------------+------------------+------------------+
A concrete size comparison for running an nginx web server:
Full VM image running nginx: ~2,000 MB (OS + libraries + nginx)
Docker image (nginx:alpine): ~23 MB (just what nginx needs)
Startup time (VM): 60-120 seconds
Startup time (container): < 1 second
Exercises
- (Beginner) What Linux kernel features underpin container isolation? Name both and describe what each does.
- (Beginner) Why are VMs considered "heavyweight" compared to containers?
- (Intermediate) A company runs 500 VMs on a fleet of physical servers. An engineer proposes migrating to containers. What are three concrete benefits they should expect, and one risk they must manage?
- (Interview) "Containers are just lightweight VMs." Is this statement accurate? Explain the technical distinction. (Hint: consider the role of the OS kernel in each model.)
Answers
- Namespaces provide isolation: each container sees its own view of the file system (mount namespace), process tree (PID namespace), network interfaces (network namespace), and hostname (UTS namespace). cgroups (control groups) enforce resource limits: they cap how much CPU, memory, disk I/O, and network bandwidth a container can consume, preventing one container from starving others.
- VMs are heavyweight because each includes a full, independent OS kernel and OS userland (init system, system libraries, drivers). This typically adds 1–4 GB of disk space and hundreds of MB of RAM per VM, plus minutes of boot time as the kernel initializes. Containers share the host OS kernel, so they only include the application and its userspace dependencies.
- Benefits: (a) Higher density — a host that ran 20 VMs might run 200 containers, reducing infrastructure cost; (b) faster deployment — new container instances start in under a second versus minutes for a VM; (c) consistent environments — container images bundle all dependencies, eliminating "works on my machine" problems. Risk: (a) shared kernel security boundary — a kernel exploit could affect all containers on a host simultaneously, whereas VMs provide stronger isolation; teams must apply OS patches to the host promptly and consider additional sandboxing (gVisor, Kata Containers) for untrusted workloads.
- The statement is inaccurate. VMs virtualize hardware: each VM runs a complete, independent OS kernel on top of a hypervisor. The kernel itself is isolated. Containers do not virtualize the kernel — they share the host OS kernel and use kernel-level isolation primitives (namespaces, cgroups) to separate processes. This makes containers faster and lighter but means they are OS-kernel-sharing processes, not isolated machines. A kernel-level bug on the host affects all containers; an equivalent bug in a guest OS affects only that VM.
Kubernetes vs Docker Swarm vs Nomad
Theory
Multiple container orchestration platforms exist, each with different design philosophies and trade-offs. The three most widely discussed are Kubernetes, Docker Swarm, and HashiCorp Nomad.
Kubernetes Originally developed at Google (derived from an internal system called Borg), Kubernetes is the most feature-rich and widely adopted orchestrator. It is highly extensible via Custom Resource Definitions (CRDs) and has a massive ecosystem. This power comes with complexity: Kubernetes has a steep learning curve and significant operational overhead.
Docker Swarm Docker Swarm is Docker's built-in orchestration mode. It is significantly simpler to set up than Kubernetes — a cluster can be initialized with a single command. It uses the same Docker Compose file format many developers already know. However, it has fewer features (no built-in autoscaling, limited scheduling options), a smaller ecosystem, and Docker Inc. has deprioritized its development in favor of Kubernetes integration.
HashiCorp Nomad Nomad is a general-purpose workload orchestrator from HashiCorp. Unlike Kubernetes, it is not container-specific — it can schedule Docker containers, Java JARs, binaries, and virtual machines using the same scheduler. It is architecturally simpler than Kubernetes and integrates naturally with other HashiCorp tools (Consul for service discovery, Vault for secrets). It is a strong choice for heterogeneous workloads but has a smaller community than Kubernetes.
| Feature | Kubernetes | Docker Swarm | Nomad |
|---|---|---|---|
| Workload types | Containers (OCI) | Docker containers | Containers, binaries, VMs |
| Setup complexity | High | Low | Medium |
| Learning curve | Steep | Gentle | Moderate |
| Autoscaling | Built-in (HPA, VPA) | Not built-in | Via Nomad autoscaler |
| Ecosystem/plugins | Very large (CNCF) | Small | Medium (HashiCorp) |
| Multi-tenancy | Strong (Namespaces, RBAC) | Basic | Moderate (Namespaces, ACLs) |
| Production adoption | Dominant | Declining | Niche but growing |
| Community size | Very large | Small | Medium |
| Best for | Large-scale, complex workloads | Simple Docker deployments | Mixed workloads, HashiCorp shops |
Example: Initializing a Cluster in Each System
# --- Docker Swarm: 2 commands to get a cluster running ---
docker swarm init # Initialize manager node
docker swarm join --token <TOKEN> <HOST> # Worker joins cluster
# --- Nomad: run agent on each node, federation is automatic ---
nomad agent -config=/etc/nomad.d/ # Start agent (dev mode: nomad agent -dev)
# --- Kubernetes: significantly more steps (simplified with kubeadm) ---
kubeadm init --pod-network-cidr=10.244.0.0/16 # Initialize control plane
# Then: configure kubectl, install a CNI plugin, join worker nodes
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
kubeadm join <HOST>:6443 --token <TOKEN> # Worker joins cluster
The setup complexity difference is real and operationally significant.
Exercises
- (Beginner) Name one scenario where Docker Swarm would be a more appropriate choice than Kubernetes.
- (Beginner) What makes Nomad distinct from both Kubernetes and Docker Swarm in terms of workload types it can manage?
- (Intermediate) A startup has a team of 3 engineers, runs 8 microservices as Docker containers, and needs to deploy to production quickly. Recommend an orchestrator and justify your choice considering trade-offs.
- (Interview) A candidate says: "Kubernetes won the orchestration wars, so there's no reason to ever choose Nomad or Swarm." Present a technical counter-argument. (Hint: think about operational simplicity, heterogeneous workloads, and total cost of ownership.)
Answers
- Docker Swarm is appropriate when: the team is small and already fluent with Docker Compose; the number of services is low (< 20); setup must be done quickly with minimal operational overhead; and advanced features like autoscaling and complex scheduling are not required. A small internal tooling deployment is a clear fit.
- Nomad is workload-agnostic: it can schedule Docker containers, raw binaries/executables, Java applications (JARs), and virtual machines (via the QEMU driver) using the same scheduler and job specification format. Kubernetes and Docker Swarm are both container-specific — they can only orchestrate OCI-compatible containers.
- Recommendation: Docker Swarm or a managed Kubernetes service (e.g., AWS EKS, Google GKE). Justification for Swarm: a 3-engineer team deploying 8 services has low complexity, and the overhead of operating a self-managed Kubernetes cluster (etcd maintenance, control plane upgrades, CNI management) would consume significant engineering time. Swarm's Docker Compose compatibility means a lower learning curve. Justification for managed Kubernetes: if the team expects rapid growth, starting on Kubernetes (managed) avoids a painful migration later; the managed control plane removes most operational burden. The key trade-off is operational overhead today vs. migration cost later.
- Counter-argument: "Kubernetes won" applies to the general market, not to every specific use case. (a) Operational cost: Kubernetes requires significant expertise to operate safely. A small team may spend more time managing Kubernetes than building product; Swarm or Nomad reduces this cost. (b) Heterogeneous workloads: organizations running a mix of legacy Java applications, native binaries, and containers benefit from Nomad's unified scheduler — Kubernetes cannot natively schedule non-containerized workloads without significant workarounds. (c) HashiCorp integration: teams already using Consul, Vault, and Terraform have a cohesive operational model with Nomad that is harder to replicate with Kubernetes. The right tool depends on organizational context, not market share.
1.2 Kubernetes Overview
Kubernetes is more than a piece of software — it is a project, a community, and an ecosystem. This subchapter traces Kubernetes from its origins inside Google to its current position as the foundation of modern cloud-native infrastructure.
History and Origin of Kubernetes
Theory
Kubernetes was not invented in a vacuum. For over a decade before its public release, Google ran nearly all of its services — Search, Gmail, YouTube — on an internal cluster management system called Borg. Borg scheduled containers (using Linux cgroups, though the term "container" was not yet common) across Google's global fleet of machines, automatically handling failures, resource packing, and rolling updates at a scale no other organization matched.
In 2013, Docker made containers accessible to the broader industry. Google recognized that the industry would soon face the same scale problems Borg had already solved. A small team — including Joe Beda, Brendan Burns, and Craig McLuckie — began building an open-source system inspired by Borg's lessons but designed for the broader ecosystem. This project was initially named "Project Seven" (a reference to the Star Trek character Seven of Nine, a nod to a "more humane Borg").
Kubernetes (from the Greek "kubernetes," meaning helmsman or pilot) was announced publicly at Google I/O in June 2014 and version 1.0 was released in July 2015. On the same day as the 1.0 release, Google donated Kubernetes to the Cloud Native Computing Foundation (CNCF), a newly formed vendor-neutral foundation under the Linux Foundation.
Key milestones:
| Year | Event |
|---|---|
| 2003 | Google's Borg system begins internal development |
| 2013 | Docker is released publicly; containers go mainstream |
| 2014 | Kubernetes announced at Google I/O (June) |
| 2015 | Kubernetes 1.0 released; donated to CNCF (July) |
| 2016 | Kubernetes becomes the most popular container orchestrator |
| 2018 | Kubernetes graduates from CNCF incubation |
| 2022+ | Kubernetes is the foundation of nearly all major cloud platforms |
Example: The Borg Legacy in Kubernetes Design
Many Kubernetes concepts map directly to Borg concepts, demonstrating the lineage:
Borg Concept -> Kubernetes Equivalent
---------------------------------------------------
Borgmaster -> kube-apiserver (control plane)
Borg scheduler -> kube-scheduler
Borglet -> kubelet (node agent)
Task -> Container
Job -> Deployment / StatefulSet
Alloc -> Pod (the unit of co-scheduling)
BNS (naming) -> Kubernetes Services + DNS
The paper "Large-scale cluster management at Google with Borg" (2015, Verma et al.) formally documented Borg and is worth reading alongside Kubernetes documentation.
Exercises
- (Beginner) What is the name of Google's internal cluster management system that inspired Kubernetes?
- (Beginner) What does the word "Kubernetes" mean, and what is the significance of the name?
- (Intermediate) Why did Google choose to open-source Kubernetes and donate it to the CNCF rather than keep it proprietary or sell it as a product?
- (Interview) What lessons from the Borg paper are reflected in Kubernetes's design? (Hint: think about the alloc/Pod abstraction and the value of declarative job specifications.)
Answers
- Google's internal cluster management system is called Borg. It has been running Google's production workloads since approximately 2003.
- "Kubernetes" is a Greek word meaning helmsman or pilot — the person who steers a ship. The name reflects the system's role in steering containerized applications across infrastructure. The "k8s" abbreviation replaces the eight letters between "k" and "s."
- Google's primary business is cloud services, not software licensing. By open-sourcing Kubernetes: (a) the broader industry would adopt containers, growing the overall market for cloud infrastructure; (b) a strong open-source community would contribute improvements that benefit Google at no cost; (c) the ecosystem of tools built around Kubernetes (monitoring, logging, CI/CD) would also benefit Google Cloud customers; (d) a vendor-neutral foundation (CNCF) would prevent any single vendor from controlling the standard, which also served Google's interests against Microsoft and Amazon.
- Key Borg lessons reflected in Kubernetes: (a) The alloc (Pod) abstraction: Borg learned that grouping multiple tasks that must run together on the same machine (e.g., a web server and a log shipper) required a first-class scheduling unit — the alloc. Kubernetes adopted this as the Pod. (b) Declarative specifications: Borg operators specified what they wanted (replicas, resources, health checks), not a procedure, allowing the system to reconcile reality to the spec. Kubernetes inherits this as its declarative model. (c) Importance of naming and discovery: Borg's naming service (BNS) became Kubernetes Services and DNS. (d) Priority and preemption: Borg's workload classes (production vs. batch) informed Kubernetes's QoS classes and priority classes.
CNCF and the Kubernetes Ecosystem
Theory
The Cloud Native Computing Foundation (CNCF) is a vendor-neutral open-source foundation, itself a part of the Linux Foundation. It was founded in 2015 with Kubernetes as its seed project. The CNCF's mission is to foster and sustain the ecosystem of open-source, cloud-native technologies.
"Cloud-native" refers to an approach to building and running applications that exploits the advantages of the cloud computing model: elasticity, distributed systems, automation, and resilience. Cloud-native applications are typically containerized, dynamically orchestrated, and composed of microservices.
The CNCF manages a landscape of over 1,000 projects and products organized into categories. Projects go through a maturity lifecycle:
- Sandbox: Early-stage, experimental projects
- Incubating: Growing adoption, defined governance
- Graduated: Proven at scale, stable API, strong governance (Kubernetes, Prometheus, Envoy, etc.)
Notable CNCF graduated projects that commonly accompany Kubernetes in production:
| Project | Category | Purpose |
|---|---|---|
| Kubernetes | Orchestration | Container lifecycle management |
| Prometheus | Monitoring | Metrics collection and alerting |
| Envoy | Service Proxy | Layer-7 proxy, sidecar pattern |
| Helm | Package Management | Kubernetes application packaging |
| Fluentd | Logging | Log collection and routing |
| containerd | Container Runtime | Low-level container execution |
| Argo | CI/CD | GitOps and workflow orchestration |
| Jaeger | Tracing | Distributed request tracing |
The CNCF ecosystem is often visualized as the "CNCF Landscape" — a sprawling map of tools covering every layer of cloud-native infrastructure.
Example: A Typical Kubernetes + CNCF Production Stack
+---------------------------------------------------------------+
| Application Layer |
| Your Microservices (running as Kubernetes Deployments) |
+---------------------------------------------------------------+
| Kubernetes (Orchestration) |
| Scheduling | Self-healing | Scaling | Service Discovery |
+---------------------------------------------------------------+
| Helm (packaging) | Argo CD (GitOps deployment) |
+---------------------------------------------------------------+
| Envoy/Istio (service mesh, mTLS, traffic management) |
+---------------------------------------------------------------+
| Prometheus + Grafana (metrics) | Jaeger (tracing) |
| Fluentd + Elasticsearch (logs) |
+---------------------------------------------------------------+
| containerd (container runtime) |
+---------------------------------------------------------------+
| Linux Nodes (VMs or bare metal) |
+---------------------------------------------------------------+
Each layer solves a distinct problem. Kubernetes alone does not provide a complete production system — the surrounding CNCF ecosystem completes it.
Exercises
- (Beginner) What does CNCF stand for, and what is its stated purpose?
- (Beginner) What are the three maturity stages of a CNCF project?
- (Intermediate) Why is Helm described as a "package manager for Kubernetes"? What problem does it solve that plain YAML files do not?
- (Interview) A CTO says: "We're adopting Kubernetes — that handles everything we need for production." What gaps in a production system does Kubernetes alone not address, and what tools fill them? (Hint: think about observability, security, and packaging.)
Answers
- CNCF stands for Cloud Native Computing Foundation. Its purpose is to foster and sustain the ecosystem of open-source, cloud-native technologies by providing a vendor-neutral home for important projects and promoting cloud-native best practices.
- The three maturity stages are: Sandbox (experimental, early adoption), Incubating (growing, defined governance), and Graduated (production-proven, stable, strong governance).
- Helm is a package manager for Kubernetes because it solves the problem of deploying complex applications that require many related Kubernetes resources (Deployments, Services, ConfigMaps, Secrets, RBAC rules, etc.). Without Helm, each resource must be managed as a separate YAML file with no built-in mechanism for versioning, parameterization (e.g., different values for dev vs. prod), or atomic installation/upgrade/rollback. A Helm Chart is a versioned, parameterizable bundle of all related resources that can be installed, upgraded, and rolled back as a single unit with
helm install/helm upgrade/helm rollback.- Gaps and tools: (a) Observability/Metrics: Kubernetes does not collect or store application metrics. Prometheus (metrics) + Grafana (visualization) fill this. (b) Distributed tracing: no built-in request tracing across services; Jaeger or Tempo provide this. (c) Log aggregation: Kubernetes provides raw container logs but no long-term storage or search; Fluentd + Elasticsearch + Kibana (or Loki + Grafana) fill this. (d) Application packaging: raw YAML files are not parameterizable or versioned as a unit; Helm solves this. (e) GitOps/CD: Kubernetes has no built-in continuous deployment; Argo CD or Flux provide this. (f) Service-to-service security (mTLS): Kubernetes networking does not encrypt traffic between pods by default; a service mesh (Istio, Linkerd) adds mutual TLS. (g) Secret management beyond basic: Kubernetes Secrets are base64-encoded (not encrypted at rest by default); Vault or Sealed Secrets provide stronger secret management.
Kubernetes Use Cases and Adoption
Theory
Kubernetes has been adopted across a remarkably diverse range of organizations and use cases, from small startups to global enterprises. Understanding the use cases helps clarify when Kubernetes is the right choice and when it may be overkill.
Primary use cases:
- Microservices deployment: Running and managing dozens to hundreds of independently deployable services
- Batch and data processing: Running periodic or event-driven workloads (CronJobs, one-off Jobs)
- CI/CD pipelines: Spinning up ephemeral build environments and test runners
- Machine learning workflows: Managing GPU workloads, training jobs, and model serving (Kubeflow)
- Edge computing: Running Kubernetes on smaller clusters at edge locations (k3s)
- Multi-cloud and hybrid cloud: Providing a consistent API across cloud providers and on-premises
Who uses Kubernetes:
Organizations across industries run Kubernetes in production: Airbnb, Spotify, Pinterest, The New York Times, Goldman Sachs, Walmart, CERN, and the majority of Fortune 500 companies. CNCF annual surveys consistently show over 90% of respondents using Kubernetes in some form.
When Kubernetes may be the wrong choice:
- Single monolithic application with no plans to decompose
- Very small team with no existing container expertise
- Stateful applications with complex data requirements that are not yet containerized
- Workloads that do not benefit from horizontal scaling
Example: Mapping Use Cases to Kubernetes Features
Use Case -> Kubernetes Feature Used
----------------------------------------------------
Long-running API server -> Deployment + Service
Scheduled batch job -> CronJob
Database (stateful) -> StatefulSet + PersistentVolumeClaim
One-off migration job -> Job
A/B testing -> Ingress + canary Deployment
GPU-based ML training -> Job with GPU resource limits
Autoscaling web app -> Deployment + HorizontalPodAutoscaler
Configuration by env -> ConfigMap + Secret
Multi-tenant SaaS -> Namespaces + RBAC + ResourceQuota
Exercises
- (Beginner) Name two Kubernetes use cases beyond running a web API server.
- (Beginner) What is the difference between a Kubernetes
Joband aCronJob?- (Intermediate) An e-commerce company has a single monolithic application written in PHP, deployed on 3 VMs, and serving 10,000 users per day. Their engineering manager wants to "move everything to Kubernetes." Evaluate whether this is advisable.
- (Interview) Kubernetes is sometimes described as both "the best and worst solution" for microservices. What does this mean? (Hint: think about the operational value it provides versus the complexity it introduces.)
Answers
- Any two from: batch and data processing, CI/CD pipeline environments, machine learning workload management, edge computing, multi-cloud deployments, A/B testing, scheduled database migrations, GPU workloads.
- A Job runs a containerized task to completion exactly once (or a specified number of times with optional parallelism) and then terminates. A CronJob is a Job that is automatically scheduled to run on a recurring schedule defined by a cron expression (e.g.,
0 2 * * *for 2am daily). A CronJob creates a new Job object each time its schedule fires.- This is likely inadvisable without significant prerequisites. A PHP monolith on 3 VMs is a well-understood system with predictable failure modes. Moving it to Kubernetes without first containerizing the application, addressing state management (session data, file uploads), understanding Kubernetes networking, and training the team introduces enormous risk for uncertain benefit. Kubernetes provides the most value for decomposed services that need independent scaling. The recommendation should be: (a) first containerize the monolith and validate it works in Docker; (b) evaluate whether the operational problems (scaling, downtime during deployments) justify Kubernetes; (c) consider a managed Kubernetes service to reduce operational overhead; (d) plan a migration path rather than a big-bang lift-and-shift.
- Kubernetes is "the best solution" for microservices because it directly solves the hardest operational problems at scale: scheduling, health management, service discovery, rolling updates, and resource efficiency across large fleets. It is "the worst solution" because it introduces significant accidental complexity: a new networking model, a new security model (RBAC), a new way to think about storage, a large surface area of YAML configuration, and an operational dependency on the Kubernetes control plane itself. Organizations that adopt Kubernetes prematurely — before they have the scale problems it solves or the expertise to operate it — often find that the tool creates more problems than it resolves. The value proposition becomes clear at scale; below that threshold, the cost dominates.
Kubernetes Release Cycle and Versioning
Theory
Kubernetes follows a structured, predictable release process. Understanding it matters for operators: running an unsupported version in production creates security and stability risks, and upgrades require planning.
Release cadence: Kubernetes publishes approximately 3 minor releases per year, roughly every 4 months (historically targeting January, May, and September, though exact dates vary). Each minor release is designated 1.X (e.g., 1.28, 1.29, 1.30).
Version scheme:
v1.30.2
^ ^ ^
| | |
| | Patch version (bug fixes, security patches — no API changes)
| Minor version (new features, may deprecate APIs)
Major version (breaking changes; has been 1 since 2015)
Support window: Each minor version receives patch releases for approximately 14 months from its release date. At any given time, approximately 3 minor versions are actively supported. This means clusters must be upgraded roughly every 14 months to stay within support.
API deprecation policy: Kubernetes has a formal policy for removing deprecated API versions. APIs are typically deprecated for at least 3 minor releases before removal for GA APIs, and 1 release for alpha APIs. Operators must track deprecations when upgrading.
Feature maturity gates:
| Stage | Stability | Default Enabled | API Change Risk |
|---|---|---|---|
Alpha (v1alpha1) | Experimental | No (feature gate required) | May be removed without notice |
Beta (v1beta1) | Mostly stable | Yes (in most releases) | May change; deprecated with notice |
GA/Stable (v1) | Production-ready | Yes | Breaking changes only in major versions |
Exercises
- (Beginner) How many minor Kubernetes releases are published per year, and approximately how long is each minor version supported?
- (Beginner) Given the version string
v1.29.4, identify the major, minor, and patch version numbers and explain what each change typically represents.- (Intermediate) Your production cluster runs Kubernetes v1.25. The current release is v1.30. How many versions behind are you, and what is the risk of remaining on v1.25?
- (Interview) A developer wants to use an alpha API feature in production. What are the risks, and how would you advise them? (Hint: consider the alpha stability guarantee and the production impact of an API being removed in the next release.)
Answers
- Kubernetes publishes approximately 3 minor releases per year. Each minor version is supported for approximately 14 months (receiving patch releases during that window). At any given time, roughly 3 minor versions are in the support window simultaneously.
v1.29.4: Major version 1 — the major version has been 1 since 2015; a major version bump would indicate breaking API changes across the project. Minor version 29 — minor versions introduce new features and may deprecate APIs; upgrading minor versions requires reviewing changelogs for deprecations. Patch version 4 — patch releases contain only bug fixes and security patches; they do not change APIs and are generally safe to apply without significant testing.- v1.25 is 5 minor versions behind v1.30. Since Kubernetes supports approximately the last 3 minor versions, v1.25 is well outside the support window and has been for some time. Risks include: (a) no further security patches — known CVEs in v1.25 will not be fixed; (b) API deprecations — several API versions removed in v1.26–v1.30 (e.g.,
policy/v1beta1PodSecurityPolicy was removed in v1.25 itself, and subsequent versions removed other beta APIs); (c) incompatibility with newer tooling and Helm charts that require newer API versions; (d) inability to use new features (autoscaling improvements, scheduling enhancements, security hardening). Upgrading 5 versions requires a sequential process (cannot skip more than 1-2 minor versions per upgrade) and should be treated as a significant project.- Using alpha APIs in production carries several critical risks: (a) No stability guarantee: alpha APIs may be changed or removed entirely in the next release with no deprecation period; (b) Not enabled by default: alpha features require explicit feature gates, which may complicate cluster configuration and upgrades; (c) Untested at scale: alpha features have not been through the community's broad testing process; production behavior may differ from expectations; (d) Upgrade blocking: if the alpha API is removed in the next release, your production workloads that depend on it will break during the cluster upgrade. Advice: use the GA (
v1) or beta (v1beta1) equivalent if one exists. If no stable version exists, treat the feature as a prototype, document the dependency clearly, establish a plan for migration when the API graduates, and thoroughly test every upgrade. Do not use alpha APIs in production systems where uptime is critical.
1.3 Core Concepts and Terminology
Kubernetes has a rich, precise vocabulary. Misunderstanding these foundational terms causes confusion when reading documentation, debugging issues, and discussing architecture. This subchapter defines the essential concepts and the mental models that connect them.
Clusters, Nodes, and Pods
Theory
These three terms form the basic hierarchy of a Kubernetes deployment. Each level is a composition of the one below it.
Cluster
A Kubernetes cluster is the top-level administrative unit — the complete set of machines and control software that Kubernetes manages as a single system. When you run kubectl commands, you are talking to a cluster's API server. An organization typically has multiple clusters (development, staging, production; or regional clusters for geographic distribution).
Node
A node is a single machine (physical server or virtual machine) that is a member of a cluster. Nodes are the workers — they run the actual containers. Each node runs a small set of Kubernetes system processes (kubelet, kube-proxy, a container runtime) that allow the control plane to manage it.
There are two roles a node can play:
- Control plane node (formerly "master"): runs the Kubernetes management components (API server, scheduler, controller manager, etcd)
- Worker node: runs user workloads (your containers)
Pod
A Pod is the smallest deployable unit in Kubernetes. It is not a container — it is a wrapper around one or more containers that should always run together on the same node, share the same network namespace (same IP address), and optionally share storage volumes.
Most Pods contain a single container. The multi-container Pod pattern is used for specific cases, such as:
- Sidecar: a helper container alongside the main container (e.g., a log shipper)
- Ambassador: a proxy that handles external communication on behalf of the main container
- Init containers: containers that run to completion before the main container starts
Cluster
|
+-- Node (worker-1, e.g., 8 CPU / 32GB RAM)
| |
| +-- Pod (api-pod-abc)
| | |-- Container: api-server (nginx)
| | |-- Container: log-sidecar (fluentd)
| |
| +-- Pod (auth-pod-xyz)
| |-- Container: auth-service (go binary)
|
+-- Node (worker-2, e.g., 8 CPU / 32GB RAM)
|
+-- Pod (api-pod-def) <- another replica of api
|-- Container: api-server (nginx)
|-- Container: log-sidecar (fluentd)
Example: Inspecting Cluster, Nodes, and Pods
# View all nodes in the cluster and their status
kubectl get nodes
# Example output:
# NAME STATUS ROLES AGE VERSION
# master-1 Ready control-plane 30d v1.30.0
# worker-1 Ready <none> 30d v1.30.0
# worker-2 Ready <none> 30d v1.30.0
# View all Pods across all namespaces
kubectl get pods --all-namespaces
# Describe a specific Pod to see containers, node assignment, and events
kubectl describe pod api-pod-abc -n default
A minimal Pod definition in YAML:
apiVersion: v1
kind: Pod
metadata:
name: my-api-pod # Unique name within the namespace
labels:
app: my-api # Labels used for selection by Services/Deployments
spec:
containers:
- name: api # Name of the container within the Pod
image: my-api:1.0 # Docker image to run
ports:
- containerPort: 8080 # Port the container listens on (documentation only)
resources:
requests:
cpu: "250m" # Request 0.25 CPU cores
memory: "128Mi" # Request 128 megabytes of RAM
limits:
cpu: "500m" # Never use more than 0.5 CPU cores
memory: "256Mi" # Never use more than 256MB RAM
Exercises
- (Beginner) What is the relationship between a Cluster, a Node, and a Pod? Write one sentence describing how they are related.
- (Beginner) Why would you put two containers in the same Pod instead of separate Pods?
- (Intermediate) A Pod has two containers:
appandsidecar. Theappcontainer writes logs to/var/log/app/app.log. How would you configure the sidecar to read those logs? What Kubernetes feature enables this?- (Interview) "You should always use one container per Pod." Is this a rule or a guideline? When is it correct to violate it, and when should you not? (Hint: consider tight coupling, the sidecar pattern, and scaling implications.)
Answers
- A Cluster is the complete Kubernetes system; it consists of multiple Nodes (machines); each Node runs one or more Pods; each Pod contains one or more containers that run together on that Node.
- Two containers belong in the same Pod when they are tightly coupled and must: (a) always run on the same physical machine; (b) share the same network namespace (communicate via
localhostrather than the network); (c) share a filesystem volume (e.g., one container writes files that another reads). The sidecar pattern — a main application container + a helper (logging agent, proxy, secrets refresher) — is the canonical example.- You would use a shared emptyDir volume. Both containers mount the volume at the same path (or different paths that serve the same logical purpose). The
appcontainer writes to/var/log/app/which is backed by the volume. Thesidecarcontainer mounts the same volume and reads from it. AnemptyDirvolume is created when a Pod is assigned to a node and deleted when the Pod is removed; it enables intra-Pod file sharing.
```yaml
spec:
volumes:
- name: log-volume # Shared emptyDir volume
emptyDir: {}
containers:
- name: app
image: my-app:1.0
volumeMounts:
- name: log-volume
mountPath: /var/log/app # App writes logs here
- name: sidecar
image: fluentd:latest
volumeMounts:
- name: log-volume
mountPath: /var/log/app # Sidecar reads logs from the same path
```
4. "One container per Pod" is a guideline, not an absolute rule. It should be followed in the vast majority of cases because: (a) it enables independent scaling — scaling a Deployment scales all containers in the Pod together; if
appanddbare in the same Pod, you cannot scaleappwithout also scalingdb; (b) it enables independent lifecycle management — separate Pods can be updated independently. It is correct to use multiple containers per Pod specifically for the sidecar pattern (log shippers, proxy agents, secrets injectors) where the helper container is a per-instance concern tightly coupled to the main container's lifecycle. It is incorrect when the containers have different scaling requirements or could be independently deployed services.
Control Plane vs Data Plane
Theory
Kubernetes separates its responsibilities into two distinct planes of operation. This separation is a fundamental architectural decision that enables Kubernetes to be both highly available and scalable.
Control Plane
The control plane is the "brain" of the cluster. It makes global decisions about the cluster (scheduling, scaling, responding to failures) and is responsible for maintaining the desired state. The control plane components are:
| Component | Responsibility |
|---|---|
kube-apiserver | The front door to Kubernetes — all communication goes through it. Exposes the Kubernetes API over HTTPS. Validates and processes API requests. |
etcd | A distributed key-value store that holds all cluster state. The single source of truth for desired configuration. |
kube-scheduler | Watches for unscheduled Pods and assigns them to appropriate nodes based on resource availability, affinity rules, and policies. |
kube-controller-manager | Runs control loops (controllers) that watch cluster state and take action to converge reality to desired state (e.g., the ReplicaSet controller ensures the right number of Pod replicas exist). |
cloud-controller-manager | (Optional) Integrates with cloud provider APIs (AWS, GCP, Azure) to manage load balancers, volumes, and node lifecycle. |
Data Plane
The data plane is where the actual workloads run. It consists of the worker nodes and the components running on them:
| Component | Responsibility |
|---|---|
kubelet | The node agent. Receives Pod specs from the API server and ensures the containers described are running and healthy. Reports node and Pod status back to the control plane. |
kube-proxy | Manages network rules on each node to implement Kubernetes Services — ensuring traffic destined for a Service IP is forwarded to the appropriate Pod(s). |
| Container Runtime | The software that actually runs containers (e.g., containerd, CRI-O). The kubelet delegates to it via the Container Runtime Interface (CRI). |
+---------------------------+ +---------------------------+
| CONTROL PLANE | | DATA PLANE |
| | | |
| kube-apiserver <--------+--+-> kubelet (each node) |
| | | | | |
| etcd (cluster state) | | container runtime |
| kube-scheduler | | kube-proxy |
| controller-manager | | |
| cloud-controller-manager | | [Your Pods run here] |
+---------------------------+ +---------------------------+
^
|
kubectl (your CLI)
In production, the control plane typically runs on dedicated nodes (separate from worker nodes) and is often replicated (3 or 5 instances of each component) for high availability.
Example: Control Plane in Action — Pod Scheduling
When you apply a Deployment, a chain of control plane events occurs:
1. You run: kubectl apply -f deployment.yaml
2. kube-apiserver:
- Receives the request
- Validates the YAML against the API schema
- Authenticates and authorizes your identity (RBAC)
- Writes the Deployment object to etcd
3. kube-controller-manager (Deployment controller):
- Notices a new Deployment object
- Creates a ReplicaSet object representing the desired Pods
- ReplicaSet controller creates Pod objects (with no node assigned)
- Writes Pods to etcd with nodeName: "" (unscheduled)
4. kube-scheduler:
- Watches for Pods with no nodeName
- Evaluates all nodes: resource availability, taints/tolerations, affinity
- Selects best node; writes nodeName: "worker-2" to the Pod in etcd
5. kubelet on worker-2:
- Watches for Pods assigned to its node
- Reads the Pod spec
- Instructs containerd to pull the image and start the container
- Monitors the container; reports status back to kube-apiserver
Exercises
- (Beginner) Name the two planes in Kubernetes and state the primary responsibility of each.
- (Beginner) What is
etcdand why is it critical to the cluster?- (Intermediate) If
kube-schedulercrashes, what happens to existing running Pods? What happens if you try to create a new Pod while the scheduler is down?- (Interview) Why is it important to run an odd number of
etcdnodes (e.g., 3 or 5) in a production cluster? (Hint: consider distributed consensus and what happens when a node becomes unreachable.)
Answers
- Control plane: makes decisions about the cluster (scheduling, scaling, reconciliation); maintains desired state. Data plane: executes workloads; runs the actual containers as directed by the control plane.
etcdis a distributed, consistent key-value store. It is the single source of truth for all Kubernetes cluster state — every object (Pods, Deployments, ConfigMaps, Secrets, etc.) is stored in etcd. Every change to the cluster is committed to etcd before being acted upon. If etcd data is lost without a backup, the cluster state is unrecoverable. This makes etcd the most critical component to back up and make highly available.- Existing Pods: unaffected. The kubelet on each node manages running containers locally. Containers that were already started continue running; the kubelet restarts them if they crash (it does not need the scheduler for this — it already knows which Pods it should be running). New Pods: they are created as objects in etcd (by the controller manager) with no node assignment, and they remain in
Pendingstate indefinitely until the scheduler recovers and assigns them to nodes. No new workload can be placed on nodes while the scheduler is down.- etcd uses the Raft consensus algorithm, which requires a majority quorum of nodes to agree before any write is committed. With
nnodes, the cluster tolerates(n-1)/2node failures and still achieves quorum. With 3 nodes: tolerates 1 failure (2 of 3 remain). With 5 nodes: tolerates 2 failures (3 of 5 remain). With an even number (e.g., 4 nodes): you tolerate only 1 failure (need 3 of 4), the same as with 3 nodes — but you pay for an extra node with no additional fault tolerance. Even-numbered clusters also carry a higher risk of a "split-brain" scenario where the cluster divides evenly and neither partition can achieve quorum. Therefore, 3 and 5 are the standard production configurations.
Declarative vs Imperative Model
Theory
These two terms describe fundamentally different ways of interacting with a system.
Imperative model: You tell the system how to achieve a goal, step by step.
"Start 3 copies of my container on these specific nodes.
Then, if one fails, restart it on node-2."
This is the model used by direct shell scripting, Docker CLI commands, and similar tools. You specify the procedure.
Declarative model: You tell the system what you want the end state to be. You do not describe how to get there — the system figures that out.
"I want 3 copies of my container running at all times."
The system examines current reality, compares it to what you declared, and makes whatever changes are necessary to close the gap. You describe the desired state; the system manages the procedure.
Kubernetes is primarily declarative. You write YAML manifests describing what you want (Deployments, Services, ConfigMaps), apply them to the cluster, and Kubernetes continuously works to ensure reality matches your declarations.
Why declarative?
- Idempotency: applying the same manifest multiple times produces the same result. Running the same imperative command twice might create duplicates or fail with a conflict.
- Self-documentation: the YAML files in your repository are always a current record of what should be running. There is no need for a separate runbook describing the current setup.
- GitOps: storing declarative manifests in git creates a complete audit trail of every change. Rolling back means reverting a git commit.
- Self-healing: the system continuously reconciles toward the declared state, which means it can automatically correct drift caused by failures.
Kubernetes does support imperative commands (e.g., kubectl run, kubectl delete, kubectl scale), but these are generally used for debugging and exploration, not for managing production systems.
Example: Imperative vs Declarative Side by Side
# --- IMPERATIVE: step-by-step instructions ---
# Create a deployment
kubectl run nginx --image=nginx:1.25 --replicas=3
# Scale it up
kubectl scale deployment nginx --replicas=5
# Update the image
kubectl set image deployment/nginx nginx=nginx:1.26
# Problem: the cluster's actual state may diverge from what you think it is.
# There is no canonical file representing "what should be running."
# --- DECLARATIVE: describe desired state in a file ---
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 5 # Desired state: 5 replicas
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26 # Desired state: version 1.26
# Apply the desired state. Kubernetes handles the rest.
kubectl apply -f deployment.yaml
# Apply again with replicas changed to 3 — Kubernetes scales down.
# Apply again with the same file — nothing changes (idempotent).
# A Pod crashes — Kubernetes restarts it without any further input.
Exercises
- (Beginner) In one sentence each, define imperative and declarative in the context of Kubernetes.
- (Beginner) What does "idempotent" mean, and why is it important for declarative systems?
- (Intermediate) A colleague runs
kubectl scale deployment api --replicas=10directly on the production cluster to handle a traffic spike. An hour later, someone runskubectl apply -f deployment.yaml(which declaresreplicas: 3). What happens? What does this illustrate about imperative changes to declaratively managed resources?- (Interview) What is GitOps, and how does Kubernetes's declarative model enable it? (Hint: think about what git provides — versioning, audit, rollback — and how it maps to managing declared cluster state.)
Answers
- Imperative: you tell Kubernetes the specific steps to perform (run this command, scale to this number, update this image). Declarative: you tell Kubernetes the desired end state (a file describing what should exist), and Kubernetes determines and executes the steps to achieve it.
- Idempotent means that performing the same operation multiple times produces the same result as performing it once. For declarative systems, this is critical because
kubectl apply -f deployment.yamlcan be run repeatedly — in CI/CD pipelines, after operator error, after a network failure — and it will always converge to the declared state without creating duplicate resources or causing errors if nothing has changed.- The
kubectl applyoverwrites the Deployment'sreplicasfield back to 3, and Kubernetes scales down from 10 to 3 Pods. The imperativekubectl scalechange was overwritten by the declarative apply. This illustrates a critical operational rule: never mix imperative changes with declarative management for the same resource. Imperative changes bypass the source of truth (the YAML file), creating invisible state drift. When the file is applied next (by a human or a CI/CD pipeline), the imperative changes are silently reverted. The correct approach would have been to update the YAML file toreplicas: 10, apply it, and then revert to 3 in a tracked commit.- GitOps is an operational practice where the desired state of infrastructure (and applications) is stored entirely in a git repository. Deployments happen by committing changes to git, and an automated operator (Argo CD, Flux) continuously synchronizes the cluster's actual state to match what is in the git repository. Kubernetes's declarative model enables GitOps because: (a) desired state can be fully expressed as YAML files that can be committed to git; (b) these files are version-controlled — every change has an author, a timestamp, and a diff; (c) rollback means reverting a git commit, which automatically triggers re-synchronization to the previous desired state; (d) git's access control (branch protection, pull request review) becomes the control gate for infrastructure changes.
Desired State and Reconciliation Loop
Theory
The desired state and reconciliation loop are the two halves of the central operating principle of Kubernetes. Together, they explain why Kubernetes behaves the way it does.
Desired State
Desired state is what you have declared should exist in the cluster — the contents of your Kubernetes objects stored in etcd. It is the answer to the question: "What should the world look like?"
Examples of desired state:
- "There should be 3 running replicas of the
apiDeployment" - "The
apiService should route traffic to Pods with labelapp: api" - "The ConfigMap
app-configshould contain the keylog_level: INFO"
Actual State (Observed State)
Actual state is the current reality of the cluster: what containers are actually running, what their health is, what nodes exist. It is observed continuously by the control plane components.
Reconciliation Loop
The reconciliation loop (also called the control loop or watch loop) is the mechanism that closes the gap between desired and actual state. Every Kubernetes controller runs a reconciliation loop:
- Observe the current actual state
- Compare it to the desired state
- Act to reduce the difference (if any)
- Repeat
This loop runs continuously. It is not a one-time operation. This is what gives Kubernetes its self-healing property: if a container crashes and the actual state diverges from desired, the controller notices on the next loop iteration and restarts the container.
An analogy: a home thermostat is a reconciliation loop. The desired state is the temperature you set (22°C). The actual state is the current room temperature. The thermostat continuously observes, compares, and acts (turn heating on/off) to close the gap.
+-------------------+
| Desired State | <- stored in etcd
| (replicas: 3) |
+-------------------+
|
| compare
v
+-------------------+
| Actual State | <- observed from kubelet reports
| (2 Pods running) |
+-------------------+
|
| difference detected: 1 Pod missing
v
+-------------------+
| Controller Acts |
| (create 1 Pod) |
+-------------------+
|
+--------> Loop repeats (all 3 now running)
Level-triggered vs edge-triggered
Kubernetes controllers are level-triggered, not edge-triggered. This means they respond to the current state of the world (the level), not to the event that caused a change (the edge). If a controller misses an event (e.g., due to a crash), it still converges to correct state on the next loop because it always observes and responds to current reality. This makes the system robust to transient failures.
Example: Reconciliation in Practice
# Desired state: 3 replicas in the Deployment
kubectl apply -f deployment.yaml # replicas: 3
# Check actual state
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# api-7d9c-abc 1/1 Running 0 5m
# api-7d9c-def 1/1 Running 0 5m
# api-7d9c-ghi 1/1 Running 0 5m
# Simulate a failure: manually delete one Pod
kubectl delete pod api-7d9c-ghi
# Actual state is now: 2 Pods (diverged from desired: 3)
# The ReplicaSet controller's reconciliation loop detects this.
# Within seconds, it creates a replacement Pod.
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# api-7d9c-abc 1/1 Running 0 6m
# api-7d9c-def 1/1 Running 0 6m
# api-7d9c-jkl 0/1 ContainerCreating 0 2s <- new Pod
The operator did nothing after deleting the Pod. The reconciliation loop detected the drift and corrected it autonomously.
Exercises
- (Beginner) Describe the three steps of a Kubernetes reconciliation loop in your own words.
- (Beginner) If you manually delete a Pod that was created by a Deployment, what happens and why?
- (Intermediate) A Kubernetes cluster loses its connection to etcd for 30 seconds, then reconnects. During this 30 seconds, a node goes down, taking 2 Pods with it. Describe what happens during the outage and after connectivity is restored.
- (Interview) Explain the difference between "level-triggered" and "edge-triggered" systems. Why does Kubernetes use level-triggered reconciliation, and what resilience properties does this provide? (Hint: consider what happens when a controller crashes and restarts mid-operation.)
Answers
- A reconciliation loop: (1) Observes the current actual state of the cluster (e.g., how many Pods are running); (2) Compares it to the desired state stored in etcd (e.g., how many should be running); (3) Acts to close any gap (e.g., creates a new Pod if too few are running, or deletes a Pod if too many). This loop repeats continuously.
- When you delete a Pod that was created by a Deployment (via a ReplicaSet), the ReplicaSet controller's reconciliation loop detects that actual state (fewer Pods than declared) diverges from desired state (the
replicascount). It creates a new Pod to replace the deleted one. This is by design — Kubernetes treats Pod deletion as a signal that desired state is not met, not as a final instruction. If you truly want to scale down, you must reduce thereplicascount in the Deployment, not delete individual Pods.- During the 30-second outage: the controllers in the control plane cannot read from or write to etcd. They cannot process new reconciliation actions. The kubelets on worker nodes continue running existing containers (they cache their current Pod assignments locally). The scheduler cannot place new Pods. When the node goes down, the kubelet on that node stops sending heartbeats, but the control plane cannot yet record the node as
NotReadybecause it cannot write to etcd. After connectivity is restored: the controllers re-read etcd state. They observe the node's heartbeat has been missing and eventually mark itNotReady. The Pod eviction mechanism (controlled by the node lifecycle controller) detects Pods on the failed node. After a configurable eviction timeout (default 5 minutes fornode.kubernetes.io/unreachabletaint), it marks the Pods asTerminatingand the ReplicaSet controller creates replacement Pods on healthy nodes. The 30-second etcd outage delayed this process but did not prevent correct reconciliation — demonstrating level-triggered resilience.- An edge-triggered system responds to events (state transitions): "a Pod was deleted" triggers a create action. If the system misses the event (crashes before processing it), the action is never taken and the system is stuck in incorrect state. A level-triggered system responds to state (the current level of reality): "there are 2 Pods, but there should be 3" triggers a create action. It does not matter how the system got to that state or whether any events were missed — every time the loop runs, it observes current reality and acts. Kubernetes uses level-triggered reconciliation because: (a) if a controller crashes and restarts, it simply re-observes current state and acts on what it finds — it does not need to replay missed events; (b) if an action fails mid-execution, the loop will retry on the next iteration because the desired/actual gap still exists; (c) this makes the system robust against partial failures, network partitions, and controller restarts without needing event replay or persistent event queues. The resilience property is eventual consistency: regardless of intermediate failures, the cluster will eventually converge to desired state.