How Kubernetes works. DotA style
🌋 Echo Slam into Kubernetes: Learn K8s with familiarity
If you've ever watched the legendary $5 million Echo Slam at The International 5, you know how satisfying it is to see Earthshaker obliterate five enemy heroes in one glorious cast.
Now imagine bringing that kind of satisfaction into learning Kubernetes.
This project is all about teaching Kubernetes fundamentals through the lens of a Dota 2 battle.
I find it much easier to learn concepts when I have something familiar to relate it to, hence why I made this simple post.
🎯 1. Namespace: dota-battle
Kubernetes concept: A namespace isolates a group of resources.
Dota analogy: This is the battlefield — where Radiant and Dire clash.
All our heroes, creeps, and Jobs live in this arena. It's clean, isolated, and epic.
namespace.yaml -->
apiVersion: v1
kind: Namespace
metadata:
name: dota-battle
💪 2. Pod: Earthshaker
Kubernetes concept: A Pod runs a single container (or tightly coupled set).
Dota analogy: Earthshaker is one unit. He doesn’t scale. He waits for the slam.
In our cluster, he’s a pod that just idles — until the slam is triggered.
earthshaker.yaml -->
apiVersion: v1
kind: Pod
metadata:
name: earthshaker
namespace: dota-battle
labels:
hero: earthshaker
spec:
containers:
- name: earthshaker
image: busybox
command: ["sh", "-c", "echo 'Earthshaker is waiting...'; sleep 3600"]
🌊 3. Job: Creep Wave
Kubernetes concept: A Job runs one or more pods to completion.
Dota analogy: A wave of creeps spawning together.
We spawn 5 creep pods at once, all labeled
team=enemy
. They wait around like a ripe Echo Slam setup.
creepwave.yaml -->
apiVersion: batch/v1
kind: Job
metadata:
name: creepwave
namespace: dota-battle
spec:
completions: 5
parallelism: 5
template:
metadata:
labels:
team: enemy
spec:
containers:
- name: creep
image: busybox
command: ["sh", "-c", "echo 'Creep spawned!'; sleep 300"]
restartPolicy: Never
🧟 4. Pods: Enemy Heroes
Kubernetes concept: Same as Earthshaker, a pod per hero.
Dota analogy: These are Winter Wyvern, Clockwerk, Lina, Dragon Knight, and Phantom Lancer.
Labeled like creeps but with
hero: name
. Still squishy. Still slam-able.
enemyheroes.yaml -->
apiVersion: v1
kind: Pod
metadata:
name: winterwyvern
namespace: dota-battle
labels:
hero: winterwyvern
team: enemy
spec:
containers:
- name: winterwyvern
image: busybox
command: ["sh", "-c", "echo 'Winter Wyvern has entered the fight'; sleep 600"]
---
apiVersion: v1
kind: Pod
metadata:
name: clockwerk
namespace: dota-battle
labels:
hero: clockwerk
team: enemy
spec:
containers:
- name: clockwerk
image: busybox
command: ["sh", "-c", "echo 'Clockwerk has entered the fight'; sleep 600"]
---
apiVersion: v1
kind: Pod
metadata:
name: lina
namespace: dota-battle
labels:
hero: lina
team: enemy
spec:
containers:
- name: lina
image: busybox
command: ["sh", "-c", "echo 'Lina has entered the fight'; sleep 600"]
---
apiVersion: v1
kind: Pod
metadata:
name: dragonknight
namespace: dota-battle
labels:
hero: dragonknight
team: enemy
spec:
containers:
- name: dragonknight
image: busybox
command: ["sh", "-c", "echo 'Dragon Knight has entered the fight'; sleep 600"]
---
apiVersion: v1
kind: Pod
metadata:
name: phantomlancer
namespace: dota-battle
labels:
hero: phantomlancer
team: enemy
spec:
containers:
- name: phantomlancer
image: busybox
command: ["sh", "-c", "echo 'Phantom Lancer has entered the fight'; sleep 600"]
🛡️ 5. ServiceAccount + RBAC: Echo Controller
Kubernetes concept: A ServiceAccount is a pod's identity. RBAC tells it what it can do.
Dota analogy: Earthshaker needs permission from the game server to slam.
We grant permissions to list and delete enemy pods — otherwise the slam fails.
echo-slam-controller-rbac.yaml -->
apiVersion: v1
kind: ServiceAccount
metadata:
name: echo-controller
namespace: dota-battle
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: echo-slam-role
namespace: dota-battle
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: echo-slam-binding
namespace: dota-battle
subjects:
- kind: ServiceAccount
name: echo-controller
namespace: dota-battle
roleRef:
kind: Role
name: echo-slam-role
apiGroup: rbac.authorization.k8s.io
💥 6. Job: Echo Slam
Kubernetes concept: A Job with logic.
Dota analogy: Earthshaker’s ultimate.
The container does 3 things:
- Lists pods labeled
team=enemy
- Deletes them (💀)
- Logs slam messages
Jobs are immutable, so to slam again, we delete and reapply.
echo-slam-job.yaml -->
apiVersion: batch/v1
kind: Job
metadata:
name: echo-slam
namespace: dota-battle
spec:
template:
spec:
serviceAccountName: echo-controller
containers:
- name: earthshaker-slam
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
echo "Detecting enemies..."
kubectl get pods -n dota-battle -l team=enemy
echo "Executing slam...";
echo "🌋 Earthshaker casts ECHO SLAM!!!";
kubectl delete pods -n dota-battle -l team=enemy
echo "💥 Slam complete."
restartPolicy: Never
backoffLimit: 1
Want to replay the Slam?
🧪 Putting It All Together
✅ Step 1: Reapply creeps and enemy heroes
Apply the YAML to spawn a new wave of enemies.
kubectl apply -f creepwave.yaml
kubectl apply -f enemy-heroes.yaml
This recreates the creeps and five enemy heroes that Earthshaker will destroy.
🧼 Step 2: Delete the previous Echo Slam job
Jobs in Kubernetes are immutable, so we need to delete the previous one before recreating it.
kubectl delete job echo-slam -n dota-battle --ignore-not-found
This clears the battlefield for a new slam.
💥 Step 3: Cast the Slam again!
Trigger Earthshaker's ult by applying the Echo Slam Job again:
kubectl apply -f echo-slam-job.yaml
This job runs a container that:
- Lists all enemy pods
- Deletes them
- Logs an epic slam message
🎬 Step 4: Watch Earthshaker’s moment of glory
Check the logs to relive the Slam:
kubectl logs job/echo-slam -n dota-battle
You’ll see output like:
🌋 Earthshaker casts ECHO SLAM!!!
Detecting enemies...
Executing slam...
💥 Slam complete.
Enemies are gone. Echo Slam was successful. GG.
Output