Kubernetes for Beginners: Deploy, Scale & Manage Containers in 2026
Learn Kubernetes from scratch — pods, deployments, services, ingress, ConfigMaps, and scaling. A practical guide with real examples to get your first app running on K8s.
What Is Kubernetes?
Kubernetes (K8s) is a container orchestration platform. If Docker is how you package your app, Kubernetes is how you run it in production — handling deployment, scaling, networking, and self-healing automatically.
The problem Kubernetes solves:
- You have 50 containers across 10 servers — who decides which container runs where?
- A container crashes at 3 AM — who restarts it?
- Traffic spikes 10x — who spins up more instances?
- You deploy a bad version — who rolls it back?
Kubernetes handles all of this.
Without K8s: You manually manage containers on servers
With K8s: You describe what you want, K8s makes it happen
Core Concepts
The Hierarchy
Cluster
└── Nodes (physical/virtual machines)
└── Pods (smallest deployable unit)
└── Containers (your app)
Key Resources
| Resource | What It Does | |----------|-------------| | Pod | Runs one or more containers together | | Deployment | Manages pods — scaling, updates, rollbacks | | Service | Stable network endpoint for pods | | Ingress | Routes external HTTP traffic to services | | ConfigMap | Stores configuration (env vars, files) | | Secret | Stores sensitive data (passwords, tokens) | | Namespace | Virtual cluster for isolation |
Setting Up
Local Development
# Option 1: minikube (most popular)
# Install minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Start cluster
minikube start
# Option 2: kind (Kubernetes in Docker)
go install sigs.k8s.io/kind@latest
kind create cluster
# Option 3: Docker Desktop (Mac/Windows)
# Enable Kubernetes in Docker Desktop settingsInstall kubectl
# Linux
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install kubectl /usr/local/bin/kubectl
# Verify
kubectl version --client
kubectl cluster-infoYour First Deployment
Step 1: Create a Deployment
# app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
replicas: 3 # Run 3 copies
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: nginx:alpine # Your container image
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"# Apply it
kubectl apply -f app-deployment.yaml
# Check status
kubectl get deployments
kubectl get podsOutput:
NAME READY UP-TO-DATE AVAILABLE AGE
my-app 3/3 3 3 30s
NAME READY STATUS RESTARTS AGE
my-app-6d8f7b4d5-abc12 1/1 Running 0 30s
my-app-6d8f7b4d5-def34 1/1 Running 0 30s
my-app-6d8f7b4d5-ghi56 1/1 Running 0 30s
Step 2: Expose with a Service
# app-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app # Matches pods with this label
ports:
- protocol: TCP
port: 80 # Service port
targetPort: 80 # Container port
type: ClusterIP # Internal only (default)kubectl apply -f app-service.yaml
kubectl get servicesStep 3: Expose Externally
# For local development / cloud providers with load balancers
apiVersion: v1
kind: Service
metadata:
name: my-app-lb
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 80
type: LoadBalancer # External access# For minikube
minikube service my-app-lbScaling
Manual Scaling
# Scale to 5 replicas
kubectl scale deployment my-app --replicas=5
# Scale down to 2
kubectl scale deployment my-app --replicas=2
# Check
kubectl get pods -w # Watch modeAuto-Scaling (HPA)
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # Scale up when CPU > 70%kubectl apply -f hpa.yaml
kubectl get hpaConfiguration
ConfigMaps (Non-Sensitive Data)
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_HOST: "postgres.default.svc.cluster.local"
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"Secrets (Sensitive Data)
# Create from command line
kubectl create secret generic app-secrets \
--from-literal=DB_PASSWORD=supersecret \
--from-literal=API_KEY=abc123Using Config in Pods
spec:
containers:
- name: my-app
image: my-app:latest
envFrom:
- configMapRef:
name: app-config # All keys become env vars
- secretRef:
name: app-secrets
env:
- name: SPECIAL_VAR # Single value from ConfigMap
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVELIngress (HTTP Routing)
Ingress routes external HTTP/HTTPS traffic to services based on hostname or path.
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 8080
tls:
- hosts:
- myapp.example.com
secretName: tls-secret# Install ingress controller (minikube)
minikube addons enable ingress
# Apply
kubectl apply -f ingress.yamlRolling Updates and Rollbacks
Update Image
# Update to new version
kubectl set image deployment/my-app my-app=my-app:v2
# Watch the rollout
kubectl rollout status deployment/my-appOutput:
Waiting for deployment "my-app" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "my-app" rollout to finish: 2 out of 3 new replicas have been updated...
deployment "my-app" successfully rolled out
Rollback
# View history
kubectl rollout history deployment/my-app
# Rollback to previous version
kubectl rollout undo deployment/my-app
# Rollback to specific revision
kubectl rollout undo deployment/my-app --to-revision=2Rolling Update Strategy
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Max pods above desired count during update
maxUnavailable: 0 # Zero downtime — always keep all pods runningDebugging
Essential Commands
# Pod status
kubectl get pods -o wide
# Detailed pod info
kubectl describe pod my-app-6d8f7b4d5-abc12
# Container logs
kubectl logs my-app-6d8f7b4d5-abc12
kubectl logs -f my-app-6d8f7b4d5-abc12 # Follow/stream
# Execute command in pod
kubectl exec -it my-app-6d8f7b4d5-abc12 -- /bin/sh
# Port forward (access pod directly)
kubectl port-forward my-app-6d8f7b4d5-abc12 8080:80
# Get all resources in namespace
kubectl get all -n default
# Delete stuck pods
kubectl delete pod my-app-6d8f7b4d5-abc12 --grace-period=0 --forceCommon Issues
| Symptom | Check | Fix |
|---------|-------|-----|
| CrashLoopBackOff | kubectl logs <pod> | Fix app crash, check env vars |
| ImagePullBackOff | kubectl describe pod | Fix image name, check registry auth |
| Pending | kubectl describe pod | Check resources, node capacity |
| 0/1 Running | Readiness probe | Fix health check endpoint |
Health Checks
spec:
containers:
- name: my-app
image: my-app:latest
livenessProbe: # Is the container alive?
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe: # Is the container ready for traffic?
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
startupProbe: # Has the container started?
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 10Namespaces
# Create namespace
kubectl create namespace staging
# Deploy to namespace
kubectl apply -f deployment.yaml -n staging
# List pods in namespace
kubectl get pods -n staging
# Set default namespace
kubectl config set-context --current --namespace=stagingQuick Reference: kubectl Commands
# CRUD
kubectl get <resource> # List
kubectl describe <resource> <name> # Details
kubectl apply -f <file> # Create/update
kubectl delete -f <file> # Delete
# Shortcuts
kubectl get po # pods
kubectl get deploy # deployments
kubectl get svc # services
kubectl get ing # ingress
kubectl get ns # namespaces
kubectl get no # nodes
# Output formats
kubectl get pods -o wide # Extra columns
kubectl get pods -o yaml # Full YAML
kubectl get pods -o json # Full JSON
kubectl get pods --sort-by=.status.startTime
# Labels
kubectl get pods -l app=my-app # Filter by label
kubectl label pod my-pod env=production # Add labelWhat's Next?
Once you're comfortable with the basics:
- Helm — Package manager for Kubernetes (charts = reusable templates)
- Kustomize — Customize YAML without templates
- ArgoCD — GitOps continuous deployment
- Prometheus + Grafana — Monitoring and dashboards
- Istio / Linkerd — Service mesh for advanced networking
- Cert-Manager — Automatic TLS certificates
The key insight: Kubernetes is declarative. You tell it what you want (3 replicas, 80% CPU limit, rolling updates), and it figures out how to make it happen. Start simple, add complexity only when you need it.