Part 10 · Architecture & Deployment

Kubernetes Core Concepts

Running 300 containers across 40 machines by hand doesn't work. How Kubernetes turns “what I want” into “what's running”: the control plane and nodes, the reconciliation loop, pods, deployments, services and ingress, health probes, resources and autoscaling — and whether you need it at all.

Lesson 5612 min readintermediate#kubernetes#devops

On this page

  1. The Problem
  2. The Core Idea
  3. How It Works
  4. Trade-offs
  5. In the Real World
  6. Interview Questions
  7. Key Takeaways
  8. Further Reading

The Problem

You have put your services in containers (post 55). Now you have 30 services, each running 3–20 containers, across 15 servers. Someone has to do all of this work:

  • decide which server each container runs on, based on the free CPU and memory,
  • restart containers that crash, and move them when a server dies,
  • scale up at 7 PM (add more copies) and down at 3 AM (remove copies),
  • roll out new versions without downtime, and roll back (go back to the old version) when a new one is bad,
  • let services find each other as containers move around (post 54),
  • deliver config and secrets to the right containers,
  • route external traffic to the right services.

Doing this by hand with scripts and SSH does not scale. Kubernetes (often written as K8s) is an open-source platform that does all of this automatically. You describe what you want, and it makes it happen. This kind of work is called container orchestration: starting, stopping, placing and connecting many containers like a conductor leads an orchestra.

The Core Idea

Think about a very well organised shipping port.

  • You give the port authority your instructions: "Keep 5 containers of product A and 3 of product B available at all times, each with this much space."
  • The crane operators (the scheduler) decide which dock (a server) has room for each container.
  • Dock supervisors (kubelets) on each dock make sure their containers are actually there and working.
  • If a container is damaged, a new one is brought in. If a whole dock floods, its containers are moved to other docks.
  • Customers do not need to know which dock holds what. They go to the "Product A" counter, which always knows where the current containers are. In Kubernetes, this counter is called a Service.

Kubernetes is declarative. This means you describe the desired state (the result you want), for example "I want 5 replicas (copies) of this image, with this much CPU, reachable at this name". You do not write the steps. Kubernetes then keeps working to make reality match your description. The opposite style is imperative, where you give step-by-step commands.

How It Works

Key terms in plain words

  • Cluster: a group of machines that work together as one system.
  • Node: one machine (real or virtual) in the cluster. It runs your containers.
  • Pod: the smallest thing Kubernetes runs. It holds one or more containers that run together.
  • Replica: one copy of a pod. "5 replicas" means 5 identical copies.
  • Control plane: the part of Kubernetes that makes decisions. The nodes do the actual work.
  • YAML: a simple text format for settings, written as indented keys and values. You write your Kubernetes objects in YAML.
  • kubectl: the command-line tool you use to talk to a cluster.
  • Label and selector: a label is a key=value tag on an object (like app: orders-api). A selector is a rule that finds all objects with a given label.
  • Endpoints: the list of pod addresses that a Service currently sends traffic to. Only ready pods are on the list.
  • Stateless and stateful: a stateless app keeps no important data inside itself, so any copy can be replaced. A stateful app (like a database) keeps data that must not be lost.

Architecture: control plane and nodes

kube-apiserver
the front door — kubectl, controllers and kubelets all talk only to it
etcd
the cluster's database — desired and current state (a Raft-replicated CP store)
kube-scheduler
placement — picks a node for each new pod
controller-manager
control loops — Deployments, ReplicaSets, nodes, jobs
Worker nodes × N
kubelet · kube-proxy / CNI · container runtime — run the pods
A Kubernetes cluster: one control plane deciding, many nodes doing. · layers

The control plane (the brain):

  • kube-apiserver: the front door. Every change goes through its API (a set of web requests that tools can call).
  • etcd: a small database that stores data as key-value pairs. It keeps copies on several machines and uses the Raft algorithm (post 24), a method that lets several machines vote and agree on one value, so the copies always agree. It holds all cluster state. Back it up.
  • kube-scheduler: chooses a node for each new pod. It looks at the resources the pod asks for, any placement rules, and how to spread pods out.
  • controller-manager: runs many controllers. A controller is a loop that watches the state and fixes any difference from what you asked for.

