← All cheatsheets · Track →
🚀Updated 2026-05
DevOps cheatsheet — Docker, CI/CD, K8s, observability
Patterns from the DevOps for Python services track. Skip the trivia, ship something the on-call would approve of.
Docker
Multi-stage build
Slim production image — no build tools in final layer.
FROM python:3.12-slim AS base
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
.dockerignore
Don't copy `.git`, `__pycache__`, secrets into the image.
.git
__pycache__
*.pyc
.env
node_modules
.venv
Healthcheck
Docker / k8s probes need a real endpoint to call.
HEALTHCHECK --interval=30s --timeout=3s CMD curl -fsS http://localhost:8000/health || exit 1
Non-root user
Drop privileges before CMD.
RUN adduser --disabled-password app
USER app
GitHub Actions
Test on push
Bare minimum CI.
name: test
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -r requirements.txt
- run: pytestBuild + push image
Build to GHCR on every tag.
on:
push:
tags: ["v*"]
jobs:
publish:
runs-on: ubuntu-latest
permissions: { packages: write }
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with: { registry: ghcr.io, username: ${{ github.actor }}, password: ${{ secrets.GITHUB_TOKEN }} }
- uses: docker/build-push-action@v6
with: { push: true, tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }} }Kubernetes
Deployment
Declarative replica set, the everyday k8s object.
apiVersion: apps/v1
kind: Deployment
metadata: { name: api }
spec:
replicas: 3
selector: { matchLabels: { app: api } }
template:
metadata: { labels: { app: api } }
spec:
containers:
- name: api
image: ghcr.io/me/api:v1
ports: [{ containerPort: 8000 }]
readinessProbe: { httpGet: { path: /health, port: 8000 } }Rolling update
Default strategy — no downtime when replicas ≥ 2.
spec:
strategy:
type: RollingUpdate
rollingUpdate: { maxUnavailable: 0, maxSurge: 1 }Rollback
Roll back a bad deploy in one command.
kubectl rollout undo deployment/api
kubectl rollout status deployment/api
Secrets
Never bake secrets into the image.
kubectl create secret generic api-env \
--from-literal=DATABASE_URL=postgres://...
Observability
Prometheus client
Expose `/metrics` so Prometheus can scrape.
from prometheus_client import Counter, make_asgi_app
REQS = Counter("api_requests_total", "Total HTTP requests")
app.mount("/metrics", make_asgi_app())Structured logging
JSON to stdout — your log collector does the rest.
import logging, json
class JsonFmt(logging.Formatter):
def format(self, r):
return json.dumps({"lvl": r.levelname, "msg": r.getMessage(), "ts": r.created})
h = logging.StreamHandler(); h.setFormatter(JsonFmt())
logging.basicConfig(level=logging.INFO, handlers=[h])USE method
Utilization, Saturation, Errors — for resources (CPU, disk, network).
# Pair with RED for services; USE for the infra under them.