পাঠ ৬ · ৩৩-এর মধ্যে · মডিউল ১
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