The Mental Model
Kubernetes (k8s) is a system for running containers reliably at scale. It manages:
- Where containers run (which machines)
- How many copies run (scaling)
- What happens when a container crashes (self-healing)
- How traffic reaches them (networking)
Think of it as an operating system for your cluster, where containers are the processes.
The Core Objects
Pod
The smallest deployable unit. A Pod is one or more containers that share networking and storage.
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: myapp:1.0.0
ports:
- containerPort: 3000
You rarely create Pods directly โ Deployments manage them.
Deployment
A Deployment manages a set of identical Pods, handles rolling updates, and restarts crashed Pods:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3 # Run 3 copies
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: myapp:1.0.0
ports:
- containerPort: 3000
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
Service
A Service exposes your Pods on a stable network address. Pods come and go; Services are stable:
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app # Routes to all pods with this label
ports:
- port: 80
targetPort: 3000
type: ClusterIP # Internal only
Ingress
Routes external HTTP/HTTPS traffic to Services:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
Essential kubectl Commands
# Get resources
kubectl get pods
kubectl get deployments
kubectl get services
kubectl get all # everything in the namespace
# Describe a resource (detailed info + events)
kubectl describe pod my-app-abc123
# View logs
kubectl logs my-app-abc123
kubectl logs my-app-abc123 -f # follow (like tail -f)
kubectl logs -l app=my-app --all-containers # all pods with label
# Execute into a running pod
kubectl exec -it my-app-abc123 -- /bin/sh
# Apply a manifest
kubectl apply -f deployment.yaml
# Delete
kubectl delete -f deployment.yaml
kubectl delete pod my-app-abc123
# Scale
kubectl scale deployment my-app --replicas=5
# Rollout
kubectl rollout status deployment/my-app
kubectl rollout undo deployment/my-app # rollback
ConfigMaps and Secrets
Don't bake config into images. Use ConfigMaps and Secrets:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_URL: "postgres://db:5432/myapp"
LOG_LEVEL: "info"
---
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
stringData:
API_KEY: "your-api-key-here"
Reference them in your Deployment:
containers:
- name: app
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secrets
Resource Requests and Limits
Always set these. Without them, one pod can starve the entire node:
resources:
requests: # Minimum guaranteed
memory: "128Mi"
cpu: "100m" # 100 millicores = 0.1 CPU
limits: # Hard maximum
memory: "256Mi"
cpu: "500m"
Kubernetes uses requests for scheduling (which node to place the Pod on) and limits for enforcement.
Local Development with Kubernetes
# minikube: local single-node cluster
brew install minikube
minikube start
kubectl apply -f deployment.yaml
minikube service my-app-service --url
# k3d: lightweight local k3s cluster
brew install k3d
k3d cluster create dev
kubectl apply -f deployment.yaml
Key Takeaways
- Pod: smallest unit (usually 1 container)
- Deployment: manages N copies of a Pod, handles restarts and updates
- Service: stable network endpoint for a set of Pods
- Ingress: routes external HTTP traffic to Services
- Always set resource requests and limits
- Use ConfigMaps for config and Secrets for sensitive values
kubectl describeandkubectl logsare your debugging tools