Worker nodes (the muscle):

  • kubelet: a small program (an agent) on each node. It starts and stops containers and reports their status to the control plane.
  • Container runtime: the program that actually runs the containers, such as containerd or CRI-O. It runs OCI images (post 55).
  • kube-proxy / CNI network plugin: these set up the network between pods and send Service traffic to the right pod. (CNI means Container Network Interface.)

Managed services (Amazon EKS, Google GKE, Azure AKS and others) run the control plane for you. Most teams use one of these instead of running the control plane themselves.

The reconciliation loop

This loop is the main idea of Kubernetes. A "loop" here is a job that repeats forever:

  1. 1
    Observe current state
    3 pods running
  2. 2
    Compare with desired state
    the Deployment says 5
  3. 3
    Act to close the gap
    create 2 pods
  4. 4
    Repeat forever
    a node dies → its pods are re-created elsewhere automatically
The reconciliation loop — the one idea behind everything Kubernetes does. · flow

Every controller does this, over and over. Say a node dies and 2 pods disappear. The Deployment's controller sees "desired 5, current 3" and creates 2 new pods on other nodes. You do not write the recovery steps. You only state the goal.

Core objects

Pod

A pod is the smallest unit you can deploy. It is one or more containers that share one network address (IP) and can share storage volumes.

  • Usually there is one main container per pod. Sometimes there are also sidecars: helper containers that run next to the main one, such as a logging agent or a service-mesh proxy (post 54).
  • Pods are disposable. They are replaced, not repaired, and each new pod gets a new IP. Never depend on one specific pod.

Deployment (and ReplicaSet)

A Deployment is the most common way to run stateless apps. It says "run N copies of this pod template, and update them safely". (A pod template is the blueprint for the pods.)

YAML
apiVersion: apps/v1kind: Deploymentmetadata:  name: orders-apispec:  replicas: 3  selector:    matchLabels: { app: orders-api }  strategy:    type: RollingUpdate    rollingUpdate: { maxUnavailable: 0, maxSurge: 1 }   # no downtime during the update  template:    metadata:      labels: { app: orders-api }    spec:      containers:        - name: api          image: myshop/orders-api:1.4.2          ports: [{ containerPort: 3000 }]          envFrom:            - configMapRef: { name: orders-config }            - secretRef:    { name: orders-secrets }          resources:            requests: { cpu: "250m", memory: "256Mi" }            limits:   { memory: "512Mi" }          readinessProbe:            httpGet: { path: /ready, port: 3000 }            periodSeconds: 5          livenessProbe:            httpGet: { path: /healthz, port: 3000 }            initialDelaySeconds: 10            periodSeconds: 10

The Deployment manages ReplicaSets. A ReplicaSet keeps the right number of pods running. Say you change the image to 1.4.3. The Deployment then does a rolling update: it starts new pods and stops old ones a little at a time, so the app stays up. In the example above, maxUnavailable: 0 and maxSurge: 1 mean that no pod may be missing, and at most one extra pod may exist during the update. The command kubectl rollout undo goes back to the previous version.

Other workload types

  • StatefulSet: for stateful apps (databases, Kafka, which passes streams of messages between programs, or ZooKeeper, a coordination service). Its pods get fixed names (db-0, db-1), their own storage that stays with them, and they start and stop in a set order.
  • DaemonSet: runs one pod on every node. It is used for log collectors, monitoring agents and network plugins.
  • Job: runs pods until the work is finished, then stops. Examples are a database migration or a batch import.
  • CronJob: runs Jobs on a schedule, like "every night at 2 AM" (post 38).

Service: a stable address for changing pods

Pods come and go, so their IPs keep changing. A Service fixes this. It gives a set of pods (chosen by labels) one stable name and virtual IP. It also load-balances (shares) the traffic between the pods that are ready (post 54):

YAML
apiVersion: v1kind: Servicemetadata:  name: orders-apispec:  selector: { app: orders-api }  ports: [{ port: 80, targetPort: 3000 }]  type: ClusterIP

Other pods can now call http://orders-api. The cluster DNS (the name lookup service) turns that name into the Service IP.

