পাঠ ৬ · ৩৩-এর মধ্যে · মডিউল ১
Home / AI Courses / MLOps / Docker for ML

Docker — ML-এর জন্য container

Docker for ML — reproducible containers
৮ মিনিট পড়া মধ্য · Intermediate Dockerfile

এই পাঠে যা শিখবেন

  • ML-এর জন্য Dockerfile-এর সাধারণ structure
  • Multi-stage build — image size optimization
  • GPU container — CUDA, cuDNN base image
  • Security baseline — non-root user, image scan

১ · কেন Docker, কেন container

একজন data scientist-এর laptop-এ মডেল চলে; production server-এ চলে না। কারণ — Python version, OS lib, CUDA version — কিছু না কিছু ভিন্ন। Docker এই সমস্যা solve করে — পুরো environment-কে একটি container imageContainer Imageএকটি portable, immutable bundle — OS subset + runtime + libraries + code। Docker এর জনপ্রিয় engine।-এ bundle।

  • Reproducibility: "my-image:v1.2.3" — যেকোনো machine-এ same behavior।
  • Portability: laptop, CI server, K8s cluster — সব জায়গায় চালু।
  • Isolation: dependency conflict অন্য container-কে effect করে না।

২ · ML-এর জন্য একটি minimal Dockerfile

Dockerfile · Minimal CPU image
# slim base — ছোট, কিন্তু python-ready
FROM python:3.11.7-slim AS runtime

