Kubernetes and Helm
Kubernetes Playground in your browser
K3d for local practice
Headlamp for Kubernetes UI
Core Building Blocks
Cluster — The overall system, made up of a control plane and worker nodes.
Node — A physical or virtual machine in the cluster. There are two types: the control plane node (manages the cluster) and worker nodes (run your workloads).
Pod — The smallest deployable unit in K8s. A pod wraps one or more containers that share networking and storage.
What is kubelet?
kubelet is an agent process that runs on every worker node. Its job is to be the local manager for that node — it talks to the API server and makes sure the containers described in pod specs are actually running and healthy on its node.
Think of it this way: the API server is like a central commander issuing orders, and the kubelet on each node is the local soldier carrying them out. When the scheduler decides "Pod X should run on Node 2," it's the kubelet on Node 2 that actually pulls the container image and starts it.
A few key things kubelet does:
Watches the API server for pods assigned to its node
Tells the container runtime (like
containerdor Docker) to start/stop containersReports the node's health and pod status back to the control plane
Runs liveness and readiness probes to check if containers are healthy
It's worth noting that kubelet is one of the few Kubernetes components that is not itself containerized — it runs as a native system process on the node, because it needs to be running before any containers can be started.
Workload Resources
Deployment — Manages a set of identical pods, handles rolling updates and rollbacks.
ReplicaSet — Ensures a specified number of pod replicas are running at all times (usually managed by a Deployment).
StatefulSet — Like a Deployment but for stateful apps (databases, etc.) — preserves pod identity and storage.
DaemonSet — Runs a copy of a pod on every node (e.g., for logging or monitoring agents).
Job / CronJob — Runs pods to completion; CronJob does it on a schedule.
Networking
Service — A stable network endpoint to expose pods. Types include ClusterIP, NodePort, and LoadBalancer.
Ingress — Manages external HTTP/HTTPS access to services, often with routing rules.
DNS — K8s has built-in DNS so services can find each other by name.
Configuration & Storage
ConfigMap — Stores non-sensitive configuration data as key-value pairs.
Secret — Stores sensitive data (passwords, tokens) in base64-encoded form.
PersistentVolume (PV) / PersistentVolumeClaim (PVC) — PV is a piece of storage provisioned in the cluster; PVC is a request for that storage by a pod.
Scheduling & Organization
Namespace — Virtual clusters within a cluster, used to isolate resources by team or environment.
Labels & Selectors — Key-value tags on objects used to organize and select resources.
Taints & Tolerations — Control which pods can be scheduled on which nodes.
Affinity / Anti-affinity — Rules to attract or repel pods from certain nodes.
Control Plane Components
API Server — The front door to the cluster; all kubectl commands go here.
etcd — The distributed key-value store that holds all cluster state.
Scheduler — Assigns pods to nodes based on resource availability and constraints.
Controller Manager — Runs controllers that reconcile desired state with actual state.
Here are 6 diagrams covering the full picture:
Cluster Architecture — Control plane components (API server, etcd, scheduler, controller manager) and their relationship to worker nodes and pods
Workload Resources — How Deployments → ReplicaSets → Pods relate, plus StatefulSets, DaemonSets, Jobs, and CronJobs
Networking & Traffic Flow — Sequence diagram showing a request traveling from the Internet → LoadBalancer → Ingress → Service → Pods
Configuration & Storage — How ConfigMaps, Secrets, PVs, and PVCs are consumed by pods
Scheduling — How labels, taints/tolerations, and affinity rules decide which pod lands on which node
Helm — How a single Chart + different value files produces different releases per environment
Key CLI Tool
kubectl is the command-line tool you use to interact with your cluster — deploying apps, inspecting resources, viewing logs, etc.
Mapping Docker concepts to Kubernetes (i.e. comparing the 2)
This is one of the most practical mental shifts when moving to Kubernetes.
The Core Idea
Docker Compose and Kubernetes are solving the same problem — "run my multi-container app" — but at different scales and with different philosophies.
In Compose, you describe everything in one file and it runs on one machine. In Kubernetes, you describe everything in multiple files and it runs across a cluster of machines.
The Conceptual Mapping
docker-compose.yml
Multiple YAML manifests (or a Helm chart)
service: block
Deployment + Service (two separate objects)
image:
Same — container image reference inside a Pod spec
ports:
Service (ClusterIP, NodePort, or LoadBalancer)
environment:
ConfigMap or Secret
volumes:
PersistentVolume + PersistentVolumeClaim
networks:
Handled automatically by K8s networking
depends_on:
No direct equivalent — apps must handle retries
replicas: (in Swarm)
replicas: in a Deployment spec
A Concrete Example
Say you have a simple web app + database in Compose:
In Kubernetes, this single file splits into roughly 5 objects:
1. Deployment for the web app (defines the pod template, image, replicas)
2. Service for the web app (exposes it — internally or externally via LoadBalancer)
3. Deployment for postgres (or more properly, a StatefulSet)
4. Service for postgres (so the web app can reach it by DNS name)
5. PersistentVolumeClaim for the postgres data volume
Plus a Secret for DB_PASS and a ConfigMap for DB_HOST — rather than hardcoding them in the manifest.
The Biggest Mindset Shifts
Services are split in two. In Compose, one service: block covers both "what runs" and "how it's reached." In K8s, a Deployment handles "what runs" and a Service handles "how it's reached." They're separate objects linked by label selectors.
Networking is automatic. In Compose you define networks explicitly. In K8s, every pod can reach every other pod by default, and services get a DNS name automatically (e.g. postgres-service.default.svc.cluster.local, or just postgres-service within the same namespace).
depends_on doesn't exist. Compose can wait for a container to start before starting another. Kubernetes has no such guarantee — it just keeps restarting crashing pods until dependencies are ready. Your app needs to handle connection retries gracefully.
Volumes are first-class infrastructure. A Compose volume is just a named Docker volume on the host. A K8s PVC is a formal request for storage that could be backed by cloud storage, NFS, or anything else — it's decoupled from the pod.
Scaling is built in. In Compose you'd run docker compose up --scale web=3. In K8s you just set replicas: 3 in your Deployment, or use an autoscaler, and K8s spreads those pods across nodes automatically.
Tools That Help
Kompose is an official tool that literally converts a docker-compose.yml into Kubernetes manifests automatically. It's a great way to see the transformation in practice — though the output usually needs some cleanup before being production-ready.
The output of kompose convert on the example above would give you exactly those 5+ YAML files, ready to apply with kubectl apply -f.
Mapping Docker concepts to Kubernetes: Visualization
7 diagrams covering every key transformation:
One Machine vs. A Cluster — the fundamental runtime difference
Concept-by-Concept Mapping — every Compose field and its K8s counterpart (including the dead-end
depends_on)The Service Split — the most important difference: one Compose block → Deployment + Service linked by labels
Full App Transformation — a 2-service Compose file expanding into 6+ K8s objects
Networking — explicit named networks vs. automatic DNS-based service discovery
depends_on → Retry Logic — sequence diagram showing the CrashLoopBackOff dance K8s does instead
Kompose — the automated conversion tool and what manual cleanup still remains afterward
Video explainer about Kubernetes
Last updated