Service types:

  • ClusterIP (the default): reachable inside the cluster only.
  • NodePort: opens the same port on every node. It is rarely used directly.
  • LoadBalancer: asks the cloud provider to create an external load balancer (a machine that spreads incoming traffic, post 12).
  • Headless (clusterIP: None): has no single virtual IP. DNS returns the IPs of the individual pods. It is often used with StatefulSets.

Ingress and Gateway API: HTTP traffic from outside

An Ingress routes web traffic (HTTP and HTTPS) from outside the cluster to Services. It chooses the Service by host name and path, and it can handle TLS (the encryption for HTTPS). The Gateway API is the newer and more powerful design for the same job. The Kubernetes project now adds new features only to the Gateway API, and the Ingress API is frozen. An Ingress controller (NGINX, Traefik, Envoy-based gateways or cloud load balancers) is the program that does the actual work. It is an L7 load balancer and reverse proxy (posts 12–13) that Kubernetes manages. "L7" means it understands HTTP. A reverse proxy is a server that receives requests for your servers and passes them on.

  1. 1
    Internet
  2. 2
    Ingress / Gateway
    TLS and host/path routing
  3. 3
    Service orders-api
    a stable virtual IP and DNS name
  4. 4
    orders-api pods × 3
How outside traffic reaches pods. · flow

ConfigMap and Secret

  • ConfigMap: settings that are not secret (feature settings, URLs). They are given to the container as environment variables or files.
  • Secret: sensitive values such as passwords. ⚠️ By default they are only base64-encoded. Base64 is a way to write data as text. It is not encryption, and anyone can decode it. So turn on encryption at rest for etcd (data is encrypted on disk), limit access with RBAC (rules about who may do what), and think about syncing secrets from an external secrets manager (post 51).

Namespaces

Namespaces divide one cluster into virtual sections (for example payments, search and staging). Each section has its own resources, access rules (RBAC) and quotas (limits). They are useful for separating teams and environments. But on their own they are not a strong security wall. Add NetworkPolicies and RBAC.

Health checks: liveness, readiness, startup

A probe is a check that Kubernetes runs on a container again and again, for example by calling a URL such as /healthz. The answer decides what Kubernetes does next. There are three kinds.

Liveness
  • •“Is this container stuck?”
  • −Failing → the container is restarted
Use whenDeadlocks, unrecoverable states
Readiness
  • •“Should this pod get traffic right now?”
  • −Failing → removed from Service endpoints, not restarted
Use whenWarm-up, dependency blips, draining
Startup
  • •“Has a slow-starting app finished booting?”
  • +Holds the other probes off until it passes
Use whenJava (JVM) apps and others with a long start-up
Three probes, three different questions. · compare
ProbeQuestionIf it fails…
Readiness"Can this pod handle traffic right now?"Removed from Service endpoints (no traffic), not restarted
Liveness"Is this pod stuck or broken?"Restarted
Startup"Has the app finished starting?"Liveness and readiness checks wait until it succeeds

Common mistake: making the liveness probe check the database. If the database has a short problem, every pod restarts at once. This makes the outage much worse. Liveness should only check "is this process healthy?". Use readiness, with care, for temporary "not ready" states (post 12).

Resources, scheduling and scaling

Requests and limits:

  • Requests: the amount of CPU and memory the pod is guaranteed. The scheduler uses it to choose a node for the pod.
  • Limits: the most the pod may use. If it goes over the memory limit, the container is killed ("OOMKilled", where OOM means out of memory). If it reaches the CPU limit, it is slowed down (this is called throttling). In the example, 250m means 250 millicores, which is a quarter of one CPU core.
  • Setting requests correctly matters for both reliability and cost.

Scaling:

  • Horizontal Pod Autoscaler (HPA): adds or removes pods automatically. It looks at CPU, memory or custom metrics (like requests per second or queue length). "Horizontal" means more copies, not bigger ones:
