Skip to content

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"]
- Pin base images - Keep layers minimal - Use .dockerignore to avoid sending unnecessary files - Never bake secrets into images

Security & Scanning

trivy image ghcr.io/org/app:1.0
- Run as non-root - Read-only root filesystem when possible - Drop unnecessary Linux capabilities


☸️ 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
Mount in pod:
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