☸ Kubernetes
Kubernetes — Container Orchestration
Kubernetes (k8s) automates deployment, scaling, and management of containerized applications across a cluster of machines.
🏗️ Cluster Architecture
Kubernetes Cluster
┌─────────────────────────────────────────────────────────────────┐
│ Control Plane (Master Node) │
│ ├── API Server ← all kubectl commands go here │
│ ├── etcd ← cluster state database │
│ ├── Scheduler ← decides which node to run pods on │
│ └── Controller Manager← watches cluster and reconciles state │
└──────────────────────────────────────────────────────────────────┘
│ │ │
┌───────────┐ ┌──────────┐ ┌───────────┐
│ Worker Node 1│ │ Worker Node 2│ │ Worker Node 3│
│ ├─ kubelet │ │ ├─ kubelet│ │ ├─ kubelet │ ← node agent
│ ├─ kube-proxy ├─ kube-proxy ├─ kube-proxy ← network rules
│ │ │ │ │ │ │
│ │ Pod A │ │ Pod B │ │ Pod C │
│ │ [app:v2] │ │ [app:v2] │ │ [db:16] │
└───────────┘ └──────────┘ └───────────┘
🧱 Core Objects
| Object | What It Does | YAML Kind |
|---|---|---|
| Pod | Smallest unit — one or more containers sharing a network and volumes | Pod |
| Deployment | Manages a set of identical pods, handles rolling updates and rollbacks | Deployment |
| Service | Stable DNS name + load balancing to a group of pods (via label selector) | Service |
| ConfigMap | Non-secret config data (env vars, config files) | ConfigMap |
| Secret | Sensitive data (passwords, API keys) — base64 encoded | Secret |
| Namespace | Virtual cluster — isolates resources (dev / staging / prod) | Namespace |
| PersistentVolumeClaim | Request for storage — bound to a PersistentVolume | PersistentVolumeClaim |
| HorizontalPodAutoscaler | Auto-scale pod count based on CPU/memory | HorizontalPodAutoscaler |
| Ingress | HTTP routing rules — routes external traffic to services | Ingress |
⌨️ kubectl Basics
# ── Context & Cluster ──────────────────────────────────
kubectl config get-contexts # list all clusters
kubectl config use-context my-cluster # switch cluster
kubectl cluster-info # show cluster endpoints
# ── Get resources ──────────────────────────────────────
kubectl get pods # pods in default namespace
kubectl get pods -n kube-system # pods in a namespace
kubectl get pods -A # pods in ALL namespaces
kubectl get pods -o wide # with node + IP
kubectl get all -n myapp # everything in namespace
# ── Describe (detailed info + events) ─────────────────
kubectl describe pod my-pod-abc123
kubectl describe deployment web
kubectl describe service db
# ── Logs ───────────────────────────────────────────────
kubectl logs my-pod-abc123 # logs from pod
kubectl logs -f my-pod-abc123 # stream logs
kubectl logs deployment/web # logs from any pod in deployment
kubectl logs my-pod -c sidecar # multi-container pod — pick container
kubectl logs -l app=web --tail=100 # logs from all pods with label
# ── Shell into a pod ────────────────────────────────────
kubectl exec -it my-pod-abc123 -- bash
kubectl exec -it my-pod-abc123 -- sh
kubectl exec -it deployment/web -- bash
# ── Apply / Delete ──────────────────────────────────────
kubectl apply -f deployment.yaml # create or update
kubectl apply -f ./manifests/ # apply whole directory
kubectl delete -f deployment.yaml # delete from file
kubectl delete pod my-pod-abc123 # delete specific resource
kubectl delete pod -l app=web # delete by label
# ── Scale ───────────────────────────────────────────────
kubectl scale deployment web --replicas=5
kubectl scale deployment web --replicas=0 # stop all pods
# ── Port forward ────────────────────────────────────────
kubectl port-forward pod/my-pod 8080:8080
kubectl port-forward service/web 8080:80
kubectl port-forward deployment/api 3000:3000
# ── Rollout ─────────────────────────────────────────────
kubectl rollout status deployment/web
kubectl rollout history deployment/web
kubectl rollout undo deployment/web # rollback
🫁 Pod
apiVersion: v1
kind: Pod
metadata:
name: myapp
namespace: default
labels:
app: myapp
version: "1.0"
spec:
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 8080
env:
- name: LOG_LEVEL
value: "info"
- name: DB_PASSWORD # from a Secret
valueFrom:
secretKeyRef:
name: db-secret
key: password
resources:
requests:
cpu: "100m" # 100 millicores = 0.1 CPU
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe: # restart container if this fails
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe: # remove from Service if not ready
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
🚀 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: myapp
spec:
replicas: 3
selector:
matchLabels:
app: web # must match pod template labels
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # at most 1 pod down during update
maxSurge: 1 # at most 1 extra pod during update
template:
metadata:
labels:
app: web # Service selector targets this
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests: { cpu: "50m", memory: "64Mi" }
limits: { cpu: "200m", memory: "256Mi" }
- name: log-sidecar # sidecar container in same pod
image: fluentd:latest
volumeMounts:
- name: logs
mountPath: /logs
volumes:
- name: logs
emptyDir: {} # shared between containers, wiped on pod deletion
🔌 Service
# ClusterIP — internal only (default)
apiVersion: v1
kind: Service
metadata:
name: web
namespace: myapp
spec:
selector:
app: web # routes to pods with this label
ports:
- name: http
port: 80 # service port (what you curl)
targetPort: 8080 # pod port
---
# NodePort — accessible on every node at nodePort
spec:
type: NodePort
selector: { app: web }
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 30000–32767
---
# LoadBalancer — creates a cloud load balancer (AWS/GCP/Azure)
spec:
type: LoadBalancer
selector: { app: web }
ports:
- port: 80
targetPort: 8080
| Service Type | Reachable From | Use When |
|---|---|---|
ClusterIP | Inside cluster only | Service-to-service communication |
NodePort | Node IP + port | Dev/testing, local kind clusters |
LoadBalancer | Public IP (cloud) | Production on AWS/GCP/Azure |
ExternalName | DNS alias | Bridge to external service via DNS |
🔐 ConfigMap & Secret
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: myapp
data:
LOG_LEVEL: "info"
CACHE_TTL: "300"
config.json: |
{ "feature_flags": { "new_ui": true } }
---
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: myapp
type: Opaque
stringData: # plain text — k8s encodes to base64
DB_HOST: "postgres.myapp.svc.cluster.local"
DB_PASSWORD: "supersecret"
DB_USER: "appuser"
# Create from literals
kubectl create secret generic db-secret \
--from-literal=DB_PASSWORD=secret123 \
--from-literal=DB_USER=appuser
# Create from file
kubectl create secret generic tls-secret \
--from-file=tls.crt=./cert.pem \
--from-file=tls.key=./key.pem
# Read a secret value
kubectl get secret db-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -d
💾 Volumes & PVCs
# 1. Claim storage
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
namespace: myapp
spec:
accessModes:
- ReadWriteOnce # mounted by one node at a time
resources:
requests:
storage: 10Gi
storageClassName: standard # or gp2 on AWS, standard on kind
---
# 2. Mount it in a pod
spec:
containers:
- name: postgres
image: postgres:16
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
persistentVolumeClaim:
claimName: postgres-data
📁 Namespaces
# Create namespace
kubectl create namespace staging
# Set default namespace for your session
kubectl config set-context --current --namespace=staging
# All commands respect namespace
kubectl get pods -n staging
kubectl apply -f . -n staging
# Cross-namespace DNS
# web.staging.svc.cluster.local → service "web" in namespace "staging"
# Full form: ..svc.cluster.local
📈 Autoscaling (HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
namespace: myapp
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60 # scale out when avg CPU > 60%
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70
kubectl get hpa -n myapp
kubectl describe hpa web-hpa -n myapp
📌 kubectl Cheat Sheet
| Task | Command |
|---|---|
| List pods (all namespaces) | kubectl get pods -A |
| Watch pod restarts live | kubectl get pods -w |
| Describe a pod (events + config) | kubectl describe pod NAME |
| Shell into pod | kubectl exec -it NAME -- bash |
| Stream logs | kubectl logs -f NAME |
| Forward port | kubectl port-forward svc/NAME 8080:80 |
| Apply manifest | kubectl apply -f file.yaml |
| Delete resource | kubectl delete -f file.yaml |
| Scale deployment | kubectl scale deploy NAME --replicas=3 |
| Rollback deployment | kubectl rollout undo deploy/NAME |
| Get events (sorted) | kubectl get events --sort-by=.lastTimestamp |
| Get resource YAML | kubectl get deploy NAME -o yaml |
| Edit live resource | kubectl edit deployment NAME |
| Force restart pods | kubectl rollout restart deploy/NAME |
| Show node resources | kubectl top nodes |
| Show pod resources | kubectl top pods -A |