← Master Index
Vol. 18 Module 18.2 Lecture

Docker

Backend & Infrastructure

How This Lesson Fits the Module & Volume

You can run FastAPI or Flask on a laptop. Production needs a reproducible process: same Python, same deps, same port, no “works on my CUDA driver.” Docker packages that process as an image. Module 18.3 will care about GPU images; here we containerize the API wrapper around Module 18.1 SDKs.

Next: Kubernetes runs many containers. Redis / Celery will appear as sibling containers in Compose. Do not confuse Docker with “we deployed”—see Deployment.

Learning Objectives

By the end of this lesson, students should be able to:

  • Explain image vs container vs registry in one sentence each.
  • Write a multi-stage-friendly Dockerfile for a FastAPI AI wrapper.
  • Pass secrets via env/runtime, never ENV OPENAI_API_KEY=sk-... in the image.
  • Use Compose to run API + Redis locally.
  • Know why GPU images (nvidia-container-toolkit) differ from CPU API images.
  • Hand a tagged image to Kubernetes without rewriting the app.
Definition

Docker is a container toolchain: a Dockerfile builds an image (immutable filesystem + default command); a container is a running instance isolated by the kernel (namespaces/cgroups). A registry (Docker Hub, GHCR, ECR) stores tagged images. Containers are not VMs; they share the host kernel. They are also not Kubernetes—K8s schedules containers.

What Goes in the Image

IncludeExclude
App code, requirements.txt / lockfileAPI keys, .env, customer data
Uvicorn/Gunicorn entrypoint--reload, Jupyter, A1111 checkpoints
Non-root user, pinned base digestlatest as a production pin if you can avoid it
HEALTHCHECK hitting /healthTraining datasets “just in case”

FastAPI Dockerfile + Compose Sketch

# Dockerfile FROM python:3.12-slim AS base WORKDIR /app ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . RUN useradd --create-home appuser && chown -R appuser /app USER appuser EXPOSE 8000 # keys injected at runtime: docker run -e OPENAI_API_KEY ... CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] # .dockerignore: .git, .env, __pycache__, *.pt, volumes/ # docker-compose.yml (API + Redis for later Celery/cache) # services: # api: # build: . # ports: ["8000:8000"] # environment: # OPENAI_API_KEY: ${OPENAI_API_KEY} # REDIS_URL: redis://redis:6379/0 # depends_on: [redis] # redis: # image: redis:7-alpine # docker build -t chat-api:0.1.0 . # docker run --rm -p 8000:8000 -e OPENAI_API_KEY -e REDIS_URL chat-api:0.1.0

CPU API Image vs GPU Runtime

This lecture (wrapper)

  • Slim Python + Uvicorn
  • Calls OpenAI/Anthropic/Gemini
  • No CUDA in the image

Self-host infer (18.3)

  • CUDA base or nvidia runtime
  • vLLM / TGI / Comfy worker
  • GPU + drivers on host

Compose vs K8s

  • Compose: laptop / single VM
  • K8s: replicas, probes, rollouts
  • Same image tag in both

Docker buys you

  • Reproducible deploys and CI
  • Parity: laptop ≈ staging process
  • Isolation from host Python chaos

Docker does not buy you

  • Auth, TLS, or cost meters by itself
  • Multi-node scheduling (Kubernetes)
  • A substitute for secret managers

Related Lectures

LectureRole
FastAPI / FlaskThe process inside the image
KubernetesRun many copies of this image
RedisSibling container in Compose
DeploymentRegistries, envs, rollouts
GPUWhen the image needs CUDA
Common Misconception

“I dockerized it, so it’s secure.” Images can still leak keys in layers (ENV, docker history, copied .env). Second: latest is not a version. Third: bind-mounting the host Docker socket into the app container is not a feature for students. Fourth: a 20 GB A1111 image is not the same job as a 150 MB FastAPI wrapper—do not cargo-cult GPU bases for a chat proxy.

Knowledge Check

  1. Short Answer: Image vs container? Answer: Image is the immutable template; container is a running instance.
  2. True/False: Bake OPENAI_API_KEY into the Dockerfile with ENV. Answer: False—inject at runtime / secret store.
  3. Multiple Choice: Typical API CMD: (a) uvicorn main:app --host 0.0.0.0 --port 8000, (b) jupyter notebook, (c) k-means. Answer: (a).
  4. Short Answer: Why a .dockerignore? Answer: Keep secrets, git, caches, and huge weights out of the build context.
  5. True/False: Docker is the same thing as Kubernetes. Answer: False—K8s schedules containers.
  6. Multiple Choice: Redis in Compose is usually: (a) a sibling service, (b) a sampler, (c) a LoRA. Answer: (a).
  7. Short Answer: Why run the process as a non-root user? Answer: Limit blast radius if the app is compromised.
  8. True/False: A CPU slim image is enough for an OpenAI-proxy API. Answer: True (no local GPU required).
  9. Multiple Choice: Next lecture: (a) Kubernetes, (b) Whisper, (c) PCA. Answer: (a).
  10. Short Answer: Name one thing Docker does not replace. Answer: Any of: authentication, TLS, monitoring, K8s scheduling, secret management.

Key Takeaways

  • Image = reproducible API process; container = running copy.
  • Slim Python + Uvicorn; secrets at runtime only.
  • Compose for API+Redis locally; same tag for K8s later.
  • GPU bases are for self-host infer, not chat proxies.
  • Next: Kubernetes.
Trainer’s Guide

Lab: Dockerize the FastAPI chat app. Prove .env is not in the image (docker history / exec env). Add Redis via Compose and print REDIS_URL from /health.

Whiteboard: Laptop Python vs image layers vs registry vs K8s Pod. Circle where the API key lives (runtime secret, not layer).

Recap: Docker packages the API. Orchestrate next with Kubernetes.