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.
- (১)