Docker packages an ML API together with its exact Python version, libraries, and system dependencies into one portable container — solving the classic "it works on my machine" problem for good.
Why Containerization Matters Specifically for ML
ML deployments are unusually sensitive to environment mismatches — a model trained with scikit-learn 1.3 can behave subtly differently, or fail to load entirely, under scikit-learn 1.5. Docker guarantees the exact same environment (library versions, system libraries, Python version) travels with the model from development through to production, eliminating an entire category of deployment failures.
A Complete Dockerfile
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY model_pipeline.pkl .
COPY main.py .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
# requirements.txt -- pin EXACT versions, not just library names
fastapi==0.111.0
uvicorn==0.30.0
scikit-learn==1.5.0
joblib==1.4.2
numpy==1.26.4
Building and Running
# Build the image
docker build -t loan-approval-api:1.2.0 .
# Run it, mapping the container's port to the host
docker run -p 8000:8000 loan-approval-api:1.2.0
# Test it
curl -X POST http://localhost:8000/predict -H "Content-Type: application/json" -d '{"income": 45000, "age": 34, "credit_score": 680}'
Why Pinning Exact Versions Matters
Writing scikit-learn in requirements.txt without a version number means every future build could silently pull whatever the latest scikit-learn happens to be at build time — potentially a version your model was never actually tested against. Pinning exact versions (scikit-learn==1.5.0) guarantees the container always reproduces the exact tested environment, indefinitely.
Multi-Stage Builds — Keeping Images Small
# A more advanced Dockerfile pattern that keeps the final image lean
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY model_pipeline.pkl main.py ./
ENV PATH=/root/.local/bin:$PATH
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Practical Use Cases
- Any production ML deployment — Docker is close to the industry-standard baseline for shipping ML services reliably
- Ensuring identical behavior across development, staging, and production environments
Common Mistakes
- Not pinning exact library versions in
requirements.txt, undermining the entire point of containerizing for reproducibility. - Building unnecessarily large images by including development tools, test files, or unused dependencies in the final container.
- Baking secrets (API keys, database credentials) directly into the image instead of injecting them as environment variables at runtime.
Interview Relevance
Q: "Why is reproducibility such a central concern for ML deployment specifically, more than for typical web apps?" A model's behavior can depend subtly on the exact versions of numeric libraries (scikit-learn, NumPy) it was trained and validated with — small version differences can change numeric results, not just cause an outright crash, making an unreproducible environment a genuine correctness risk, not just a compatibility inconvenience.
Practice Question
Explain why requirements.txt should specify scikit-learn==1.5.0 instead of just scikit-learn, in the context of a containerized ML deployment.