YAML
apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: { name: orders-api }spec:  scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: orders-api }  minReplicas: 3  maxReplicas: 30  metrics:    - type: Resource      resource: { name: cpu, target: { type: Utilization, averageUtilization: 65 } }
  • Vertical Pod Autoscaler (VPA): changes a pod's requests and limits based on what it really uses. "Vertical" means a bigger pod, not more pods.
  • Cluster Autoscaler / Karpenter: tools that add or remove nodes. They add nodes when pods cannot be placed, and remove nodes that are barely used.
  • Event-driven autoscaling (KEDA): a tool that scales based on events, such as queue length or Kafka lag (how far a consumer is behind). It can even scale down to zero pods.

Spreading for availability: use topology spread constraints or pod anti-affinity (rules that keep pods apart) to spread replicas across nodes and availability zones. An availability zone is one or more separate data centres inside one region, with their own power and network. This way, one failure does not take out every replica (post 40). A PodDisruptionBudget limits how many replicas planned maintenance may remove (evict) at the same time. Bin-packing means fitting many pods tightly onto few nodes to save money.

Storage

  • Volumes attach storage to pods. A plain volume may disappear with the pod.
  • PersistentVolume (PV): a piece of storage that lives on after the pod is gone (like a cloud disk).
  • PersistentVolumeClaim (PVC): a pod's request for storage ("I need 50 GB of fast SSD").
  • StorageClass: defines types of storage and creates volumes on demand.

You can run databases on Kubernetes, often with operators (explained below). But many teams choose managed databases outside the cluster because they are simpler.

Security basics

  • RBAC (role-based access control) decides who can do what through the API. "Who" can be people or service accounts (identities for programs).
  • NetworkPolicies control which pods may talk to which. By default, every pod can talk to every other pod.
  • Pod security: run as non-root, with a read-only root file system and only the Linux capabilities you need (post 55).
  • Admission policies (tools like Kyverno or OPA Gatekeeper) check every new object and reject unsafe ones.
  • Keep the cluster and nodes patched, and scan images.

The ecosystem

  • Helm: a package manager for Kubernetes (like npm for your cluster). It bundles YAML files into reusable, configurable packages called "charts".
  • Kustomize: keeps one base set of YAML and adds small changes on top for each environment (it is built into kubectl).
  • Operators: controllers that contain expert knowledge about running complex software ("how to run PostgreSQL or Kafka"). They add new object types to Kubernetes with Custom Resource Definitions (CRDs).
  • GitOps (Argo CD, Flux): you keep the desired state in Git, and a controller keeps the cluster the same as the repository (post 58).
  • Service meshes (Istio, Linkerd): a layer of helper proxies that gives services mTLS (both sides prove who they are and encrypt the traffic), traffic control and observability (the ability to see what is happening) between services (posts 51 and 54).

Do you need Kubernetes?

Kubernetes is powerful, but it is complex. It is a good fit when you have:

  • many services and teams,
  • a need for portability across clouds or on-premises,
  • a platform team to run it,
  • workloads that benefit from bin-packing, auto-scaling and self-healing (automatic restart and replacement of failed parts).

It may not be a good fit (yet) when you have:

  • a small app or small team,
  • or a simpler managed platform (a PaaS, serverless, or a managed container service like AWS ECS/Fargate or Google Cloud Run) that would do the job with far less work to run it (post 57).

Trade-offs

  • ✅ Self-healing, automated rollouts and rollbacks, auto-scaling, service discovery, config management, and efficient bin-packing of workloads onto servers.
  • ✅ Declarative and portable: the same concepts work across clouds and on-premises, with a huge ecosystem.
  • ❌ Complexity: there are many concepts, a lot of YAML, and hard topics like networking, security and upgrades. It takes real time to learn (a steep learning curve).
  • ❌ Operational cost: even with managed control planes, someone must manage nodes, add-ons, upgrades, security and cost.
  • ❌ Easy to set up wrongly: wrong probes, missing resource requests, no PodDisruptionBudgets, network policies that are too open.
  • ❌ Stateful workloads need extra care (StatefulSets, operators, backups).

In the Real World

From Borg to Kubernetes. Google ran its services for years on Borg, an internal cluster manager, and later on Omega. Engineers who worked on them created Kubernetes. Google made it open source in 2014 and released version 1.0 in 2015. At that time it was given to the newly formed Cloud Native Computing Foundation. The paper "Borg, Omega, and Kubernetes" explains the lessons that were carried over.

