Kubernetes — From Beginner to Advanced
🟢 CHAPTER 1: What is Kubernetes? (Absolute Beginner)
The Problem First
Imagine you built a Node.js app. You dockerized it. Now:
Your app crashes → no one restarts it automatically
Traffic increases → you need 10 copies of your app running
One server dies → your app goes down
You need something to manage all this automatically.
That's Kubernetes.
What Kubernetes Does
Kubernetes is a system that automatically manages your Docker containers — starts them, restarts them, scales them, and balances traffic between them.
Think of it like this:
YOU → tell Kubernetes: "I want 3 copies of my Node.js app running always"
KUBERNETES → does it, watches it, fixes it if anything breaks
Core Vocabulary (memorize these)
| Term | Simple Meaning |
|---|---|
| Cluster | A group of machines (servers) Kubernetes manages |
| Node | One machine (server) inside the cluster |
| Pod | The smallest unit — holds 1 or more containers |
| Deployment | Tells Kubernetes: run this Pod, keep N copies alive |
| Service | Gives your Pod a stable address (like a door to your app) |
| Namespace | A way to group/separate resources (like folders) |
| kubectl | The command-line tool you use to talk to Kubernetes |
🟢 CHAPTER 2: How Kubernetes Works Internally
[ Your Laptop / CI ]
|
| kubectl apply -f file.yaml
↓
[ Control Plane (Master) ]
- API Server ← receives all commands
- Scheduler ← decides which Node to put Pod on
- etcd ← stores the entire cluster state
- Controller ← watches and fixes things
[ Worker Nodes ]
- kubelet ← runs Pods on this machine
- kube-proxy ← handles networking
- Container Runtime (Docker/containerd)
You never talk to Nodes directly. You talk to the API Server using kubectl.
🟡 CHAPTER 3: Your First YAML — The Pod
Every Kubernetes resource is described in a YAML file. You write what you want, Kubernetes makes it happen.
# pod.yaml
apiVersion: v1 # Which Kubernetes API version to use
kind: Pod # What type of resource this is
metadata:
name: my-node-app # Name of this Pod
labels:
app: node-app # A tag — used later by Services to find this Pod
spec:
containers:
- name: node-container # Name of the container inside the Pod
image: my-node-app:1.0 # Docker image to use
ports:
- containerPort: 3000 # Port your Node.js app listens on
Apply it:
kubectl apply -f pod.yaml
kubectl get pods # see running pods
kubectl describe pod my-node-app # detailed info
kubectl logs my-node-app # see app logs
⚠️ Important Rule:
You almost never create Pods directly. You use Deployments instead. A Pod alone has no self-healing.
🟡 CHAPTER 4: Deployment YAML — The Real Way
A Deployment wraps your Pod and adds:
Auto-restart if Pod crashes
Rolling updates (zero downtime)
Easy scaling
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-app-deployment # Name of the Deployment
spec:
replicas: 3 # Keep 3 copies of this Pod running always
selector:
matchLabels:
app: node-app # Manage Pods that have this label
template: # This is the Pod blueprint
metadata:
labels:
app: node-app # Label on each Pod — must match selector above
spec:
containers:
- name: node-container
image: my-node-app:1.0
ports:
- containerPort: 3000
resources:
requests:
memory: "128Mi" # Minimum memory needed
cpu: "250m" # 250 millicores = 0.25 CPU
limits:
memory: "256Mi" # Max memory allowed
cpu: "500m" # Max CPU allowed
Key Concepts in this YAML:
replicas: 3 → Kubernetes always ensures exactly 3 Pods are running. If one dies, it creates a new one immediately.
selector.matchLabels → This links the Deployment to its Pods using labels.
template → The Pod definition. Every Pod created will look like this.
resources → Always set this. Without it, one app can eat all server memory and kill everything.
kubectl apply -f deployment.yaml
kubectl get deployments
kubectl get pods # you'll see 3 pods
kubectl rollout status deployment/node-app-deployment
🟡 CHAPTER 5: Service YAML — Expose Your App
A Pod's IP changes every time it restarts. A Service gives a stable endpoint.
There are 3 main Service types:
| Type | Use Case |
|---|---|
| ClusterIP | Internal only — Pods talk to each other |
| NodePort | Expose on a port of the Node (for testing) |
| LoadBalancer | Cloud providers give a public IP |
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: node-app-service
spec:
type: ClusterIP # Only accessible inside the cluster
selector:
app: node-app # Find Pods with this label (matches Deployment)
ports:
- protocol: TCP
port: 80 # Port the Service exposes
targetPort: 3000 # Port the Pod/container listens on
How traffic flows:
Request → Service (port 80) → Pod (port 3000)
The Service load-balances automatically between all 3 Pods.
🟡 CHAPTER 6: ConfigMap and Secret YAML
Your Node.js app needs environment variables (DB_HOST, API_KEY, etc.). Don't hardcode them in the image.
ConfigMap — for non-sensitive config:
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: node-app-config
data:
NODE_ENV: "production"
PORT: "3000"
DB_HOST: "postgres-service"
Secret — for sensitive data:
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: node-app-secret
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQxMjM= # base64 encoded — never plain text
JWT_SECRET: bXlzZWNyZXRrZXk=
Encode your values:
echo -n "password123" | base64
# output: cGFzc3dvcmQxMjM=
Use them inside your Deployment:
# inside deployment.yaml → spec.containers
env:
- name: NODE_ENV
valueFrom:
configMapKeyRef:
name: node-app-config # ConfigMap name
key: NODE_ENV # Key inside ConfigMap
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: node-app-secret # Secret name
key: DB_PASSWORD # Key inside Secret
🟠 CHAPTER 7: Ingress + Nginx — The Real Production Setup
The goal: User hits yourapp.com → Nginx Ingress Controller → routes to your Node.js Service
Internet
|
[ Ingress Controller (Nginx) ] ← one entry point
| |
| |
[node-app-service] [another-service]
|
[3 Node.js Pods]
Step 1 — Install Nginx Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.4/deploy/static/provider/cloud/deploy.yaml
Step 2 — Ingress YAML
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: node-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # Rewrite URL path
spec:
ingressClassName: nginx # Use nginx ingress class
rules:
- host: yourapp.com # Your domain
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: node-app-service # Your Service name
port:
number: 80 # Service port
Multiple apps on same domain:
rules:
- host: yourapp.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
🟠 CHAPTER 8: Namespace YAML
Namespaces separate your environments inside one cluster.
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
kubectl apply -f namespace.yaml
kubectl apply -f deployment.yaml -n production # deploy into this namespace
kubectl get pods -n production
🔴 CHAPTER 9: Full Real-World Node.js + Nginx Setup
Here is the complete folder structure:
k8s/
├── namespace.yaml
├── configmap.yaml
├── secret.yaml
├── deployment.yaml
├── service.yaml
└── ingress.yaml
namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: node-config
namespace: production
data:
NODE_ENV: "production"
PORT: "3000"
secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: node-secret
namespace: production
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQxMjM=
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-deployment
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: node-app
strategy:
type: RollingUpdate # Zero downtime deployment
rollingUpdate:
maxSurge: 1 # Create 1 extra Pod during update
maxUnavailable: 0 # Never take Pods down before new ones are ready
template:
metadata:
labels:
app: node-app
spec:
containers:
- name: node-app
image: your-dockerhub/node-app:1.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
valueFrom:
configMapKeyRef:
name: node-config
key: NODE_ENV
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: node-secret
key: DB_PASSWORD
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe: # Kubernetes checks if app is alive
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10 # Wait 10s before first check
periodSeconds: 5 # Check every 5 seconds
readinessProbe: # Kubernetes checks if app is ready for traffic
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 3
service.yaml
apiVersion: v1
kind: Service
metadata:
name: node-service
namespace: production
spec:
type: ClusterIP
selector:
app: node-app
ports:
- port: 80
targetPort: 3000
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: node-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- yourapp.com
secretName: tls-secret # Your SSL certificate stored as a Secret
rules:
- host: yourapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: node-service
port:
number: 80
Deploy everything:
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml
🔴 CHAPTER 10: Scaling & Updates (Advanced)
Scale manually:
kubectl scale deployment node-deployment --replicas=10 -n production
Auto-scaling (HPA):
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: node-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: node-deployment
minReplicas: 2 # Never go below 2 Pods
maxReplicas: 20 # Never go above 20 Pods
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # Scale up when CPU hits 70%
kubectl apply -f hpa.yaml
kubectl get hpa -n production
Update your app (zero downtime):
# Build and push new Docker image
docker build -t your-dockerhub/node-app:2.0 .
docker push your-dockerhub/node-app:2.0
# Update the image in Kubernetes
kubectl set image deployment/node-deployment node-app=your-dockerhub/node-app:2.0 -n production
# Watch the rolling update happen live
kubectl rollout status deployment/node-deployment -n production
# Rollback if something goes wrong
kubectl rollout undo deployment/node-deployment -n production
📋 Essential kubectl Commands Cheatsheet
# Get everything
kubectl get all -n production
# Watch pods live
kubectl get pods -n production -w
# See logs
kubectl logs <pod-name> -n production
kubectl logs <pod-name> -n production -f # follow live logs
# Go inside a Pod (like docker exec)
kubectl exec -it <pod-name> -n production -- /bin/sh
# Delete and re-apply
kubectl delete -f deployment.yaml
kubectl apply -f deployment.yaml
# See resource usage
kubectl top pods -n production
kubectl top nodes
🗺️ Your Learning Path Summary
Beginner: Pod → Deployment → Service
Intermediate: ConfigMap → Secret → Namespace → Ingress + Nginx
Advanced: HPA → Rolling Updates → Probes → TLS → Multi-service routing


