You’ve containerized your app with Docker. It works great on one server. Now you need it on ten servers, with automatic scaling, rolling updates, and self-healing. Welcome to Kubernetes.
What Kubernetes Actually Does#
Kubernetes (K8s) is a container orchestrator. You tell it what you want — “run 3 copies of my app, keep them healthy, expose them to the internet” — and it figures out how to make that happen.
Think of it as a very capable operations team that never sleeps:
- Scheduling: Decides which server runs which container
- Scaling: Adds or removes containers based on demand
- Healing: Restarts crashed containers automatically
- Networking: Routes traffic to healthy containers
- Updates: Rolls out new versions without downtime
Core Concepts#
Pods#
The smallest unit in Kubernetes. A pod is one or more containers that share storage and network.
1
2
3
4
5
6
7
8
9
10
| apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 8080
|
Most of the time, you don’t create pods directly — you use Deployments.
Deployments#
Manages pods for you: how many replicas, how to update them, how to roll back.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 8080
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
|
Apply it:
1
| kubectl apply -f deployment.yaml
|
Kubernetes creates 3 pods, distributes them across nodes, and keeps them running.
Services#
Pods come and go. Services provide a stable endpoint to reach them.
1
2
3
4
5
6
7
8
9
10
11
| apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
type: ClusterIP
|
Service types:
- ClusterIP: Internal only (default)
- NodePort: Exposes on each node’s IP
- LoadBalancer: Creates cloud load balancer
Ingress#
Routes external HTTP traffic to services:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
|
Practical Example: Full Stack App#
Let’s deploy a web app with a database.
ConfigMap for Configuration#
1
2
3
4
5
6
7
| apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_HOST: "postgres-service"
DATABASE_NAME: "myapp"
|
Secret for Sensitive Data#
1
2
3
| kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=secretpass123
|
PostgreSQL Deployment#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: postgres-pvc
---
apiVersion: v1
kind: Service
metadata:
name: postgres-service
spec:
selector:
app: postgres
ports:
- port: 5432
|
Application Deployment#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: app
image: myapp:1.0
envFrom:
- configMapRef:
name: app-config
env:
- name: DATABASE_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
|
Essential kubectl Commands#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| # Get resources
kubectl get pods
kubectl get deployments
kubectl get services
kubectl get all
# Describe (detailed info)
kubectl describe pod my-app-xyz123
# Logs
kubectl logs my-app-xyz123
kubectl logs -f my-app-xyz123 # Follow
# Execute commands in pod
kubectl exec -it my-app-xyz123 -- /bin/sh
# Scale
kubectl scale deployment my-app --replicas=5
# Update image
kubectl set image deployment/my-app app=myapp:2.0
# Rollback
kubectl rollout undo deployment/my-app
# Delete
kubectl delete -f deployment.yaml
|
When to Use Kubernetes#
Good fit:
- Multiple services that need to communicate
- Variable load requiring auto-scaling
- Teams deploying independently
- Need for rolling updates and rollbacks
- Multi-cloud or hybrid deployments
Overkill for:
- Single application on one server
- Small teams without ops capacity
- Applications that rarely change
- When managed services (Lambda, App Engine) work
Getting Started Locally#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Install minikube
brew install minikube # macOS
# or
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
# Use kubectl
kubectl get nodes
# Deploy something
kubectl create deployment hello --image=nginx
kubectl expose deployment hello --port=80 --type=NodePort
minikube service hello
|
The Bottom Line#
Kubernetes is complex because distributed systems are complex. But the abstraction it provides — “run my containers, keep them healthy, handle the networking” — is powerful.
Start small. Deploy one app. Learn the basics. The complexity is there when you need it, but you don’t have to use it all on day one.
Questions about Kubernetes? Find me on Twitter.