Pokémon GO (2016). Pokémon GO ran on Google Kubernetes Engine at launch. Google said that traffic reached many times the worst case they had planned for, within days. The game scaled up quickly on the platform. It is a famous example of Kubernetes scaling during a sudden, unexpected spike.

Spotify's migration. Spotify had built its own container orchestration tool (Helios). Later it moved to Kubernetes to use the larger community and tools around it, instead of keeping its own system.

Stripe and Kubernetes. Stripe has written about how it learned to run Kubernetes reliably. It tested a lot, adopted it step by step, and built trust before moving critical workloads. This shows that adopting Kubernetes is a long process, not a single switch.

Kubernetes everywhere. Today, Kubernetes runs in every major cloud (EKS, GKE, AKS), in company data centres, and even on edge devices (small machines near the user) and in retail stores. It has become the common "operating system" for containerised workloads.

Interview Questions

Q1What problem does Kubernetes solve?

It runs many containers across many machines in a reliable way. It places containers on nodes, restarts failed ones, replaces lost nodes, rolls out new versions with no downtime, finds and balances services, handles config and secrets, and scales automatically. All of this is driven by a declared desired state.

Q2What is the reconciliation loop?

Controllers keep comparing the desired state (stored through the API server in etcd) with the actual state. When they differ, they act to close the gap by creating, deleting or updating pods. This is why Kubernetes heals itself: the pods of a dead node are simply created again on another node.

Q3Pod, Deployment, Service — what's the difference?

A pod is the smallest unit. It is one or more closely linked containers that share one network namespace (the same IP). A Deployment manages a set of identical pods and rolls out new versions. A Service gives a stable name and virtual IP, and it shares traffic between the ready pods that match a label selector.

Q4Liveness vs readiness probes?

Readiness decides whether a pod gets traffic. If it fails, the pod is taken out of the Service endpoints, but it is not restarted. Liveness decides whether the container is stuck. If it fails, the container is restarted. Do not make liveness depend on outside services. If it does, one short database problem can restart everything.

Q5What are resource requests and limits?

Requests are what the scheduler reserves when it places a pod. Limits cap what the pod may use. A container that reaches its CPU limit is slowed down (throttled). A container that goes over its memory limit is killed (OOM-killed). Set requests from real usage, and always set memory limits.

Q6Does every team need Kubernetes?

No. It adds a lot of work to run and understand. Small teams are often better served by a PaaS, serverless or a managed container service. Kubernetes pays off when you have many services, several teams and a platform team. A managed offering like EKS, GKE or AKS also helps.

Key Takeaways

  • Kubernetes orchestrates containers across many machines using a declarative desired state and reconciliation loops.
  • The control plane (API server, etcd, scheduler, controllers) decides. Nodes (kubelet, runtime) run pods.
  • Core objects:
    • Pods (disposable units),
    • Deployments (stateless apps, rolling updates),
    • StatefulSets / DaemonSets / Jobs / CronJobs,
    • Services (stable names), Ingress / Gateway API (external HTTP),
    • ConfigMaps / Secrets, Namespaces.
  • Use readiness vs liveness probes correctly, set resource requests and limits, and spread replicas across zones with PodDisruptionBudgets.
  • Scale with HPA / VPA / cluster autoscaling, extend with Helm, operators and GitOps, and weigh Kubernetes' power against its complexity. Simpler platforms may be enough.

Further Reading

  • The official Kubernetes documentation: "Concepts"
  • The paper "Large-scale cluster management at Google with Borg" (EuroSys 2015)
  • The article "Borg, Omega, and Kubernetes" by Burns, Grant, Oppenheimer, Brewer and Wilkes (ACM Queue, 2016)
  • Kubernetes: Up and Running (3rd edition) by Brendan Burns, Joe Beda, Kelsey Hightower and Lachlan Evenson
  • "Kubernetes The Hard Way" by Kelsey Hightower (on GitHub)
  • Stripe's engineering blog post on operating Kubernetes reliably

Published by Jainik · Last updated · How these lessons are made

Keep learning

Part of the study guide

Related series