# system dep (যদি দরকার, যেমন libgomp ML libraries-এর জন্য)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libgomp1 \
    && rm -rf /var/lib/apt/lists/*

# non-root user (security)
RUN useradd --create-home --shell /bin/bash mluser
WORKDIR /app

# dependency layer আগে — caching benefit
COPY requirements.lock /app/requirements.lock
RUN pip install --no-cache-dir -r requirements.lock

# app code
COPY --chown=mluser:mluser . /app
USER mluser

# health & entrypoint
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

    
চারটি গুরুত্বপূর্ণ pattern: (১) pinned base image, (২) requirements layer আগে — code change হলেও pip install cache, (৩) non-root user, (৪) --no-cache-dir — image size ছোট।

৩ · Multi-stage build — slim production image

Training-এর জন্য heavy dependencies (jupyter, debugpy, build tools) দরকার। Production-এ লাগে না। Multi-stage build দু'টো ভিন্ন context গড়ে।

Dockerfile · Multi-stage
# Stage 1 — builder (heavy, with compilers)
FROM python:3.11.7-slim AS builder

RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential gcc \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /build
COPY requirements.lock .
# wheel ফাইল pre-build করি
RUN pip wheel --no-cache-dir -r requirements.lock -w /wheels

# Stage 2 — runtime (slim, no compilers)
FROM python:3.11.7-slim AS runtime

RUN apt-get update && apt-get install -y --no-install-recommends \
    libgomp1 \
    && rm -rf /var/lib/apt/lists/*

RUN useradd --create-home --shell /bin/bash mluser
WORKDIR /app

# wheel-গুলো installed
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir --no-index --find-links=/wheels /wheels/*.whl \
    && rm -rf /wheels

COPY --chown=mluser:mluser app/ /app/
USER mluser
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

    
Builder stage compiler/headers carries। Runtime image-এ শুধু wheels copy হয় — compiler থাকে না। ফলে production image ৩০০ MB থেকে ৮০ MB-তে নামতে পারে।

৪ · GPU container — CUDA base image

Deep learning model GPU-তে train ও infer। Python packages CUDA-aware হলেও — host-এ proper driver + container-এ CUDA runtime দরকার।

  • Base image: nvidia/cuda:12.1.0-cudnn8-runtime-ubuntu22.04 (inference) or ...-devel-... (training)।
  • Host: NVIDIA driver compatible version + nvidia-container-toolkit।
  • Run: docker run --gpus all my-image।
  • K8s: GPU resource request nvidia.com/gpu: 1।
Dockerfile · GPU PyTorch
FROM nvidia/cuda:12.1.0-cudnn8-runtime-ubuntu22.04

ENV DEBIAN_FRONTEND=noninteractive \
    PYTHONUNBUFFERED=1

RUN apt-get update && apt-get install -y --no-install-recommends \
    python3.11 python3-pip libgomp1 \
    && ln -sf /usr/bin/python3.11 /usr/bin/python \
    && rm -rf /var/lib/apt/lists/*

RUN useradd --create-home mluser
WORKDIR /app

COPY requirements.lock .
RUN pip install --no-cache-dir torch==2.2.0 --index-url https://download.pytorch.org/whl/cu121 \
    && pip install --no-cache-dir -r requirements.lock

COPY --chown=mluser:mluser . /app/
USER mluser
CMD ["python", "serve.py"]

    
Note: PyTorch CUDA wheel আলাদা index URL থেকে — cu121 = CUDA 12.1। Image বিশাল হয় (২-৪ GB) — multi-stage এখানে কম effective, কারণ wheels-ই বিশাল। Better — separate base image team-wide।

৫ · Image size optimization

  • slim/alpine base: python:3.11-slim ~১২০ MB; alpine ~৪০ MB কিন্তু ML-এ glibc compatibility issues।
  • --no-cache-dir: pip cache না রাখা।
  • Multi-stage: compilers throw away।
  • .dockerignore: .git, tests, notebooks, data — image-এ যাবে না।
  • Layer ordering: rare-change first (system deps), frequent-change last (code)।
  • Buildkit: parallel layer + cache mount — faster + smaller।

৬ · Security baseline

  • Non-root user: default root → mluser। Container escape-এর mitigation।
  • Read-only filesystem: K8s deployment-এ readOnlyRootFilesystem: true।
  • Image scanning: Trivy, Grype — known CVE check।
  • Pin base image SHA: tag mutable হতে পারে; @sha256:... immutable।
  • No secrets in image: API key, DB password — env var বা secret manager।
  • Distroless base: Google distroless — minimum, no shell, super-secure।
Multi-stage Docker build for ML Builder (heavy) → Runtime (slim) Stage 1 · Builder ~৮০০ MB FROM python:3.11-slim apt: gcc, build-essential pip wheel → /wheels/*.whl ⚙️ compile, build, prepare Stage 2 · Runtime ~১২০ MB (target) FROM python:3.11-slim COPY --from=builder /wheels non-root user, app code 🚀 production-ready, slim /wheels Compilers থাকে stage 1-এ; final image-এ যায় না — ৮০-৯০% size reduction।
Multi-stage build — ১ম stage-এ heavy build tools, ২য় stage-এ শুধু runtime artifacts। Image size ৮০-৯০% reduce, security surface কমে।
ML-এর জন্য Docker একটি essential skill। MLOps maturity Level 1+ পর্যায়ে আপনার প্রতিটি training run, প্রতিটি serving — Docker-এ চলবে। যত আগে কঠিন বুঝবেন — পরের পাঠগুলো তত সহজ।

ভাবনার প্রশ্ন

প্র ০১ "আমার Docker image ৫ GB। এটা সমস্যা?" — কখন size matters, কখন matter করে না?

Image size সবসময় optimize করার দরকার নেই — context-dependent।

সমস্যা যখন:

  • Cold start: Lambda/Fargate/serverless — ৫ GB image pull-এ ১-২ মিনিট। User-facing এ unacceptable।
  • Auto-scaling: traffic spike → নতুন pod start → image pull → response delay।
  • Edge deployment: mobile/IoT — bandwidth limited। ৫ GB unusable।
  • Cost: registry storage cost (ECR ~$০.১/GB/month)। ১০০টি model × ৫ GB = ৫০ GB = $৫/month — small but accumulates।

সমস্যা না যখন:

  • Dedicated long-running pod: K8s deployment image once-pull, container days run।
  • Internal batch job: nightly training, latency irrelevant।
  • GPU image inherent size: CUDA + cuDNN + PyTorch GPU = ৩ GB minimum। আরও কমানো effortless না।

Optimization approach:

  • First — dive into layers: docker history my-image। কোন layer কত MB।
  • Common waste: apt cache, pip cache, build artifacts, .git, test files, sample notebooks।
  • Diminishing returns: ৫ GB → ৩ GB easy। ৩ GB → ২ GB possible। ২ GB → ১ GB অনেক effort।

"Layer caching" benefit:

  • ৫ GB image-এ shared layers (CUDA, PyTorch) cached at registry এবং pull caching।
  • "My ৫ GB image-এ ৪ GB CUDA — shared with ৫০ অন্য image" → effective per-image cost ~১ GB।
  • ECR/GCR-এ caching — second pull অনেক fast।

Bangladesh context:

  • Local data center / cloud — bandwidth ক্ষেত্রে cost matter। On-prem, image registry close → less concerned।
  • BD-host server-এ AWS Mumbai pull → not super fast — image cache critical।

Concrete decision tree:

  • Cold start matters → minimize aggressively।
  • Long-running pod, on-prem cache → 5 GB acceptable।
  • CI/CD bottleneck → optimize layer caching first।

মূল উপলব্ধি: Image size একটি engineering trade-off — premature optimization waste। First measure (cold start time, deployment frequency, user impact)। Then optimize where it actually hurts। GPU image-এ "৫ GB normal" — অহেতুক shame না।

প্র ০২ "CUDA version mismatch" — host driver, container CUDA, PyTorch CUDA — কে কোনটা control করে?

GPU container-এর সবচেয়ে confusing দিক — ৩-layered version dependency।

৩-tier version structure:

  1. Host NVIDIA driver: kernel-level, host machine-এ install। CUDA version-এর support window decide করে।
  2. Container CUDA toolkit: image-এ। User-space CUDA libraries, math kernels।
  3. Framework CUDA build: PyTorch / TensorFlow CUDA-targeted wheel।

Compatibility rules:

  • Driver-CUDA forward compatible: driver 525 → CUDA 11.8, 12.0, 12.1 all OK।
  • Driver minimum: CUDA 12.1 → minimum driver 525।
  • Framework-CUDA exact: PyTorch built for CUDA 11.8 — works with CUDA 11.8 ও 12.x runtime usually। But "minor version drift" সাধারণত fine, "major" drift sometimes break।

Common scenarios:

  • Newer driver, older container CUDA: usually works (forward compat)।
  • Older driver, newer container CUDA: fails — driver too old।
  • Driver mismatch on K8s nodes: node taint দিয়ে handle।

Diagnosis tools:

  • nvidia-smi on host → driver + max CUDA supported।
  • docker run --gpus all nvidia/cuda:12.1.0-base nvidia-smi → container সদর-দর্শন।
  • python -c "import torch; print(torch.version.cuda)" → PyTorch's bundled CUDA।
  • torch.cuda.is_available() → end-to-end check।

Common pitfalls:

  • Mixed driver across nodes: node-A driver 525, node-B driver 470। Workload schedule random, sometimes fail।
  • Spot/preemptible-এ random GPU: A100 vs T4 — different compute capability।
  • Reboot reset: driver upgrade-এর পর reboot না হলে — old driver runtime, new claim।

Best practice:

  • Image-এ explicit CUDA version pin (e.g., nvidia/cuda:12.1.0-cudnn8-runtime-ubuntu22.04)।
  • PyTorch wheel matching CUDA index URL।
  • Cluster-wide driver standardize।
  • Health check: container start-এ torch.cuda.is_available() assert।

মূল উপলব্ধি: CUDA stack একটি onion — host driver outer-most, container CUDA middle, framework innermost। ভিতরের ভিতরের লেয়ার বদলালে সহজে দেখা যায় না; outer change সব ভিতরের impact। Driver-CUDA-PyTorch combo lock down — ব্যর্থ deployment-এর সবচেয়ে common cause এড়ানো।

প্র ০৩ "Docker Compose ML dev-এ ব্যবহার করা উচিত?" — কখন good, কখন overkill?

Docker Compose একটি multi-container orchestration tool — single host-এ। ML dev-এ ব্যবহার common, কিন্তু সঠিক context চাই।

ML dev-এ Compose কোথায় valuable:

  • Multi-service local stack: MLflow server + PostgreSQL backend + MinIO artifact store + your training code — চারটি service এক docker compose up-এ।
  • Reproducible team environment: নতুন engineer "git clone + docker compose up" — ১৫ মিনিটে full local environment।
  • Database/cache dependency: Redis, Postgres, RabbitMQ — Compose-এ pre-configured।
  • Integration testing: CI-তে full stack run, end-to-end test।

Compose overkill যখন:

  • Single training script: docker run my-image train.py — simpler।
  • Notebook-only workflow: Jupyter container alone যথেষ্ট।
  • K8s production target: Compose ↔ K8s manifest ভিন্ন। প্রায়ই duplicate maintenance।

Production-এ Compose না:

  • Compose single-host orchestrator। Scale, fault tolerance, rolling update — K8s-এর কাজ।
  • "docker-compose.prod.yml" anti-pattern — production-এ K8s বা ECS।

Bangladesh dev team common setup:

  • compose.yml-এ: model service + MLflow + Postgres + MinIO + Adminer।
  • GPU support: deploy.resources.reservations.devices।
  • Volume mount: code change → live reload।

Common Compose anti-patterns in ML:

  • Service-এ health check absent — depends_on race condition।
  • Volume permissions wrong — host write, container read fail।
  • Hardcoded ports — multiple project-এ port collision।

Alternative — devcontainer (VS Code):

  • Compose + IDE integration। Single click "open in container"।
  • .devcontainer/devcontainer.json + compose.yml combo।

মূল উপলব্ধি: Compose ML local dev-এ চমৎকার tool — multi-service stack-এ। Production-এ ব্যবহার-এর জন্য না। Compose vs K8s — single-host vs cluster-orchestration। দুটো-ই ML lifecycle-এ আছে, ভিন্ন stage-এ।

প্র ০৪ ML container-এ security কী কী আলাদা চিন্তা — DevOps-এর তুলনায়?

ML container security অনেকটা DevOps-এর সাথে overlap, কিন্তু ML-specific দিক আছে।

Common with DevOps (অবশ্যই করুন):

  • Non-root user।
  • Minimal base image (slim/distroless)।
  • Pinned base image SHA।
  • Image vulnerability scan (Trivy, Grype)।
  • No secrets in image।
  • Read-only filesystem in K8s।

ML-specific concerns:

(১) Model file as attack surface:

  • Pickle deserialization → arbitrary code execution। Untrusted .pkl load করবেন না।
  • সমাধান: SafeTensors, ONNX — safer formats।
  • Model registry-তে provenance + signature।

(২) Training data privacy:

  • Training image-এ data leak — hard-coded path, accidentally COPY।
  • Data fetch runtime-এ — image-এ না।
  • PII handling: NID, mobile, address — encrypt at rest, no log of raw।

(৩) GPU resource control:

  • Multi-tenant cluster-এ — GPU resource limit।
  • Memory limit miss → noisy neighbor crash।
  • K8s GPU operator + resource limit।

(৪) Adversarial input:

  • Prediction API public হলে — adversarial inputs (perturbed images, prompt injection)।
  • Input validation, rate limit, monitoring।
  • "Tricky inputs"-এর telemetry — pattern detect।

(৫) Model extraction attack:

  • Public API queried-এ model recreate করা possible (model stealing)।
  • Mitigation: rate limit, query logging, prediction differential privacy।

(৬) Supply chain — pre-trained model:

  • Hugging Face থেকে download — untrusted source।
  • Pickle-based model এ embedded malicious code possible।
  • SafeTensors prefer, signature check।

(৭) PyPI typosquatting:

  • "tensorflo" বা "scikit-learner" — fake package।
  • Lock file + hash verify।

Bangladesh-context-এ practical note:

  • Bangladesh Bank ২০২৩ guideline — financial AI-এর encryption + audit log mandate।
  • Personal Data Protection Act (২০২৩ draft) — data lineage track।
  • Global model use (OpenAI, Anthropic API) — data export concern।

মূল উপলব্ধি: ML container security DevOps-এর foundation + extra layers। Pickle attack, model provenance, adversarial input — ML-specific। Bangladesh-এ regulation evolving — early adoption ভাল। "Ship and worry later" — ML security-এ বিপজ্জনক।

অনুশীলন

  1. লিখুন: একটি minimal Python ML script-এর জন্য Dockerfile লিখুন। Multi-stage না, কিন্তু non-root + pinned base + .dockerignore include করুন।
    FROM python:3.11.7-slim
    RUN useradd --create-home mluser
    WORKDIR /app
    COPY requirements.lock .
    RUN pip install --no-cache-dir -r requirements.lock
    COPY --chown=mluser:mluser . .
    USER mluser
    CMD ["python", "main.py"]

    .dockerignore: .git, .venv, __pycache__, notebooks/, data/, tests/

  2. Convert: উপরের Dockerfile-কে multi-stage-এ রূপান্তর করুন।

    উপরের section ৩-এর pattern follow করুন। Builder stage = wheels build, runtime = wheels install।

  3. চিন্তা: আপনার GPU model image ৬ GB। ৩ ধাপে কীভাবে ৪ GB-এ নামাবেন?
    • (১) runtime base নিন devel-এর বদলে — ১.৫ GB save।
    • (২) Multi-stage — pip wheel build stage 1-এ, install stage 2-এ — কিছু MB।
    • (৩) --no-cache-dir + rm -rf /var/lib/apt/lists/* + .dockerignore — ৩০০-৫০০ MB।

আরও পড়ুন

পূর্ববর্তী পাঠ
পাঠ ৫ · Reproducibility