Skills101

Cloud & DevOps · Lesson 6 of 9 · Updated ·

Kubernetes Basics — Pods, Deployments, Services, Scaling and Self-Healing Explained

Docker runs containers on one machine. But production means many containers on many machines: who restarts a crashed container at 3 a.m., spreads them across servers, rolls out new versions without downtime, and adds more when traffic spikes? That's Kubernetes (often written K8s).

1. What Kubernetes does for you

You declare what you want — "run 3 copies of myapp:2.1, expose them on port 80" — and Kubernetes keeps reality matching that declaration forever:

  • Self-healing: a container crashes → it's restarted; a server dies → its containers are recreated elsewhere.
  • Scaling: change 3 to 10 (or let an autoscaler do it).
  • Rolling updates and rollbacks with no downtime.
  • Service discovery and load balancing between containers.
  • Config and secrets injected at runtime.

2. Architecture

Kubernetes architecture: the control plane (API server, scheduler, controller manager, etcd) manages worker nodes; each node runs a kubelet, kube-proxy and the pods that contain your containers

PartRole
API serverthe front door; kubectl and everything else talk to it
etcdthe cluster's database of desired and current state
Schedulerpicks which node a new pod runs on
Controller managercontrol loops that fix differences ("3 wanted, 2 running → start 1")
Nodea worker machine (VM)
kubeletagent on each node that starts and watches containers
kube-proxynetworking rules for Services

Managed services — EKS (AWS), AKS (Azure), GKE (Google) — run the control plane for you; you manage the workloads. For learning, run a local cluster with minikube or kind.

3. The core objects

ObjectWhat it is
Podthe smallest unit: one (or a few tightly coupled) containers with a shared IP
Deployment"keep N identical pods of this image running"; handles updates/rollbacks
ReplicaSetcreated by a Deployment to keep the pod count; you rarely touch it directly
Servicea stable name + IP that load-balances to matching pods (pods come and go)
IngressHTTP routing from outside (api.example.com/ → the API Service), usually with TLS
ConfigMap / Secretconfiguration and sensitive values, injected as env vars or files
Namespacea folder for objects (dev, staging, prod)

How the objects connect: an Ingress routes outside traffic to a Service, which load-balances across the pods that a Deployment keeps running, selected by matching labels

The glue is labels: the Deployment stamps pods with app: courses-api, and the Service sends traffic to every pod with that label.

4. A Deployment and a Service in YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: courses-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: courses-api
  template:
    metadata:
      labels:
        app: courses-api
    spec:
      containers:
        - name: api
          image: ghcr.io/skills101/courses-api:4f2c9e1
          ports:
            - containerPort: 3000
          envFrom:
            - configMapRef:
                name: courses-config
            - secretRef:
                name: courses-secrets
          resources:
            requests: { cpu: 100m, memory: 128Mi }
            limits: { cpu: 500m, memory: 256Mi }
          readinessProbe:
            httpGet: { path: /health, port: 3000 }
            periodSeconds: 5
          livenessProbe:
            httpGet: { path: /health, port: 3000 }
            initialDelaySeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: courses-api
spec:
  selector:
    app: courses-api
  ports:
    - port: 80
      targetPort: 3000
  • requests = what the scheduler reserves; limits = the maximum (a container over its memory limit is killed and restarted).
  • readinessProbe — "ready for traffic?" Pods failing it are removed from the Service (e.g. while warming up).
  • livenessProbe — "still alive?" Failing it restarts the container (e.g. stuck in a deadlock).
  • 100m CPU = 0.1 of a core.

Other pods can now call http://courses-api — the Service name is a DNS name inside the cluster.

5. kubectl: the commands you'll use

kubectl apply -f k8s/                     # create/update everything in the folder (declarative)
kubectl get pods -o wide                  # pods and which node they're on
kubectl get deploy,svc                    # deployments and services
kubectl describe pod courses-api-7d9c-x2  # events: why is it Pending/CrashLoopBackOff?
kubectl logs -f deploy/courses-api        # logs
kubectl exec -it courses-api-7d9c-x2 -- sh
kubectl scale deploy/courses-api --replicas=6
kubectl set image deploy/courses-api api=ghcr.io/skills101/courses-api:9a8b7c6
kubectl rollout status deploy/courses-api
kubectl rollout undo deploy/courses-api   # roll back to the previous version

Common pod states while debugging: Pending (no node has room / image pull waiting), ImagePullBackOff (wrong image name or no registry access), CrashLoopBackOff (the app keeps exiting — check logs), OOMKilled (memory limit too low or a leak).

6. Rolling updates and autoscaling

When the image changes, the Deployment starts new pods, waits until they're ready, then removes old ones — a few at a time — so there's no downtime. If the new pods never become ready, the rollout stops and you rollout undo.

A HorizontalPodAutoscaler adds or removes pods based on load:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: courses-api
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: courses-api
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60

When average CPU goes above 60% of the requested CPU, more pods are added (and nodes too, if a cluster autoscaler is set up).

7. Do you even need Kubernetes?

Kubernetes is powerful but complex. A single VPS with Docker Compose or a PaaS is often the right answer for a small product. Kubernetes pays off when you have many services, several teams, frequent deploys and real scaling needs. Interviewers like candidates who know this trade-off.

8. Case study: the 3 a.m. crash that nobody noticed

An exam-prep API had a memory leak that crashed a container every few hours. On a plain server, each crash meant downtime until someone restarted it. On Kubernetes with 3 replicas and a liveness probe, each crashed pod was restarted in seconds while the other two served traffic — users saw nothing. The team still fixed the leak (they saw the restarts in monitoring), but the system healed itself in the meantime.

Common mistakes

  • No readiness probe → traffic is sent to pods that aren't ready yet.
  • No resource requests/limits → one pod starves the node.
  • Secrets in plain ConfigMaps or in Git (Kubernetes Secrets are only base64-encoded; enable encryption at rest or use a secrets manager).
  • Using latest tags, so rollouts and rollbacks are unpredictable.
  • kubectl edit in production instead of changing YAML in Git and re-applying.

Quick recap

  • Kubernetes keeps the declared state: self-healing, scaling, rolling updates.
  • Control plane (API server, etcd, scheduler, controllers) + worker nodes (kubelet, kube-proxy, pods).
  • Pod < Deployment (replicas, updates) + Service (stable name, load balancing) + Ingress (HTTP from outside); labels connect them.
  • Use readiness/liveness probes, requests/limits, HPA; kubectl rollout undo to roll back.

Practice what you learned

📝 Quiz: Kubernetes Basics5 questions · instant answers & explanations · +10 XP · counts towards your free certificateTake the quiz →