Docker — ML-এর জন্য container
এই পাঠে যা শিখবেন
- 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
# 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"]
--no-cache-dir — image size ছোট।
৩ · Multi-stage build — slim production image
Training-এর জন্য heavy dependencies (jupyter, debugpy, build tools) দরকার। Production-এ লাগে না। Multi-stage build দু'টো ভিন্ন context গড়ে।
# 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"]
৪ · 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।
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"]
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।
ভাবনার প্রশ্ন
প্র ০১ "আমার 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:
- Host NVIDIA driver: kernel-level, host machine-এ install। CUDA version-এর support window decide করে।
- Container CUDA toolkit: image-এ। User-space CUDA libraries, math kernels।
- 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-smion 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.ymlcombo।
মূল উপলব্ধি: 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-এ বিপজ্জনক।
অনুশীলন
-
লিখুন: একটি 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/ -
Convert: উপরের Dockerfile-কে multi-stage-এ রূপান্তর করুন।
উপরের section ৩-এর pattern follow করুন। Builder stage = wheels build, runtime = wheels install।
-
চিন্তা: আপনার GPU model image ৬ GB। ৩ ধাপে কীভাবে ৪ GB-এ নামাবেন?
- (১)
runtimebase নিন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।
- (১)