Skip to main content

← 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: pytest

Build + 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.

Want to actually learn these patterns, not just paste them? Open the DevOps cheatsheet track — each snippet has a full lesson behind it.