Docker Coding Reference — AI Engineers Edition
⌨️
DOCKER
Complete Coding Reference
Every Command, Every Flag, Real AI/ML Code — Fully Explained
DOCUMENT 2 OF 2 — CODE
Page 1 of 25
Docker Coding Reference — AI Engineers Edition
Section 1: Essential Docker Commands — Every Flag
Explained
1.1 docker run — The Most Important Command
docker run creates a container from an image and starts it. It is shorthand for docker create +
docker start combined. It has dozens of flags — here are all the important ones:
# Full syntax:
docker run [OPTIONS] IMAGE [COMMAND] [ARGS...]
# ── Identity & Naming ───────────────────────────────────────────
--name my-container # Give it a human-readable name (else random)
--hostname ml-server # Set container's hostname inside
# ── Detached / Interactive ─────────────────────────────────────
-d # Detached mode: run in background, print container ID
-it # Interactive + pseudo-TTY: for shell access
--rm # Auto-remove container when it exits (great for tests)
# ── Port Mapping ───────────────────────────────────────────────
-p 8080:8000 # Host port 8080 → container port 8000
-p [Link]:8080:8000 # Bind to localhost only (more secure)
-P # Publish ALL exposed ports to random host ports
# ── Volume Mounts ──────────────────────────────────────────────
-v myvolume:/app/data # Named volume mount
-v $(pwd)/src:/app/src # Bind mount (current dir/src → /app/src)
-v /data/models:/models:ro # Read-only bind mount (:ro flag)
--tmpfs /tmp # RAM-backed temporary filesystem (lost on stop)
# ── Environment Variables ─────────────────────────────────────
-e MY_VAR=value # Set single environment variable
--env-file .env # Load all vars from a .env file
# ── Resource Limits ─────────────────────────────────────────
--memory=8g # Hard RAM limit (container killed if exceeded)
--memory-swap=16g # Total memory+swap limit
--cpus=4 # Limit to 4 CPU cores (can be fractional: 0.5)
--cpu-shares=512 # Relative CPU weight (default 1024)
# ── GPU Access ───────────────────────────────────────────────
--gpus all # All GPUs
--gpus 1 # One GPU
--gpus "device=0,1" # Specific GPU IDs
# ── Network ─────────────────────────────────────────────────
--network mynet # Attach to user-defined network
--network host # Share host network stack (no isolation)
--network none # No network at all
--add-host=mydb:[Link] # Add entry to /etc/hosts
--dns=[Link] # Custom DNS server
Page 2 of 25
Docker Coding Reference — AI Engineers Edition
# ── Security ────────────────────────────────────────────────
--user 1001:1001 # Run as UID:GID (non-root)
--read-only # Mount root filesystem as read-only
--cap-drop=ALL # Drop all Linux capabilities
--cap-add=NET_BIND_SERVICE # Add back only what's needed
--security-opt=no-new-privileges # Prevent privilege escalation
# ── Restart Policy ──────────────────────────────────────────
--restart=no # Never restart (default)
--restart=always # Always restart (even on docker daemon restart)
--restart=unless-stopped # Always restart unless manually stopped
--restart=on-failure:3 # Restart on non-zero exit, max 3 times
# ── Real-world AI model server example:
docker run -d \
--name model-api \
--gpus all \
--memory=16g \
--cpus=8 \
-p [Link]:8000:8000 \
-v model-weights:/app/models \
-e MODEL_NAME=llama-3-8b \
--env-file .[Link] \
--restart=unless-stopped \
--network ai-stack \
my-model-api:v1.2.3
1.2 docker build — Building Images
docker build reads a Dockerfile and creates an image. Every flag matters for production builds:
# Basic build (. = build context is current directory):
docker build -t myimage:v1.0 .
# Full syntax:
docker build [OPTIONS] PATH | URL | -
# ── Tagging ─────────────────────────────────────────────────
-t myimage:latest # Name and tag the output image
-t myimage:v1.0 -t myimage:latest # Multiple tags at once
# ── Dockerfile location ─────────────────────────────────────
-f ./docker/[Link] # Use specific Dockerfile (default: ./Dockerfile)
# ── Multi-stage builds ──────────────────────────────────────
--target builder # Stop at 'builder' stage (don't build final)
# ── Build arguments ─────────────────────────────────────────
--build-arg PYTHON_VER=3.11 # Pass ARG values (defined in Dockerfile)
--build-arg MODEL_URL=[Link]
# ── Cache control ───────────────────────────────────────────
Page 3 of 25
Docker Coding Reference — AI Engineers Edition
--no-cache # Ignore all cached layers (full rebuild)
--cache-from myimage:latest # Use a remote image as cache source (CI/CD)
# ── Platform / Architecture ─────────────────────────────────
--platform linux/amd64 # Build for x86 (default on most machines)
--platform linux/arm64 # Build for ARM (Apple M-series, Graviton)
--platform linux/amd64,linux/arm64 # Multi-arch (with buildx)
# ── Output ─────────────────────────────────────────────────
--push # Push directly to registry after build
--load # Load into local Docker (with buildx)
--squash # Squash all layers into one (loses cache)
# ── Progress ────────────────────────────────────────────────
--progress=plain # Show full build output (good for debugging)
--progress=auto # Default: condensed output
# CI/CD production build example:
docker build \
-t myrepo/model-api:${GIT_SHA} \
-t myrepo/model-api:latest \
-f [Link] \
--build-arg PYTHON_VERSION=3.11.9 \
--cache-from myrepo/model-api:latest \
--platform linux/amd64 \
--push \
.
1.3 Container Management Commands
# ── Listing ─────────────────────────────────────────────────
docker ps # Running containers
docker ps -a # ALL containers (including stopped)
docker ps --format 'table {{.Names}} {{.Status}} {{.Ports}}'
# ── Starting / Stopping ─────────────────────────────────────
docker start mycontainer # Start a stopped container
docker stop mycontainer # Send SIGTERM, wait 10s, then SIGKILL
docker stop -t 30 mycontainer # Wait 30s before SIGKILL (for slow cleanup)
docker kill mycontainer # SIGKILL immediately (no graceful shutdown)
docker restart mycontainer # Stop + Start
docker pause mycontainer # Freeze (SIGSTOP all processes)
docker unpause mycontainer # Unfreeze
# ── Removal ─────────────────────────────────────────────────
docker rm mycontainer # Remove stopped container
docker rm -f mycontainer # Force remove (even if running)
docker rm $(docker ps -aq) # Remove ALL stopped containers
# ── Inspection / Debugging ──────────────────────────────────
docker logs mycontainer # Show stdout/stderr from container
docker logs -f mycontainer # Follow (stream) logs in real time
docker logs --tail=100 mycontainer # Last 100 lines
Page 4 of 25
Docker Coding Reference — AI Engineers Edition
docker logs --since=1h mycontainer # Logs from last 1 hour
docker exec -it mycontainer bash # Open shell INSIDE running container
docker exec mycontainer python -c 'import torch; print(torch.__version__)'
docker exec -u root mycontainer bash # Enter as root even if USER is set
docker inspect mycontainer # Full JSON metadata (IPs, mounts, config)
docker inspect mycontainer | python -m [Link] # Pretty-print
docker inspect -f '{{.[Link]}}' mycontainer
docker stats # Live CPU/RAM/NET/IO for all running containers
docker stats --no-stream # One-time snapshot (good for scripts)
docker top mycontainer # Processes running inside container
docker port mycontainer # Port mappings
docker diff mycontainer # Files changed in container layer
# ── Copying files ────────────────────────────────────────────
docker cp mycontainer:/app/[Link] ./[Link] # Container→Host
docker cp ./[Link] mycontainer:/app/[Link] # Host→Container
1.4 Image Management Commands
# ── Listing & Searching ─────────────────────────────────────
docker images # List local images
docker images -a # Include intermediate layers
docker image ls --filter dangling=true # Untagged leftover images
docker search pytorch # Search Docker Hub
# ── Pulling & Pushing ───────────────────────────────────────
docker pull python:3.11-slim # Pull specific tag
docker pull python@sha256:abc123... # Pull by digest (reproducible)
docker push myrepo/myimage:v1.0 # Push to registry
# ── Tagging ─────────────────────────────────────────────────
docker tag myimage:v1 myrepo/myimage:v1 # Add tag to existing image
docker tag myimage:v1 myrepo/myimage:latest
# ── Inspection ──────────────────────────────────────────────
docker inspect python:3.11-slim # Full image metadata
docker history myimage:v1 # Show all layers and their sizes
docker image inspect -f '{{.[Link]}}' python:3.11 # View ENVs
# ── Removal & Cleanup ───────────────────────────────────────
docker rmi myimage:v1 # Remove image
docker rmi -f myimage:v1 # Force remove (even if tagged)
docker image prune # Remove dangling (untagged) images
docker image prune -a # Remove ALL unused images
docker system prune # Remove stopped
containers+networks+dangling images
docker system prune -a --volumes # Nuclear option: clean EVERYTHING
docker system df # Show disk usage breakdown
# ── Registry Login ──────────────────────────────────────────
Page 5 of 25
Docker Coding Reference — AI Engineers Edition
docker login # Login to Docker Hub
docker login [Link] # Login to GitHub Container Registry
docker login -u AWS -p $(aws ecr get-login-password) [Link]-east-
[Link]
# ── Save/Load (for offline transfer) ───────────────────────
docker save myimage:v1 > [Link] # Export to tar file
docker load < [Link] # Import from tar file
docker export mycontainer > [Link] # Export container fs
docker import [Link] newimage:v1 # Import as image
1.5 Network & Volume Commands
# ── Networks ────────────────────────────────────────────────
docker network ls # List all networks
docker network create mynet # Create bridge network
docker network create --driver overlay myswarmnet # Overlay for Swarm
docker network create --subnet=[Link]/16 --gateway=[Link] mynet
docker network inspect mynet # Full network details
docker network connect mynet mycontainer # Add running container to network
docker network disconnect mynet mycontainer # Remove from network
docker network rm mynet # Delete network
docker network prune # Remove all unused networks
# ── Volumes ─────────────────────────────────────────────────
docker volume ls # List volumes
docker volume create model-weights # Create named volume
docker volume inspect model-weights # Details (mount path, driver)
docker volume rm model-weights # Delete volume
docker volume prune # Delete unused volumes
# Backup a volume:
docker run --rm -v model-weights:/data -v $(pwd):/backup \
ubuntu tar czf /backup/[Link] /data
# Restore a volume:
docker run --rm -v model-weights:/data -v $(pwd):/backup \
ubuntu tar xzf /backup/[Link] -C /
Page 6 of 25
Docker Coding Reference — AI Engineers Edition
Section 2: Dockerfiles — Every Pattern Explained
2.1 Complete Dockerfile Instruction Reference with Examples
FROM — The Base Image
# Single base:
FROM python:3.11-slim
# Multi-stage — name each stage:
FROM python:3.11-slim AS builder
FROM python:3.11-slim AS runtime
# Specific digest (pinned, never changes — production must-have):
FROM python:3.11-
slim@sha256:4c2cf627f2606b5e6f7c6b9b3e82b6d06e882c6fbf05f10f5b3cc4a4c3c8e4b2
# Cross-platform build:
FROM --platform=linux/amd64 python:3.11-slim
# Use ARG before FROM for dynamic base versions:
ARG PYTHON_VERSION=3.11
FROM python:${PYTHON_VERSION}-slim
# Note: ARG before FROM is not available after FROM — redefine if needed
RUN — Execute Commands
# Shell form (uses /bin/sh -c):
RUN pip install torch
# Exec form (no shell — more explicit, needed for args with spaces):
RUN ["pip", "install", "torch"]
# CORRECT: Chain commands to minimize layers and clean up in SAME layer:
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libgomp1 \
curl \
git && \
rm -rf /var/lib/apt/lists/*
# Why rm at end? apt cache is ~100MB. If you rm in a SEPARATE RUN, it stays
# in the previous layer. Same RUN = removed from that layer too.
# BuildKit cache mounts — persistent cache between builds (huge speedup):
# syntax=docker/dockerfile:1.5 ← Must be first line of Dockerfile
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r [Link]
# This keeps pip's download cache across builds — first build downloads,
# subsequent builds just install from cache. Huge for large packages.
# Secret mount — inject secrets without baking them into layers:
RUN --mount=type=secret,id=hf_token \
Page 7 of 25
Docker Coding Reference — AI Engineers Edition
HF_TOKEN=$(cat /run/secrets/hf_token) \
python download_model.py
# Build: docker build --secret id=hf_token,src=./hf_token.txt .
COPY vs ADD
# COPY: Prefer this always. Simple, predictable.
COPY [Link] /app/[Link]
COPY --chown=appuser:appuser ./src /app/src # Set ownership
COPY --chmod=755 [Link] /[Link] # Set permissions
# COPY from another build stage (multi-stage):
COPY --from=builder /install /usr/local
COPY --from=builder /app/[Link] /app/[Link]
# ADD: Only use when you need auto-extraction or URL download.
ADD [Link] /app/models/ # Auto-extracts tarball
# WARNING: ADD from URL is not recommended — use RUN curl/wget instead
# (ADD URL not cached, curl gives you more control)
ENV and ARG — Variables
# ARG: Build-time only. NOT in final image. Use for versions, paths.
ARG MODEL_VERSION=1.0
ARG HF_TOKEN # No default — must be passed via --build-arg
# ENV: Persists in final image. Visible at runtime and in docker inspect.
ENV PYTHONUNBUFFERED=1 # Disable Python output buffering (CRITICAL)
ENV PYTHONDONTWRITEBYTECODE=1 # Don't create .pyc files in container
ENV PYTHONPATH=/app/src # Python module search path
ENV MODEL_PATH=/app/models/[Link]
ENV PORT=8000
# Use ARG to set ENV (ARG visible at build time, ENV at runtime):
ARG APP_VERSION=unknown
ENV APP_VERSION=${APP_VERSION} # Now visible at runtime too
# Multiple ENVs in one instruction (best practice — fewer layers):
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
# NEVER put secrets in ENV or ARG — they appear in 'docker history':
# BAD: ENV OPENAI_API_KEY=sk-abc123
# GOOD: Pass at runtime: docker run -e OPENAI_API_KEY=$OPENAI_API_KEY ...
WORKDIR, USER, EXPOSE, VOLUME
# WORKDIR: Sets working directory. Creates it if not exists.
WORKDIR /app
# All subsequent RUN, COPY, CMD, ENTRYPOINT are relative to /app
Page 8 of 25
Docker Coding Reference — AI Engineers Edition
# Equivalent to: RUN mkdir -p /app && cd /app (but better)
# USER: Switch user for security. All subsequent instructions + container runtime.
RUN useradd --no-create-home --uid 1001 --shell /bin/false appuser
USER appuser
# After USER, RUN commands execute as appuser, not root
# Need to install packages? Put USER before COPY of your code, after installs.
# EXPOSE: DOCUMENTS that the container listens on this port.
# Does NOT publish it. Does NOT create firewall rules.
EXPOSE 8000
EXPOSE 8000/tcp 8001/udp # Protocol can be specified
# To actually publish: docker run -p 8080:8000 (host:container)
# VOLUME: Declares mount points for external data.
VOLUME /app/models # Model weights — expect to be mounted
VOLUME /app/logs # Logs — persist outside container
VOLUME ["/app/data", "/app/cache"] # Multiple volumes, exec form
# If no volume is mounted at runtime, Docker creates an anonymous volume.
ENTRYPOINT and CMD — The Process That Runs
# Three patterns:
# Pattern 1: CMD only (no ENTRYPOINT)
# Entire command in CMD. Fully overridable at runtime.
CMD ["python", "[Link]"]
# docker run myimage python different_script.py → overrides CMD completely
# Pattern 2: ENTRYPOINT only
# Fixed executable. Extra args appended to it.
ENTRYPOINT ["gunicorn"]
# docker run myimage -w 4 app:app → gunicorn -w 4 app:app
# Pattern 3: ENTRYPOINT + CMD (BEST for AI model servers)
# ENTRYPOINT = fixed program. CMD = default arguments.
ENTRYPOINT ["python", "-m", "uvicorn"]
CMD ["[Link]:app", "--host", "[Link]", "--port", "8000", "--workers", "2"]
# Override just the args:
# docker run myimage [Link]:app --port 9000 --workers 8
# Override entrypoint entirely:
# docker run --entrypoint bash myimage
# ALWAYS use exec form (JSON array) NOT shell form:
# BAD: CMD python [Link] → PID 1 is /bin/sh, python is a child
# GOOD: CMD ["python", "[Link]"] → python is PID 1, receives signals
# With tini (init process for signal handling + zombie reaping):
RUN apt-get install -y tini
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["python", "[Link]"]
Page 9 of 25
Docker Coding Reference — AI Engineers Edition
HEALTHCHECK and LABEL
# HEALTHCHECK: Docker periodically runs this to check container health.
HEALTHCHECK --interval=30s \ # Check every 30 seconds
--timeout=10s \ # Mark unhealthy if takes >10s
--start-period=60s \ # Grace period for startup (model loading)
--retries=3 \ # Fail 3 times in a row → unhealthy
CMD curl -f [Link] || exit 1
# For gRPC services:
HEALTHCHECK CMD grpc_health_probe -addr=:50051 || exit 1
# Disable inherited healthcheck:
HEALTHCHECK NONE
# LABEL: Add metadata. OCI-standard labels.
LABEL [Link]="My Model API"
LABEL [Link]="1.0.0"
LABEL [Link]="[Link]
LABEL [Link]="2024-01-15T12:00:00Z"
LABEL maintainer="ml-team@[Link]"
LABEL model="llama-3-8b"
LABEL framework="pytorch"
# Labels are queryable: docker inspect -f '{{.[Link]}}' myimage
Page 10 of 25
Docker Coding Reference — AI Engineers Edition
2.2 Complete Production Dockerfiles for AI Engineers
Dockerfile A: FastAPI Model Inference Server
# syntax=docker/dockerfile:1.5
# ═══════════════════════════════════════════════════════════
# Stage 1: Builder — install deps, don't carry build tools forward
# ═══════════════════════════════════════════════════════════
FROM python:3.11-slim AS builder
WORKDIR /build
# Install build tools (not in final image)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc g++ && \
rm -rf /var/lib/apt/lists/*
# Copy requirements FIRST — cache this layer (changes rarely)
COPY [Link] .
# Install to /install prefix — easy to copy to final stage
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --no-cache-dir --prefix=/install -r [Link]
# ═══════════════════════════════════════════════════════════
# Stage 2: Runtime — lean, secure final image
# ═══════════════════════════════════════════════════════════
FROM python:3.11-slim AS runtime
# Only runtime system deps
RUN apt-get update && apt-get install -y --no-install-recommends \
libgomp1 \ # OpenMP (required by many ML libs)
curl \ # For healthcheck
tini && \ # Init process
rm -rf /var/lib/apt/lists/*
# Copy installed Python packages from builder
COPY --from=builder /install /usr/local
WORKDIR /app
# Create non-root user
RUN useradd --no-create-home --uid 1001 --shell /bin/false appuser && \
mkdir -p /app/models /app/logs && \
chown -R appuser:appuser /app
# Critical environment variables
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONPATH=/app/src \
MODEL_PATH=/app/models \
PORT=8000
# Copy application code last (changes most frequently — cache hit above)
Page 11 of 25
Docker Coding Reference — AI Engineers Edition
COPY --chown=appuser:appuser ./src /app/src
COPY --chown=appuser:appuser ./config /app/config
# Switch to non-root user
USER appuser
# Document which ports are used
EXPOSE 8000
# Document that models should be mounted here
VOLUME /app/models
# Metadata
LABEL [Link]="FastAPI Model Server"
LABEL maintainer="ml-team@[Link]"
# Health check (start-period covers model loading time)
HEALTHCHECK --interval=30s --timeout=10s --start-period=90s --retries=3 \
CMD curl -f [Link] || exit 1
# tini as init (signal handling + zombie reaping)
ENTRYPOINT ["/usr/bin/tini", "--"]
# CMD provides defaults — overridable at runtime
CMD ["python", "-m", "uvicorn", "[Link]:app",
"--host", "[Link]", "--port", "8000", "--workers", "2"]
Dockerfile B: PyTorch GPU Inference (CUDA)
# syntax=docker/dockerfile:1.5
ARG CUDA_VERSION=12.1.0
ARG UBUNTU_VERSION=22.04
# NVIDIA CUDA base image — includes CUDA runtime + cuDNN
FROM nvidia/cuda:${CUDA_VERSION}-cudnn8-runtime-ubuntu${UBUNTU_VERSION} AS base
# Avoid interactive prompts during package install
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
python3.11 python3.11-pip python3.11-dev \
libgomp1 curl tini git && \
update-alternatives --install /usr/bin/python python /usr/bin/python3.11 1 &&
\
update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1 && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Install PyTorch with CUDA support
COPY [Link] .
RUN --mount=type=cache,target=/root/.cache/pip \
pip install torch==2.3.0 torchvision==0.18.0 --index-url
[Link] && \
Page 12 of 25
Docker Coding Reference — AI Engineers Edition
pip install -r [Link]
# Non-root user
RUN useradd --no-create-home --uid 1001 appuser && \
mkdir -p /app/models /app/outputs && \
chown -R appuser:appuser /app
COPY --chown=appuser:appuser ./src /app/src
ENV PYTHONUNBUFFERED=1 \
CUDA_VISIBLE_DEVICES=0 \ # Default to first GPU
PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:512 # Reduce CUDA OOM
USER appuser
EXPOSE 8000
VOLUME /app/models
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=3 \
CMD python -c "import torch; assert [Link].is_available()" || exit 1
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["python", "-m", "[Link]", "--device", "cuda"]
Dockerfile C: Jupyter Notebook Server for ML Development
FROM pytorch/pytorch:2.3.0-cuda12.1-cudnn8-runtime
WORKDIR /workspace
RUN apt-get update && apt-get install -y --no-install-recommends \
git vim curl wget htop && \
rm -rf /var/lib/apt/lists/*
COPY [Link] .
RUN pip install --no-cache-dir \
jupyterlab==4.1.0 \
ipywidgets \
matplotlib seaborn plotly \
-r [Link]
ENV JUPYTER_ENABLE_LAB=yes \
JUPYTER_TOKEN=mysecrettoken \ # Change in production!
PYTHONPATH=/workspace/src
EXPOSE 8888
VOLUME /workspace
# Jupyter doesn't need root; run as user 1000 (common UID)
RUN useradd -m -u 1000 jupyter && chown -R jupyter /workspace
USER jupyter
CMD ["jupyter", "lab", "--ip=[Link]", "--port=8888", "--no-browser",
"--[Link]=${JUPYTER_TOKEN}"]
Page 13 of 25
Docker Coding Reference — AI Engineers Edition
# Run it: docker run --gpus all -p 8888:8888 -v $(pwd):/workspace mylab
Page 14 of 25
Docker Coding Reference — AI Engineers Edition
Section 3: Docker Compose — Complete Reference
3.1 Complete [Link] for AI Stack
# [Link] — Complete AI ML Stack
# Run: docker compose up -d
# Run specific profile: docker compose --profile monitoring up -d
name: ai-stack # Project name (default: directory name)
services:
# ── Model Inference API ───────────────────────────────────
model-api:
build:
context: . # Build context
dockerfile: [Link]
target: runtime # Stop at this multi-stage target
args:
PYTHON_VERSION: '3.11'
image: my-model-api:${APP_VERSION:-latest} # Built image name
container_name: model-api
restart: unless-stopped
ports:
- "[Link]:8000:8000" # Only on localhost (nginx in front)
environment:
- PYTHONUNBUFFERED=1
- MODEL_NAME=${MODEL_NAME:-llama-3-8b}
- LOG_LEVEL=INFO
- DB_HOST=postgres # Resolves via Docker DNS!
- REDIS_URL=redis://redis:6379
env_file:
- .[Link] # Secrets loaded from file at runtime
volumes:
- model-weights:/app/models # Named volume for model weights
- ./logs:/app/logs # Bind mount for logs
deploy:
resources:
limits:
memory: 16G # Hard RAM limit
cpus: '8'
reservations:
devices:
- driver: nvidia
count: 1 # Request 1 GPU
capabilities: [gpu] # Must specify for NVIDIA toolkit
healthcheck:
test: ["CMD", "curl", "-f", "[Link]
interval: 30s
timeout: 10s
start_period: 120s # Wait 2min before first check (model load)
retries: 3
depends_on:
postgres:
condition: service_healthy # Wait until postgres is ready
Page 15 of 25
Docker Coding Reference — AI Engineers Edition
redis:
condition: service_healthy
networks:
- backend # Internal network
- frontend # Network shared with nginx
logging:
driver: json-file
options:
max-size: '50m'
max-file: '5'
# ── PostgreSQL Database ────────────────────────────────────
postgres:
image: postgres:16-alpine
container_name: postgres
restart: unless-stopped
environment:
POSTGRES_DB: mlops
POSTGRES_USER: mluser
POSTGRES_PASSWORD_FILE: /run/secrets/db_password # Secret file
secrets:
- db_password
volumes:
- postgres-data:/var/lib/postgresql/data # Persist DB data
- ./[Link]:/docker-entrypoint-initdb.d/[Link]:ro # Init script
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mluser -d mlops"]
interval: 10s
timeout: 5s
start_period: 30s
retries: 5
networks:
- backend
# ── Redis Cache ─────────────────────────────────────────────
redis:
image: redis:7-alpine
container_name: redis
restart: unless-stopped
command: redis-server --maxmemory 2gb --maxmemory-policy allkeys-lru
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
networks:
- backend
# ── Nginx Reverse Proxy ─────────────────────────────────────
nginx:
image: nginx:1.25-alpine
container_name: nginx
restart: unless-stopped
ports:
Page 16 of 25
Docker Coding Reference — AI Engineers Edition
- "80:80"
- "443:443"
volumes:
- ./nginx/[Link]:/etc/nginx/[Link]:ro
- ./nginx/certs:/etc/nginx/certs:ro
depends_on:
model-api:
condition: service_healthy
networks:
- frontend
# ── Grafana Monitoring ──────────────────── profile: monitoring ─
grafana:
image: grafana/grafana:10.3.0
profiles: [monitoring] # Only starts with --profile monitoring
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
networks:
- backend
# ── Model Downloader (one-off init container) ──────────────
model-init:
image: python:3.11-slim
profiles: [init] # Run manually: docker compose --profile init
run model-init
volumes:
- model-weights:/models
environment:
- HF_TOKEN=${HF_TOKEN}
command: ["python", "/[Link]", "--model", "meta-llama/Meta-Llama-3-8B"]
# ── Networks ──────────────────────────────────────────────────
networks:
backend:
driver: bridge
name: ai-backend # Explicit name (not prefixed by project)
frontend:
driver: bridge
# ── Volumes ───────────────────────────────────────────────────
volumes:
model-weights:
name: ai-model-weights # Explicit name
postgres-data:
redis-data:
grafana-data:
# ── Secrets ───────────────────────────────────────────────────
secrets:
db_password:
file: ./secrets/db_password.txt # Plain text file, not committed to git
3.2 Docker Compose Commands — Complete Reference
Page 17 of 25
Docker Coding Reference — AI Engineers Edition
# ── Starting & Stopping ─────────────────────────────────────
docker compose up # Start all services (foreground)
docker compose up -d # Detached (background)
docker compose up --build # Rebuild images before starting
docker compose up --no-deps model-api # Start only model-api (skip deps)
docker compose up --profile monitoring # Also start monitoring-profile services
docker compose up --scale model-api=3 # Run 3 replicas of model-api
docker compose down # Stop & remove containers + networks
docker compose down --volumes # Also remove volumes (DATA LOSS!)
docker compose down --rmi all # Also remove built images
docker compose stop # Stop without removing containers
docker compose start # Start stopped containers
docker compose restart model-api # Restart specific service
docker compose pause # Pause all services
docker compose unpause # Resume
# ── Status & Monitoring ─────────────────────────────────────
docker compose ps # List containers and status
docker compose ps --format json # JSON output for scripting
docker compose logs # All service logs
docker compose logs -f model-api # Follow logs for specific service
docker compose logs --tail=50 # Last 50 lines from each service
docker compose top # Processes in each container
docker compose stats # Live resource usage
# ── Exec & Run ──────────────────────────────────────────────
docker compose exec model-api bash # Shell in running container
docker compose exec postgres psql -U mluser # Run command in service
docker compose run --rm model-api python [Link] migrate # One-off command
# ── Build & Push ─────────────────────────────────────────────
docker compose build # Build all services with build config
docker compose build --no-cache # Force full rebuild
docker compose build model-api # Build specific service
docker compose push # Push built images to registry
docker compose pull # Pull latest images from registry
# ── Config & Validation ─────────────────────────────────────
docker compose config # Validate and view resolved compose config
docker compose config --services # List service names
docker compose config --volumes # List volume names
# ── Multiple compose files (overriding) ─────────────────────
docker compose -f [Link] -f [Link] up
# [Link] auto-merges with [Link] — use for dev overrides
Page 18 of 25
Docker Coding Reference — AI Engineers Edition
Section 4: Real AI/ML Code Patterns
4.1 FastAPI + Model Loading Pattern
# src/[Link] — Production FastAPI with proper Docker patterns
import os, signal, logging, asyncio
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import torch
[Link](level=[Link], format='%(asctime)s %(levelname)s
%(message)s')
log = [Link](__name__)
# Read config from environment (twelve-factor pattern):
MODEL_PATH = [Link]('MODEL_PATH', '/app/models/[Link]')
DEVICE = [Link]('DEVICE', 'cuda' if [Link].is_available() else 'cpu')
MAX_BATCH_SIZE = int([Link]('MAX_BATCH_SIZE', '8'))
model = None # Global model reference
# Lifespan handler: runs at startup and shutdown
@asynccontextmanager
async def lifespan(app: FastAPI):
global model
[Link](f'Loading model from {MODEL_PATH} on {DEVICE}')
model = [Link](MODEL_PATH, map_location=DEVICE)
[Link]()
[Link]('Model loaded. Ready to serve.')
yield # Container runs here
[Link]('Shutdown: releasing model')
del model
[Link].empty_cache()
app = FastAPI(lifespan=lifespan, title='Model API')
class InferenceRequest(BaseModel):
text: str
max_tokens: int = 512
@[Link]('/health') # Required for Docker HEALTHCHECK
async def health():
if model is None:
raise HTTPException(503, 'Model not loaded')
return {'status': 'healthy', 'device': DEVICE,
'cuda_available': [Link].is_available()}
@[Link]('/infer')
async def infer(req: InferenceRequest):
with torch.inference_mode():
# ... run model inference ...
result = model([Link])
Page 19 of 25
Docker Coding Reference — AI Engineers Edition
return {'output': result}
4.2 [Link] Best Practices for Docker
# [Link] — Pin ALL versions for reproducibility in Docker
# ── Core Framework ─────────────────────────────────────────
fastapi==0.111.0
uvicorn[standard]==0.29.0
pydantic==2.7.1
# ── ML Libraries ────────────────────────────────────────────
# Note: torch pinned via --index-url in Dockerfile (CUDA version specific)
torch==2.3.0
transformers==4.41.1
accelerate==0.30.1
sentencepiece==0.2.0
# ── Database ────────────────────────────────────────────────
sqlalchemy==2.0.30
asyncpg==0.29.0
alembic==1.13.1
# ── Caching ─────────────────────────────────────────────────
redis==5.0.4
# ── Monitoring ──────────────────────────────────────────────
prometheus-client==0.20.0
opentelemetry-sdk==1.24.0
# ── Separate files for different environments ───────────────
# [Link]: jupyter, pytest, black, mypy, etc.
# [Link]: pytest, pytest-asyncio, httpx (test client)
# [Link]: ONLY inference deps (smallest possible)
# Generate pinned requirements from loose requirements:
# pip-compile [Link] > [Link]
# (pip-compile from pip-tools package)
4.3 .env Files for Docker — Development vs Production
# .[Link] — committed to git (no real secrets)
APP_VERSION=dev
LOG_LEVEL=DEBUG
MODEL_NAME=tiny-test-model
DB_HOST=localhost
DB_PORT=5432
REDIS_URL=redis://localhost:6379
# .[Link] — NEVER commit to git, inject at deploy time
OPENAI_API_KEY=sk-... # Real secret
Page 20 of 25
Docker Coding Reference — AI Engineers Edition
HF_TOKEN=hf_... # Real secret
DB_PASSWORD=... # Real secret
SENTRY_DSN=[Link] # Real secret
# .gitignore — always exclude:
.[Link]
.[Link]
secrets/
*.env
# Use in Compose:
# env_file:
# - .[Link]
# - .[Link] ← overlays, production values win
# Or pass individually at runtime:
# docker run -e OPENAI_API_KEY=$OPENAI_API_KEY ...
# The $OPENAI_API_KEY comes from your shell, not from any file.
4.4 GPU Docker Compose for Multi-GPU Training
# [Link] — Multi-GPU training job
services:
trainer:
build:
context: .
dockerfile: [Link]
volumes:
- ./src:/app/src:ro # Code (read-only)
- /data/datasets:/data:ro # Dataset (read-only)
- ./checkpoints:/checkpoints # Save checkpoints to host
- ./logs/train:/app/logs
environment:
- MASTER_ADDR=localhost # For DDP (distributed training)
- MASTER_PORT=12355
- WORLD_SIZE=2 # Total GPUs across all nodes
- CUDA_VISIBLE_DEVICES=0,1 # Use GPUs 0 and 1
- HF_TOKEN=${HF_TOKEN} # From shell environment
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all # All GPUs
capabilities: [gpu]
limits:
memory: 128G
shm_size: '16gb' # Shared memory for PyTorch DataLoader
ulimits: # Increase for large training jobs
memlock:
soft: -1
hard: -1
ipc: host # Shared IPC for multi-GPU (alternative to
shm_size)
Page 21 of 25
Docker Coding Reference — AI Engineers Edition
command: ["torchrun", "--nproc_per_node=2", "[Link]",
"--epochs", "100", "--batch-size", "32"]
# Run it:
# docker compose -f [Link] up
# Check GPU usage: docker exec trainer nvidia-smi
# Follow logs: docker compose -f [Link] logs -f
4.5 Makefile for Docker Workflows
# Makefile — Standard Docker workflow shortcuts
.PHONY: build push run dev test clean logs shell
# Variables
IMAGE_NAME := my-model-api
REGISTRY := [Link]/myorg
GIT_SHA := $(shell git rev-parse --short HEAD)
VERSION := $(shell cat VERSION 2>/dev/null || echo 'dev')
# Build the production image
build:
docker build \
-t $(IMAGE_NAME):$(GIT_SHA) \
-t $(IMAGE_NAME):latest \
--build-arg APP_VERSION=$(VERSION) \
--cache-from $(REGISTRY)/$(IMAGE_NAME):latest \
.
# Push to registry
push: build
docker tag $(IMAGE_NAME):$(GIT_SHA) $(REGISTRY)/$(IMAGE_NAME):$(GIT_SHA)
docker tag $(IMAGE_NAME):$(GIT_SHA) $(REGISTRY)/$(IMAGE_NAME):latest
docker push $(REGISTRY)/$(IMAGE_NAME):$(GIT_SHA)
docker push $(REGISTRY)/$(IMAGE_NAME):latest
# Start full stack in background
run:
docker compose up -d
# Development with live code reload
dev:
docker compose -f [Link] -f [Link] up
# Run tests in container
test:
docker compose run --rm model-api pytest tests/ -v --tb=short
# Open shell in running container
shell:
docker compose exec model-api bash
# Follow logs
Page 22 of 25
Docker Coding Reference — AI Engineers Edition
logs:
docker compose logs -f model-api
# Clean everything
clean:
docker compose down --volumes --rmi local
docker system prune -f
# Download model weights to volume
init-model:
docker compose --profile init run --rm model-init
Page 23 of 25
Docker Coding Reference — AI Engineers Edition
Section 5: Debugging and Troubleshooting
5.1 Container Won't Start — Diagnosis
# Step 1: See why it exited
docker ps -a # Find the container, check STATUS and EXIT CODE
docker logs mycontainer # Read error output
docker inspect mycontainer | python -m [Link] # Full metadata
# Step 2: Override CMD to get a shell (bypass your broken entrypoint):
docker run -it --entrypoint bash myimage:v1
# Now you're inside — test your app manually:
python [Link] # Run directly and see the actual error
python -c 'import mymodule' # Test specific imports
env # Check environment variables
ls -la /app # Check file permissions
cat /app/[Link] # Check config file contents
# Step 3: Common exit codes:
# Exit 0 = process exited normally (restart policy 'on-failure' won't restart)
# Exit 1 = application error (check logs)
# Exit 137 = killed by OOM killer (out of memory, increase --memory)
# Exit 139 = segfault (bad native lib version)
# Exit 143 = killed by SIGTERM (graceful shutdown — normal)
5.2 Networking Issues
# Can't connect container-to-container:
docker network inspect mynet # Check which containers are on the network
docker exec api ping postgres # Test DNS resolution and connectivity
docker exec api curl [Link] # Test HTTP
docker exec api nslookup postgres # DNS lookup
# Check port mappings:
docker port mycontainer # What ports are published
netstat -tlnp | grep 8080 # Is port 8080 listening on host?
curl localhost:8080/health # Test from host
# Container can't reach internet:
docker exec mycontainer curl [Link] # Test outbound
docker exec mycontainer cat /etc/[Link] # Check DNS config
docker exec mycontainer route -n # Check routing table
5.3 Performance Issues
# Live resource monitoring:
docker stats # CPU/RAM/NET/IO for all containers
docker stats mycontainer # Specific container
docker exec mycontainer top # Process list inside container
Page 24 of 25
Docker Coding Reference — AI Engineers Edition
# GPU monitoring in container:
docker exec mycontainer nvidia-smi # GPU usage
docker exec mycontainer nvidia-smi dmon # Continuous GPU monitoring
docker run --gpus all nvidia/cuda:12.1.0-base nvidia-smi # Quick GPU test
# Memory issues — container OOMed:
docker inspect mycontainer | grep -i oom # Was OOM killer triggered?
dmesg | grep -i 'out of memory' # Host kernel OOM messages
# Image too large — analyze layers:
docker history myimage:v1 --human --format 'table {{.Size}} {{.CreatedBy}}'
# Install dive for deep layer analysis:
docker run --rm -it -v /var/run/[Link]:/var/run/[Link] \
wagoodman/dive myimage:v1
5.4 Build Issues
# See exactly what's happening in build:
docker build --progress=plain . # Show all RUN output (no condensing)
docker build --no-cache . # Force rebuild all layers
# Build context too large (slow uploads):
docker build . 2>&1 | head -5 # First line shows build context size
# If 'Sending build context to Docker daemon 2.5GB' — fix your .dockerignore
# Find what's in build context:
find . -not -path './.git/*' | sort # List all files that could be in context
# Test .dockerignore:
docker build --file /dev/null --tag test-context . # Builds with empty Dockerfile
# First line shows context size — should be small
# BuildKit debugging:
DOCKER_BUILDKIT=1 docker build --progress=plain . 2>&1 | tee [Link]
END OF DOCUMENT 2 — CODING REFERENCE
Refer to Document 1 (Concepts) for deep explanations of every topic covered in this coding guide.
Page 25 of 25