Docker & Kubernetes¶
Practical commands, configurations, and patterns for containerizing apps and running them reliably in Kubernetes.
π³ Docker Essentials¶
Build, Run, Exec, Logs¶
# Build image
docker build -t app:1.0 .
# Run container (map port 8080)
docker run --name app -p 8080:8080 -e ENV=dev app:1.0
# Shell into container
docker exec -it app /bin/sh
# Follow logs
docker logs -f app
Images & Registries (GitHub Container Registry example)¶
# Login to GHCR
echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_USER --password-stdin
# Tag & push
docker tag app:1.0 ghcr.io/YOUR_ORG/app:1.0
docker push ghcr.io/YOUR_ORG/app:1.0
Volumes & Networks¶
# Create named volume
docker volume create appdata
docker run -v appdata:/var/lib/app app:1.0
# Create network & connect containers
docker network create appnet
docker run --network appnet --name api api:1.0
docker run --network appnet --name web -e API_URL=http://api:8080 web:1.0
Compose Example (dev setup)¶
docker-compose.yml
version: "3.9"
services:
api:
image: ghcr.io/org/api:1.0
ports: ["8080:8080"]
env_file: [.env]
web:
image: ghcr.io/org/web:1.0
ports: ["3000:3000"]
environment:
API_URL: "http://api:8080"
depends_on: [api]
docker compose up -d
docker compose logs -f
docker compose down -v
Dockerfile Best Practices¶
FROM python:3.12-slim
WORKDIR /app
RUN useradd -m appuser
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER appuser
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
EXPOSE 8080
CMD ["python", "main.py"]
.dockerignore to avoid sending unnecessary files
- Never bake secrets into images
Security & Scanning¶
trivy image ghcr.io/org/app:1.0
βΈοΈ Kubernetes Essentials¶
Contexts & Namespaces¶
kubectl config get-contexts
kubectl config use-context prod
kubectl create namespace payments
kubectl -n payments get pods
Deployment + Service¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: ghcr.io/org/web:1.2.3
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
targetPort: 8080
type: ClusterIP
Ingress Example¶
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations:
kubernetes.io/ingress.class: alb # or nginx
alb.ingress.kubernetes.io/scheme: internet-facing
spec:
rules:
- host: web.prod.sregeeks.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
ConfigMaps & Secrets¶
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
data:
ENV: "prod"
---
apiVersion: v1
kind: Secret
metadata:
name: web-secrets
type: Opaque
stringData:
DB_PASSWORD: "change-me"
Rollouts & Scaling¶
kubectl apply -f deploy.yaml
kubectl rollout status deployment/web
kubectl rollout undo deployment/web
kubectl scale deployment/web --replicas=5
Storage with PVC¶
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 20Gi
volumeMounts:
- name: data
mountPath: /var/lib/app
volumes:
- name: data
persistentVolumeClaim:
claimName: data-pvc
Observability Commands¶
kubectl top nodes
kubectl -n prod top pods
kubectl -n prod get events --sort-by=.metadata.creationTimestamp | tail
kubectl -n prod logs -f deploy/web
kubectl -n prod exec -it deploy/web -- sh
Resilience & Scheduling¶
# Anti-affinity to spread pods
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app: web
# Resource requests/limits
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
Network Policies¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: prod
spec:
podSelector: {}
policyTypes: ["Ingress","Egress"]
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-web-to-api
namespace: prod
spec:
podSelector:
matchLabels:
app: web
policyTypes: ["Egress"]
egress:
- to:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 8080
Helm Quickstart¶
values.yaml
image:
repository: ghcr.io/org/web
tag: "1.2.3"
replicaCount: 3
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: alb
hosts:
- host: web.prod.sregeeks.com
paths:
- /
helm upgrade --install web charts/web -f values.yaml -n prod
Checklist Before Production: - β Probes configured and passing - β Resource limits set - β β₯3 replicas on β₯2 nodes - β PodDisruptionBudget set - β NetworkPolicies in place - β SLO dashboards & alerts configured