๐ณโธ๏ธ Docker and Kubernetes - The Complete Guide

From zero to hero, explained as if teaching a small child โ with simple examples and diagrams. 18 lessons โ Docker (1โ8), Kubernetes (9โ18).
๐ Table of Contents
Part 1 โ Docker
- What is Docker? + Image vs Container
- Installing it and running your first container
- Basic commands
- Docker Hub โ where to find images
- Dockerfile โ building your own image
- Volumes โ keeping your data safe
- Ports & Networking
- Docker Compose
Part 2 โ Kubernetes 9. Why do we need Kubernetes? 10. Cluster, Nodes & Control Plane 11. Pods 12. Deployments 13. Services 14. ConfigMaps & Secrets 15. Namespaces 16. Volumes & Persistent Storage 17. Ingress 18. Everything together โ a real app
๐ณ Part 1 โ Docker
Lesson 1
What is Docker? + Image vs Container
The problem
A programmer builds an app on their own computer. On their machine it works perfectly. But when it's put on a different computer, it doesn't work. There's a famous phrase for this:
"But it works on my machine!"
The reason: every computer has a different environment (libraries, settings, versions). It's like cooking a chicken curry โ if one house has a different cooker and different ingredients than another, the curry won't turn out the same way.
The solution โ Docker
Docker is a tool that lets you pack your app and everything it needs (code, libraries, settings, environment) into one box. That box is called a container. Take that box to any computer, and it works exactly the same everywhere.
flowchart TB
subgraph without["โ Without Docker"]
A["Developer laptop<br/>App works"] -->|"move to server"| B["Different server<br/>App breaks ๐ฅ"]
B -.-> C["'works on my machine!'"]
end
subgraph with["โ
With Docker"]
D["Container<br/>App + everything packed"] --> E["Laptop โ
"]
D --> F["Server โ
"]
G["Friend's PC โ
"]
D --> G
end
The 2 most important words
| Image | Container | |
|---|---|---|
| What is it? | The recipe / blueprint | The real, running app |
| State | Read-only | Alive, running |
| Example | The cake recipe card | The cake you baked |
| How many | 1 | You can make many from it |
Golden rule: Image โ (run) โ Container
Lesson 2
Installing it and running your first container
Docker Engine
Docker Engine is the "engine" that creates, runs, and manages containers โ like a chef who cooks for the containers. You need to install it on your computer.
- Windows / Mac: download and install the
Docker Desktopapp (docker.com) - Linux: install
Docker Enginewith a few commands
Check that it installed:
docker --version
Your first container
docker run hello-world
Here's what happens behind the scenes with that one command:
flowchart TB
A["You: docker run hello-world"] --> B["Docker Engine: do I already have the image?"]
B -->|"if not"| C["Download from Docker Hub"]
C --> D["Create a container from the image"]
B -->|"if yes"| D
D --> E["Container runs<br/>message is printed โ
"]
A real web server
docker run -d -p 8080:80 nginx
Browser โ http://localhost:8080 โ "Welcome to nginx!" ๐
-dโ detached mode (runs in the background, your terminal stays free)-p 8080:80โ port mapping (Lesson 7)nginxโ the image to run
๐ก You never installed nginx โ Docker fetched it from Docker Hub, set it up, and ran it for you. That's the power of Docker.
Lesson 3
Basic commands
The life of a container (lifecycle)
flowchart LR
A["Image<br/>the recipe"] -->|"docker run"| B["Running"]
B -->|"docker stop"| C["Stopped"]
C -->|"docker start"| B
C -->|"docker rm"| D["Removed ๐๏ธ"]
Everyday commands
| What you want to do | Command |
|---|---|
| See running containers | docker ps |
| See all (even stopped) | docker ps -a |
| Stop one | docker stop <name> |
| Start it again | docker start <name> |
| Remove one | docker rm <name> |
| See your images | docker images |
| Remove an image | docker rmi <image> |
| See what's going on inside | docker logs <name> |
| Go inside a running container | docker exec -it <name> bash |
๐ก stop = a temporary pause. start = start again. rm = delete completely.
Lesson 4
Docker Hub โ where to find images
Docker Hub is the big "app store" for Docker images (like the Play Store, but for images). People all over the world upload images, and anyone can download them for free.
flowchart TB
HUB["๐ช Docker Hub<br/>nginx | mysql | python | node ..."]
HUB -->|"pull (download)"| PC["Your computer<br/>takes it and runs it"]
MINE["The image you built"] -->|"push (upload)"| HUB
- Pull = download an image from Docker Hub โ
docker pull mysql - Push = upload an image you built, to share it
Image name and tag
nginx:1.27
โ โ
โ โโโ tag (the version)
โโโโโโโโโ the image's name
- A tag is like a version โ
python:3.12,mysql:8.0 - If you don't give a tag โ it automatically uses
latest - โ ๏ธ In real projects it's better to specify an exact version (
latestchanges over time)
Official images (nginx, mysql, python) = verified by Docker and trustworthy. Use these whenever you can.
Lesson 5
Dockerfile โ building your own image โญ
This is the heart of Docker. A Dockerfile is the sheet where you write the recipe for building an image โ a list of steps.
Example project (3 files)
app.py (a small Python web app):
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'Hello from my own Docker image! ๐'
app.run(host='0.0.0.0', port=5000)
requirements.txt:
flask
Dockerfile โญ:
FROM python:3.12
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 5000
CMD ["python", "app.py"]
Every line explained
| Keyword | Meaning (simply) |
|---|---|
FROM python:3.12 |
Which base image to start from (like a ready-made cake mix) |
WORKDIR /app |
The working folder inside the container (like clearing the kitchen counter) |
COPY . . |
Copy my files into the container (bringing in the ingredients) |
RUN pip install ... |
Commands to run while building the image (installing things) |
EXPOSE 5000 |
Which port the app works on (a signboard) |
CMD ["python","app.py"] |
The main thing to start when the container runs |
๐ง
RUN= while building the image (happens once).CMD= every time the container runs.
Build and run
docker build -t myapp .
docker run -d -p 5000:5000 myapp
Browser โ http://localhost:5000 โ "Hello from my own Docker image!" ๐
flowchart LR
A["Dockerfile<br/>recipe (text)"] -->|"docker build"| B["Image<br/>myapp (read-only)"]
B -->|"docker run"| C["Container<br/>app is running"]
Lesson 6
Volumes โ keeping your data safe
The problem
A container is temporary (like a whiteboard). When you run docker rm, all the data inside is lost. For a database, that's a huge problem!
The solution โ Volume
A volume is a place outside the container (on your computer) where data is saved โ like an external hard disk. Even if the container is gone, the data in the volume stays exactly as it was.
flowchart TB
subgraph nov["โ Without a volume"]
A["Container<br/>data inside"] -->|"docker rm"| B["data is gone ๐ฅ"]
end
subgraph wv["โ
With a volume"]
C["Container"] -->|"connect"| D["Volume<br/>saved on the computer<br/>(like a hard disk)"]
C -->|"docker rm โ new container"| E["Old data is back! โ
"]
D --> E
end
Using it โ the -v flag
docker run -d -v mydata:/var/lib/mysql mysql
-v mydata : /var/lib/mysql
โ โ
โ โโโ where data is saved inside the container
โโโโโโโโโโโโโโโ the volume's name (on your computer)
2 types of volumes
| Named Volume | Bind Mount | |
|---|---|---|
| Left side is | A name (mydata) |
A real folder path (/home/...) |
| Who manages it | Docker | You |
| Best used for | Databases, important data | While developing code |
Volume commands
| What you want to do | Command |
|---|---|
| List volumes | docker volume ls |
| Create one | docker volume create mydata |
| Remove one | docker volume rm mydata |
๐ง Golden rule: Give every container that holds a database, user files, or other important data a volume.
How exactly does the folder connect?
-v SOURCE:TARGET โ left = the real location, right = the location inside the container. This is not a copy โ it's a live link. Both sides point to the very same files.
flowchart LR
A["Folder on your computer<br/>/home/kamal/myshop/uploads<br/>(SOURCE = left)"] <-->|"the same files (live link)"| B["Folder inside the container<br/>/app/uploads<br/>(TARGET = right)"]
- Named volume โ managed by Docker (on Linux:
/var/lib/docker/volumes/...). Best for databases. - Bind mount โ a real folder of yours. Awesome while developing code:
# Linux/Mac docker run -d -p 5000:5000 -v $(pwd):/app myapp # Windows PowerShell docker run -d -p 5000:5000 -v ${PWD}:/app myapp$(pwd)= "the folder I'm in right now". If you edit the code, it's instantly updated inside the container too!
๐ก Every program has a place inside the container where it stores its data:
- MySQL โ
/var/lib/mysql- PostgreSQL โ
/var/lib/postgresql/data- MongoDB โ
/data/db
Lesson 7
Ports & Networking
What is a port?
An apartment building has one address (IP), with a number of flats inside (ports). A port = a specific door.
- Web โ port 80 / 443
- MySQL โ 3306
- Our Flask app โ 5000
The -p flag
A container is closed off โ to open a door to the outside, you need -p.
-p 8080 : 80
โ โ
โ โโโ the port inside the container (where the app runs)
โโโโโโโโโโ the port on your computer (the door from outside)
flowchart LR
A["Browser<br/>localhost:8080"] --> B["Computer's door<br/>port 8080<br/>(left)"]
B -->|"-p 8080:80"| C["Inside the container<br/>port 80<br/>nginx"]
- The left and right numbers don't have to match:
-p 3000:80โlocalhost:3000 - If a door is already in use, pick another number:
-p 9090:80
Two containers talking to each other โ Docker Network
A Docker network is a private room just for a few containers. Containers inside it recognise each other by name (no IP needed).
docker network create shop-net
docker run -d --name shop-db --network shop-net mysql:8.0
docker run -d --name web-app --network shop-net myapp
flowchart LR
subgraph net["Docker network: shop-net (private room)"]
A["web-app<br/>Flask"] -->|"talks via the name 'shop-db'"| B["shop-db<br/>MySQL"]
end
For web-app to talk to shop-db, it simply uses the name shop-db itself as the address.
-p vs --network
-p (port mapping) |
--network |
|
|---|---|---|
| What for? | Outside world โ container | Container โ container |
| Example | browser โ web app | web app โ database |
Lesson 8
Docker Compose
The problem
Running a multi-container app with a pile of commands is long, hard, and error-prone.
The solution โ Compose
Docker Compose = the conductor of an orchestra. You write all your containers in one file (docker-compose.yml) and run them with a single command.
docker-compose.yml
services:
web-app:
build: .
ports:
- "5000:5000"
depends_on:
- shop-db
shop-db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: mypass123
MYSQL_DATABASE: shopdb
volumes:
- shop-data:/var/lib/mysql
volumes:
shop-data:
services:โ the containersbuild: .โ build from the Dockerfileimage:โ pull from Docker Hubports/environment/volumesโ the same as-p,-e,-vin the commands, just written neatlydepends_onโ what needs to start first
๐ง None of this is new โ it's the very same things from the commands, written in an orderly way!
flowchart LR
A["docker-compose.yml<br/>web-app + shop-db<br/>+ volume + network"] -->|"docker compose up"| B["Automatically: network + volume<br/>+ build + run<br/>the whole app โ
"]
Commands
| What you want to do | Command |
|---|---|
| Run everything (in the background) | docker compose up -d |
| Stop and remove everything | docker compose down |
| View logs | docker compose logs |
| Running services | docker compose ps |
| Rebuild and run again | docker compose up -d --build |
โธ๏ธ Part 2 โ Kubernetes
Lesson 9
Why do we need Kubernetes?
Docker Compose is limited to a single computer. As your app grows, problems appear:
- ๐ฅ One computer isn't enough โ you need many servers
- ๐ด If a container crashes, it doesn't come back automatically
- ๐ How do you add or remove containers depending on the number of customers?
- ๐ฅ What if an entire server dies?
The solution โ Kubernetes (K8s)
Kubernetes = a "ship's captain" โ that automatically manages lots of containers across lots of servers. (K + 8 letters + s = K8s)
- ๐งญ Distributes โ spreads containers properly across servers
- โค๏ธโ๐ฉน Self-healing โ a dead one is automatically brought back
- ๐ Scaling โ more or fewer, depending on customers
- ๐ Load balancing โ spreads traffic properly
- ๐ Rolling updates โ switch versions with no downtime
flowchart TB
subgraph c["Docker Compose"]
A["Just one computer<br/>if it crashes โ rebuild by hand"]
end
subgraph k["Kubernetes (the Captain manages automatically)"]
B["Server 1<br/>web, web"]
C["Server 2<br/>web, database"]
D["Server 3<br/>web"]
end
โ ๏ธ Kubernetes โ a replacement for Docker. Docker creates containers, Kubernetes manages them โ they work together. For small projects Compose is enough; K8s is worth it for big, serious apps.
Lesson 10
Cluster, Nodes & Control Plane
- Cluster = the entire Kubernetes setup (the whole restaurant)
- Node = a computer/server (a member of the cluster)
- Control Plane = the brain / manager (makes decisions, doesn't do the work itself)
- Worker Nodes = the chefs (they actually run the containers)
flowchart TB
subgraph cluster["CLUSTER (the whole setup)"]
CP["Control Plane (the Captain / the brain)<br/>makes decisions โ doesn't run containers"]
CP -->|"'do this'"| W1["Worker Node 1<br/>container, container"]
CP --> W2["Worker Node 2<br/>container, database"]
CP --> W3["Worker Node 3<br/>container"]
end
kubectl โ your walkie-talkie
The tool you use to give commands to the control plane (the captain). (Pronounced "cube-control".)
kubectl get nodes # see the nodes in the cluster
kubectl get pods # see the running pods
docker= for one computer.kubectl= for the entire cluster.
A cluster to learn on
On your own laptop: Minikube, kind, or Docker Desktop (enable Kubernetes).
๐ฌ Who does kubectl talk to?
kubectl is only for you (from outside) โ giving orders to the captain (Control Plane). The captain โ worker conversation isn't done with kubectl โ that happens automatically inside the cluster, via components like kubelet.
flowchart LR
U["You (laptop)"] -->|"kubectl"| CP["Control Plane (Captain)"]
CP <-->|"automatic (not kubectl)"| W["Worker Nodes<br/>(kubelet)"]
Lesson 11
Pods
Kubernetes doesn't manage containers directly โ it puts the container in a Pod and manages the Pod.
Pod = the smallest unit that K8s manages, wrapping one container (or several) โ like a pea pod ๐ซ.
flowchart LR
subgraph p1["Pod (usually)"]
C1["container<br/>(web-app)"]
end
subgraph p2["Pod (sometimes)"]
C2["app"]
C3["helper"]
end
- Usually a pod has just one container (99% of the time)
- Containers in the same pod โ share network + storage (they talk over
localhost) - โ ๏ธ Pods are temporary โ they die, new ones come, and the IP changes
Pod YAML (for learning/testing only)
apiVersion: v1
kind: Pod
metadata:
name: my-web-pod
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 80
kubectl apply -f my-pod.yaml
kubectl get pods
โ ๏ธ In real projects you don't create pods directly (if one crashes, it doesn't come back). You use a Deployment (next lesson).
Hierarchy โ Russian dolls ๐ช
flowchart TB
CL["CLUSTER"] --> N["NODE (a computer)"]
N --> P["POD (many on one node)"]
P --> C["CONTAINER (usually one per pod)"]
Cluster โ Nodes โ Pods โ Containers โ like building โ apartments โ families. (One node can hold many pods!)
Lesson 12
Deployments โญ
The most important, everyday-use thing in Kubernetes.
Deployment = the manager that looks after pods (like a thermostat ๐ก๏ธ). You say "what I want" โ it takes care of everything else.
Desired State
You say: "I always want 3 of this pod" (replicas: 3).
- If one dies โ Kubernetes automatically creates a new one (back to 3)
- Just like a thermostat holding the temperature at 24ยฐC
flowchart TB
D["Deployment (manager)<br/>replicas: 3"] --> P1["Pod 1 โ
"]
D --> P2["Pod 2 ๐ฅ crash"]
D --> P3["Pod 3 โ
"]
D -->|"'want 3, have 2' โ auto"| P2b["Pod 2 (new!) โ
"]
Deployment YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: myapp:1.0
ports:
- containerPort: 5000
replicas: 3โญ = "I want 3 pods"template:= the pods to be created should look like thislabels/selector= a "sticker" ๐ท๏ธ on the pods (this is how the Deployment finds its own pods)
Commands
kubectl apply -f deployment.yaml # create/update
kubectl get deployments
kubectl get pods
kubectl scale deployment web-app --replicas=10 # scale! ๐
kubectl rollout undo deployment web-app # rollback ๐
Self-healing test: kubectl delete pod <name> โ kubectl get pods โ a new one has appeared! ๐คฏ
๐ Rolling Updates
Change the image in the YAML to myapp:2.0 and run kubectl apply โ the old pods are gradually removed and replaced with new ones โ switching versions with no downtime.
๐ง Golden rule: In Kubernetes you never create a pod directly โ always use a Deployment.
Lesson 13
Services
2 problems
- A pod's IP keeps changing โ how do you talk to it?
- There are 3 pods โ which one gets the traffic?
The solution โ Service
Service = a front desk ๐ that sits in front of the pods, has a fixed address, and distributes traffic (like an office receptionist).
- Even if the pods' IPs change, the Service's address stays fixed โ
- Traffic is spread properly across the pods (load balancing) โ
- It finds the pods using a label (sticker)
flowchart LR
U["Users"] --> S["Service<br/>fixed address<br/>(front desk)"]
S -->|"distributes"| P1["Pod 1"]
S --> P2["Pod 2"]
S --> P3["Pod 3"]
3 types of Service
| Type | What it's for | When |
|---|---|---|
| ClusterIP (default) | Internal only ๐ | web-app โ database |
| NodePort | Opened to the outside (simply) ๐ช | while testing |
| LoadBalancer | The real internet ๐ | a production website |
Service YAML
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: ClusterIP
selector:
app: web # to the pods that have the 'app: web' sticker
ports:
- port: 80
targetPort: 5000
kubectl apply -f service.yaml
kubectl get services
๐๏ธ Deployment + Service = the basic set for any Kubernetes app.
Lesson 14
ConfigMaps & Secrets
Hard-coding settings/passwords into your code is bad ๐ฌ. So we keep them separate:
- ConfigMap ๐ = settings that aren't secret (db name, mode, URL)
- Secret ๐ = secret things (passwords, API keys)
flowchart LR
CM["ConfigMap ๐<br/>db name, mode, URL"] -->|"inject"| POD["Pod (app)<br/>gets settings from them<br/>(not hard-coded in the code)"]
SEC["Secret ๐<br/>password, API key"] -->|"inject"| POD
YAML
ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DB_NAME: shopdb
APP_MODE: production
Secret:
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
stringData:
DB_PASSWORD: mypass123
โ ๏ธ Important: By default a Secret is only "hidden" using base64 โ that is not real encryption. Anyone can decode it. In production, enable encryption / use tools like Vault.
Injecting into a Pod (environment variables)
containers:
- name: web
image: myapp:1.0
env:
- name: DB_NAME
valueFrom:
configMapKeyRef:
name: app-config
key: DB_NAME
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: DB_PASSWORD
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl get configmaps
kubectl get secrets
Lesson 15
Namespaces
Namespace = a separate "room" ๐๏ธ inside the cluster โ to keep things separated and tidy (like rooms in an office building).
- Names only need to be unique within the same namespace (the same name is fine in different namespaces)
- Most common use: separating dev / test / production
flowchart TB
subgraph CL["CLUSTER"]
subgraph dev["Namespace: dev"]
D1["web-app"]
D2["database"]
end
subgraph test["Namespace: test"]
T1["web-app"]
T2["database"]
end
subgraph prod["Namespace: production"]
P1["web-app"]
P2["database"]
end
end
(All 3 namespaces have a "web-app" โ no conflict!)
Ones that already exist
defaultโ where things go if you don't specify a namespacekube-systemโ Kubernetes' own stuff (โ ๏ธ don't touch)kube-publicโ public stuff
Commands โ the -n flag matters!
kubectl get namespaces
kubectl create namespace dev
kubectl get pods -n dev # pods in the dev namespace
kubectl get pods -n production # pods in production
โ ๏ธ If you don't add
-n, it always looks atdefault. If you can't see the pods in dev, add-n dev!
In YAML: metadata.namespace: dev
Lesson 16
Volumes & Persistent Storage
Since pods are temporary, you need storage to keep data safe (like Docker volumes). Kubernetes separates this into the request and the actual storage:
- PersistentVolume (PV) ๐๏ธ = the actual storage (the books ๐)
- PersistentVolumeClaim (PVC) ๐ = the "I need storage" request (the application form)
- StorageClass โก = automatically creates PVs for you (in the cloud)
flowchart LR
POD["Pod (app)<br/>needs to save data"] -->|"use"| PVC["PVC (request)<br/>'I need 5GB' ๐"]
PVC -->|"K8s matches"| PV["PV (actual storage)<br/>hard disk / cloud ๐๏ธ"]
YAML
PVC (the request):
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-storage
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
Using it in a Pod/Deployment:
spec:
containers:
- name: db
image: mysql:8.0
volumeMounts:
- name: data
mountPath: /var/lib/mysql # where MySQL keeps its data inside the container
volumes:
- name: data
persistentVolumeClaim:
claimName: my-storage
kubectl apply -f pvc.yaml
kubectl get pvc
kubectl get pv
kubectl get storageclass
| Docker | Kubernetes | |
|---|---|---|
| Keeping data safe | Volume | PV |
| How you ask for it | -v name:/path |
PVC |
| Auto-creates it | โ | StorageClass |
Lesson 17
Ingress
The problems
- ๐ธ One LoadBalancer per app โ very expensive
- You can't split traffic by URL (
/products,/blog)
The solution โ Ingress
Ingress ๐ฆ = the smart traffic policeman standing at the entrance to the cluster. It takes in traffic through a single door, looks at the URL, and directs it to the right Service.
flowchart LR
I["Internet<br/>users"] --> ING["Ingress ๐ฆ<br/>looks at the URL<br/>(one door)"]
ING -->|"/products"| S1["products Service"]
ING -->|"/blog"| S2["blog Service"]
ING -->|"/api"| S3["api Service"]
โ ๏ธ Ingress = just the rules. You need to install an Ingress Controller to actually carry them out (the most popular: nginx-ingress).
- Ingress = the rulebook ๐
- Ingress Controller = the actual policeman ๐ฎ
Ingress YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-ingress
spec:
rules:
- host: shop.com
http:
paths:
- path: /products
pathType: Prefix
backend:
service:
name: products-service
port:
number: 80
- path: /blog
pathType: Prefix
backend:
service:
name: blog-service
port:
number: 80
kubectl apply -f ingress.yaml
kubectl get ingress
๐ HTTPS (SSL/TLS) can also be managed in the Ingress, all in one place.
Lesson 18
Everything together โ a real app ๐
An online shop โ every concept we've learned, working together:
flowchart TB
U["Users (internet) ๐"] --> ING["Ingress ๐ฆ (shop.com)"]
ING --> WS["web Service ๐ช"]
WS --> WD
subgraph WD["web Deployment (replicas: 3) โค๏ธโ๐ฉน"]
W1["web pod"]
W2["web pod"]
W3["web pod"]
end
CFG["ConfigMap ๐<br/>Secret ๐"] -->|"settings"| WD
WD -->|"via the name 'db-service'"| DS["db Service ๐ช (ClusterIP)"]
DS --> DB["db pod (MySQL) ๐๏ธ"]
DB --> PVC["PVC โ PV ๐พ<br/>(data is safe)"]
The journey of a request ๐ถ
- ๐ A customer comes to
shop.com - ๐ฆ Ingress โ looks at the URL and sends it to the web Service
- ๐ช web Service โ picks one of the 3 pods (load balancing)
- ๐ฆ web pod processes it (settings/password from the ConfigMap + Secret)
- ๐๏ธ If it needs the db โ goes to the db Service using the name
db-service - ๐พ db pod โ data is kept safe on the PVC โ PV
- โฉ๏ธ The answer goes back to the customer โ the website appears! ๐
Deployment order
| File | What it's for | Lesson |
|---|---|---|
configmap.yaml |
settings | 14 |
secret.yaml |
password | 14 |
pvc.yaml |
database storage | 16 |
db-deployment.yaml + db-service.yaml |
database | 12, 13 |
web-deployment.yaml + web-service.yaml |
web app | 12, 13 |
ingress.yaml |
internet access | 17 |
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f pvc.yaml
kubectl apply -f db-deployment.yaml
kubectl apply -f db-service.yaml
kubectl apply -f web-deployment.yaml
kubectl apply -f web-service.yaml
kubectl apply -f ingress.yaml
๐ก Put everything in one folder and run
kubectl apply -f .to do it all at once!
Commands Cheat Sheet
๐ณ Docker
# Images & containers
docker --version
docker run hello-world
docker run -d -p 8080:80 nginx # detached + port mapping
docker ps # running containers
docker ps -a # all of them
docker stop <name> # stop
docker start <name> # start again
docker rm <name> # remove
docker logs <name> # view logs
docker exec -it <name> bash # go inside
# Images
docker images # list images
docker pull mysql # download
docker rmi <image> # remove an image
docker build -t myapp . # Dockerfile โ image
# Volumes
docker volume ls
docker volume create mydata
docker run -d -v mydata:/var/lib/mysql mysql
docker run -d -v $(pwd):/app myapp # bind mount
# Network
docker network create shop-net
docker run -d --name web --network shop-net myapp
# Compose
docker compose up -d
docker compose down
docker compose logs
docker compose ps
docker compose up -d --build
โธ๏ธ Kubernetes (kubectl)
# View
kubectl get nodes
kubectl get pods
kubectl get deployments
kubectl get services
kubectl get ingress
kubectl get configmaps
kubectl get secrets
kubectl get pvc
kubectl get pv
kubectl get namespaces
# Create / update
kubectl apply -f file.yaml
kubectl apply -f . # everything in the folder
# Deployment
kubectl scale deployment web-app --replicas=10
kubectl rollout undo deployment web-app
# Namespace
kubectl create namespace dev
kubectl get pods -n dev # -n = which namespace
# Debug
kubectl logs <pod>
kubectl describe pod <pod>
kubectl delete pod <pod> # (the Deployment will recreate it)
What's next?
Going deeper into Kubernetes:
- ๐ฉบ Probes (liveness/readiness) โ checking whether a pod is healthy
- ๐ HPA (Horizontal Pod Autoscaler) โ automatically increasing/decreasing the number of pods
- ๐ฆ Helm โ the "package manager" for Kubernetes
- ๐ RBAC โ who is allowed to do what (security)
Real-world work:
- ๐ CI/CD โ push code โ automatically build & deploy
- ๐ Monitoring โ Prometheus + Grafana
- โ๏ธ Managed Kubernetes โ AWS (EKS), Google (GKE), Azure (AKS)
The most important thing โ hands-on experience! ๐ ๏ธ Install Docker Desktop or Minikube on your laptop and build this shop app by hand. You learn far more by doing than by reading โ it's what really sticks in the mind.
๐ Summary of the core ideas
| Concept | In one sentence |
|---|---|
| Image | The app's recipe/blueprint (read-only) |
| Container | The real, running app made from that recipe |
| Dockerfile | The recipe sheet that builds the image |
| Volume | External storage to keep data safe |
| Docker Compose | Multi-container โ one file, one command |
| Kubernetes | The captain that auto-manages lots of containers |
| Cluster | The entire K8s setup |
| Node | A computer/server |
| Pod | The smallest unit wrapping containers |
| Deployment | The manager that looks after pods (self-heal, scale) |
| Service | A fixed address for pods + load balancing |
| ConfigMap / Secret | Settings / secrets (kept separate from the code) |
| Namespace | A separate room inside the cluster |
| PV / PVC | The actual storage / the request for storage |
| Ingress | The policeman that routes traffic by URL |
๐ Congratulations! You've learned Docker and Kubernetes from start to finish. Now go get some hands-on experience! ๐ช