DevOps Tutorial · Containers and Kubernetes · Lesson 19 of 25
Kubernetes Basics
Pods, Deployments, Services and the declarative reconciliation loop that makes Kubernetes self-healing.
What Kubernetes does
Kubernetes runs containers across a cluster of machines. You declare the desired state ("3 replicas of api:1.4"), and controllers continuously compare it with the actual state and fix differences: restarting crashed containers, rescheduling pods from failed nodes, rolling out new versions.
desired = {"api": 3, "worker": 2}
actual = {"api": ["api-a", "api-b"], "worker": ["worker-a", "worker-b", "worker-c"]}
def reconcile():
for app, want in desired.items():
pods = actual[app]
if len(pods) < want:
new = f"{app}-{chr(ord('a') + len(pods))}"
pods.append(new)
print(f"{app}: {len(pods) - 1}/{want} -> start {new}")
elif len(pods) > want:
print(f"{app}: {len(pods)}/{want} -> stop {pods.pop()}")
else:
print(f"{app}: {want}/{want} ok")
reconcile()
actual["api"].remove("api-b") # a node fails
print("node lost api-b")
reconcile()
Output
api: 2/3 -> start api-c worker: 3/2 -> stop worker-c node lost api-b api: 2/3 -> start api-c worker: 2/2 ok
Core objects
| Object | Purpose |
|---|---|
| Pod | One or more containers scheduled together; the unit Kubernetes runs |
| Deployment | Keeps N identical pods running; handles rolling updates |
| Service | A stable name and virtual IP that load-balances to matching pods |
| Ingress / Gateway | HTTP routing from outside the cluster to Services |
| ConfigMap / Secret | Configuration and sensitive values for pods |
| Namespace | A scope for names, quotas and access control |
apiVersion: apps/v1
kind: Deployment
metadata: { name: api }
spec:
replicas: 3
selector: { matchLabels: { app: api } }
template:
metadata: { labels: { app: api } }
spec:
containers:
- name: api
image: ghcr.io/acme/api:3f9c2a1 # deploy by commit SHA
ports: [{ containerPort: 8080 }]
resources:
requests: { cpu: 250m, memory: 256Mi }
limits: { memory: 512Mi }
readinessProbe: { httpGet: { path: /readyz, port: 8080 } }
---
apiVersion: v1
kind: Service
metadata: { name: api }
spec:
selector: { app: api }
ports: [{ port: 80, targetPort: 8080 }]
kubectl apply -f api.yaml
kubectl get pods -l app=api
kubectl describe pod api-7c9d... # events: scheduling, probes, OOMKilled
kubectl logs deploy/api -f
kubectl rollout undo deploy/api # back to the previous version
Managed Kubernetes services: Amazon EKS, Azure AKS and Google GKE run the control plane for you.
Test yourself
A pod managed by a Deployment is deleted. What happens?
The Deployment's controller creates a replacement to restore the desired replica countNothing until someone redeploysThe whole Deployment is deletedThe Service stops working permanently
Show answer
Answer: The Deployment's controller creates a replacement to restore the desired replica count
Controllers reconcile actual state to desired state continuously.