LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 177 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/8
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/11
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageClustering and PCACore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/24
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernanceData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/16
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/19
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning Agent System Design
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnComputing FoundationsDocker for Reproducible AI
⚙️EasyMLOps & Deployment

Docker for Reproducible AI

Package the access-request scorer in a portable Docker image with a small build context, runtime data and secrets, a non-root user, and a reproducible gate.

11 min read
Learning path
Step 2 of 177 in the full curriculum
Git, Shell, Linux for AIPython for AI Engineering

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

Git carries the scorer and fixture between machines, but it can't pin Python, OS packages, runtime users, filesystem layout, or how secrets arrive. Docker records those assumptions in an image and a runtime command.[1]Reference 1Docker Documentation.https://docs.docker.com/

The repo from the previous chapter already contains eval/access_requests.jsonl and a scorer that must print 0.667. This lesson packages that exact command so another laptop or CI worker uses the same version-constrained environment instead of discovering a different Python version, missing dependency, leaked .env, or volume permission error.

Check your reasoning: if two people run the same files with different Python versions and different installed packages, Git did its job but the project still isn't reproducible.

Multi-stage Docker contract for the access-request scorer: repo files build into a slim runtime image, eval data mounts read-only, secrets inject at run time, and the gate reproduces score 0.667 on CPU before any GPU extension.
The container turns the access-request scorer into a portable artifact. The base lesson is CPU-first so each student can run it; the GPU path keeps the same contracts but uses a platform-specific image and NVIDIA runtime checks.

What a container must guarantee

A useful Docker setup answers six questions before a teammate has to ask them.

BoundaryQuestionRepo contract
Base imageWhich Python and OS run the code?A version-constrained base image such as python:3.12-slim-trixie; use a digest when exact bytes must be reproducible. On Apple Silicon, also pick the platform deliberately (--platform linux/amd64 vs linux/arm64) so teammate Macs don't silently use a different architecture
DependenciesWhich packages are installed?requirements.txt copied before application code
Build contextWhich files enter the image build?.dockerignore that excludes secrets, caches, model weights, and virtualenvs
Runtime userWho owns files inside the container?A non-root user and explicit writable directories
DataWhere does eval data live?Tiny fixtures can be copied; changing data and model caches should be mounted
SecretsHow does the API key arrive?Runtime --env-file or Compose env_file, not ARG or COPY .env

Git made the files reproducible. Docker makes the environment portable.

These boundaries become a small lifecycle: build inputs become image layers, then run-time data and credentials join only when the scorer starts.

Diagram showing 1 Repo + Dockerfile, 2 Build context, 3 Multi-stage image, and 4 Run as appuser.
1 Repo + Dockerfile, 2 Build context, 3 Multi-stage image, and 4 Run as appuser.

The solid path is the artifact lifecycle. The dotted inputs stay outside image layers and arrive only for a specific run.

Six container boundaries for a reproducible AI project mapped to placement: base image, dependencies, build context, and runtime user are baked; eval data is mounted; secrets are injected at runtime only.
A good container setup answers the six boundary questions up front: what gets baked into the image, what stays on the host and mounts in, and what must only arrive at runtime.

Start with .dockerignore

Create .dockerignore at the root of access-rag/, next to .gitignore:

.dockerignore
1# .dockerignore - keep the build context tiny and secret-free 2.env 3.env.* 4*.pem 5secrets/ 6.git/ 7.github/ 8.venv/ 9__pycache__/ 10*.py[cod] 11*.egg-info/ 12node_modules/ 13models/ 14*.gguf 15*.safetensors 16*.bin 17chroma/ 18faiss_index/ 19*.db 20runs/ 21eval_cache/ 22wandb/ 23mlruns/ 24.DS_Store 25.idea/ 26.vscode/ 27*.swp

Docker reads this file before sending the build context to the daemon. Without it, a broad COPY . /app can accidentally send .env, cached model files, local indexes, notebooks, and virtualenvs into the build. That makes images slower to build and easier to leak.

The filter is simple in principle: if a path matches .dockerignore, it never enters the build context.

Reuse the scorer you already tested

The previous chapter committed scripts/score_access_requests.py and eval/access_requests.jsonl. Keep those as the single scorer and fixture instead of creating a second implementation for Docker. The image also expects requirements.txt; it can stay empty until the scorer gains external dependencies.

terminal
1test -f scripts/score_access_requests.py 2test -f eval/access_requests.jsonl 3touch requirements.txt 4python3 scripts/score_access_requests.py
Output
1Eval rows: 3 2Exact-match accuracy on tiny fixture: 0.667 (2/3) 3Gate passed. You may commit.

Build the smallest runnable scorer image

Start with a CPU image. That choice is deliberate. The three-row scorer doesn't need a GPU, and a beginner should be able to prove the container contract on a normal laptop before adding NVIDIA runtime setup.

Create this Dockerfile:

Dockerfile
1# syntax=docker/dockerfile:1 2# Tag is fine for learning. For exact rebuilds, pin both stages by digest, e.g.: 3# FROM python:3.12-slim-trixie@sha256:<verified-digest> AS builder 4FROM python:3.12-slim-trixie AS builder 5 6ENV PYTHONDONTWRITEBYTECODE=1 \ 7 PYTHONUNBUFFERED=1 \ 8 PIP_NO_CACHE_DIR=1 \ 9 PIP_DISABLE_PIP_VERSION_CHECK=1 10 11RUN python -m venv /opt/venv 12ENV PATH="/opt/venv/bin:$PATH" 13 14COPY requirements.txt /tmp/requirements.txt 15# Empty requirements are fine here. When packages appear, prefer a lockfile 16# (uv.lock / hashed requirements) and install with hashes for repeatable builds. 17RUN python -m pip install --no-cache-dir -r /tmp/requirements.txt 18 19FROM python:3.12-slim-trixie AS runtime 20 21ENV PYTHONDONTWRITEBYTECODE=1 \ 22 PYTHONUNBUFFERED=1 \ 23 PATH="/opt/venv/bin:$PATH" 24 25RUN useradd --create-home --no-log-init --user-group --uid 10001 --shell /usr/sbin/nologin appuser 26 27WORKDIR /app 28 29COPY --from=builder /opt/venv /opt/venv 30COPY --chown=appuser:appuser scripts/score_access_requests.py scripts/score_access_requests.py 31COPY --chown=appuser:appuser eval/ eval/ 32 33USER appuser 34 35ENTRYPOINT ["python", "scripts/score_access_requests.py"]

Dependencies install into /opt/venv in the first stage. A clean second stage copies the virtualenv, scorer, and fixture, then runs as appuser instead of root. Its entrypoint calls the same scorer the Git gate used.

Dockerfile sectionPurpose
builder stageinstalls packages once into a reusable virtualenv
runtime stageruns only the existing scorer, fixture, and installed environment

The official Python image manifest maps python:3.12-slim-trixie to the Python 3.12 line on Debian 13 (trixie).[2]Reference 2Official Python Image Manifesthttps://github.com/docker-library/official-images/blob/master/library/python[3]Reference 3Debian Trixie Release Informationhttps://www.debian.org/releases/trixie/ This constrains the Python minor line and Debian release, but it doesn't pin exact bytes. Image tags are mutable, so a later rebuild can pick up a new Python patch release or rebuilt OS packages.[4]Reference 4Building Best Practiceshttps://docs.docker.com/build/building/best-practices/#pin-base-image-versions Use a digest (python:3.12-slim-trixie@sha256:<verified-digest>) when the same base-image bytes must resolve on every machine and in CI. Lock application dependencies, including any build tools you add, and use hashes when the project requires repeatable package artifacts.

Later, when you add dependencies, package changes invalidate the dependency layer instead of the code layer. Editing scripts/score_access_requests.py won't force a full package reinstall.

Docker layer caching follows the same order rule: copy requirements.txt and install dependencies before application code so routine code edits don't bust the dependency layer.

Why does the Dockerfile copy requirements.txt before the scorer source?

Answer

Dependency installation stays in an earlier cacheable layer. Editing scorer code can then reuse the dependency layer instead of reinstalling every package.

Build and run it

From the project root:

terminal-3
1docker build -t access-rag:local .

Run the image without any host mount first:

terminal-4
1docker run --rm access-rag:local

Expected output:

Output
1Eval rows: 3 2Exact-match accuracy on tiny fixture: 0.667 (2/3) 3Gate passed. You may commit.

The printed score is rounded for humans. Keep the gate comparison on the exact fraction, as this tiny check does:

check_gate_fraction.py
1matches, total = 2, 3 2score = matches / total 3 4assert 0 <= matches <= total 5print(f"score={score:.3f} ({matches}/{total})") 6print("gate_passed:", score >= 2 / 3)
Output
1score=0.667 (2/3) 2gate_passed: True

Verify copied and mounted data

The image ID is not the proof. The proof is that the same three rows produce the same 0.667 after moving into the container. Exact rebuilds also require a base-image digest and locked dependency artifacts.

Contract checkWhat proves it
Same scorer and fixturethe Dockerfile copies only scripts/score_access_requests.py and eval/
Same commandthe entrypoint runs that scorer directly
Same resultdocker run --rm access-rag:local prints 0.667 (2/3)
Runtime data can replace baked dataa read-only bind mount supplies /app/eval

What proves more than the image ID when checking this containerized scorer?

Answer

Running the image against the three-row fixture and observing 0.667 (2/3). That receipt checks the command, code, data, and runtime together.

Run the image against host data:

terminal-5
1docker run --rm \ 2 -v "$(pwd)/eval:/app/eval:ro" \ 3 access-rag:local

A bind mount replaces the image path for that run; Docker doesn't merge the host and image directories. If the score changes, compare the mounted fixture with the committed one before changing the image.

Practice: break one thing on purpose

After the first successful run, make one small mistake and predict the symptom before you rerun the command.

ChangePredictionWhy
Rename eval/access_requests.jsonl on the hostmounted run fails with a missing filethe :ro mount replaces the image's /app/eval directory
Remove requirements.txt from the build contextbuild fails at the COPY requirements.txt stepDocker can copy files that exist in the context
Add env_file: .env to Compose before creating .envCompose reports the missing env filedeclared runtime files must exist locally
Run on a machine without Docker Compose v2docker compose version is unknownDocker Engine and the Compose plugin are separate on some Linux installs

These failures are useful. Each one proves which part of the contract you were relying on.

Compose keeps the local command stable

For one service, docker run is fine. As soon as the project adds a vector database, API, worker, or model cache, you want one checked-in Compose file so each engineer starts the same stack.

Start with a runnable docker-compose.yml for the scorer:

docker-compose.yml
1services: 2 scorer: 3 build: 4 context: . 5 dockerfile: Dockerfile 6 image: access-rag:local 7 volumes: 8 - ./eval:/app/eval:ro

Validate the file before running it:

terminal-6
1if docker compose version >/dev/null 2>&1; then 2 docker compose config --quiet 3 docker compose run --rm scorer 4else 5 echo "Docker Compose v2 plugin missing. Install docker-compose-plugin before using compose." 6fi

Docker Desktop includes Compose v2. Some Linux installs need the docker-compose-plugin package first.[1]Reference 1Docker Documentation.https://docs.docker.com/ If docker compose version is unknown, the Dockerfile is still usable through docker run, but the Compose workflow isn't installed yet. Note two modern conventions: the old top-level version: key is obsolete and Compose v2 ignores it (omit it, as above), and the preferred filename is now compose.yaml, though docker-compose.yml still works. Always use the hyphen-free docker compose command; the legacy docker-compose v1 binary is end-of-life.

When the RAG stack grows, add vector-db, api, and worker services to this same file. Don't add fake services before they exist. A Compose file that starts today is better than an impressive YAML file that fails on the first command.

Secrets belong at runtime

Don't pass real secrets with ARG:

Dockerfile-2
1# BAD: the value can leak through image history and layers 2ARG OPENAI_API_KEY 3RUN echo "$OPENAI_API_KEY" > /tmp/key.txt

Use runtime environment instead:

terminal-7
1docker run --rm \ 2 --env-file .env \ 3 -v "$(pwd)/eval:/app/eval:ro" \ 4 access-rag:local

Compose uses the same idea:

secrets-belong-at-runtime.yaml
1services: 2 scorer: 3 # Add this after you have a local .env file. 4 env_file: 5 - .env

The secret is available to the process when the container runs. It isn't copied into the image, pushed to the registry, or shown by docker history.

Build context and runtime env are separate channels. A secret should appear only in the runtime channel.

Why should an API key enter through runtime environment configuration instead of COPY or a Docker build argument?

Answer

Runtime injection keeps the key out of image layers, registry artifacts, and docker history. .dockerignore also prevents the local secret file from entering the build context.

When the GPU enters the story

The CPU-first image is the right base contract here. It works on Linux, macOS, CI runners, and most developer laptops. A CUDA image is different: it targets Linux hosts with NVIDIA drivers and the NVIDIA Container Toolkit, which installs a runtime hook so the container can see the host GPU. Configure the runtime, restart Docker so the daemon loads the change, then pass --gpus at run time.[5]Reference 5NVIDIA Container Toolkit Installation Guidehttps://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html

terminal
1sudo nvidia-ctk runtime configure --runtime=docker 2sudo systemctl restart docker

When a later PyTorch or inference chapter needs GPU acceleration, keep the same contracts and change the platform-specific pieces:

ContractCPU scorer nowGPU workload later
Base imagepython:3.12-slim-trixieofficial PyTorch CUDA image or NVIDIA CUDA runtime image matched to the torch wheel
Runtime checkscorer returns 0.667python -c "import torch; assert torch.cuda.is_available()"
Run commanddocker run access-rag:localdocker run --gpus all --shm-size=2g ...
Portability claimsame Python runtime on normal machinessame image on compatible Linux NVIDIA machines

Don't promise that one CUDA image gives Apple Silicon and NVIDIA parity. On Apple Silicon, use the CPU image for this foundation scorer or a separate Metal/MPS path for PyTorch. For production GPU serving, test the Linux NVIDIA image on a host that has the NVIDIA runtime.

The first GPU smoke test is:

terminal-8
1docker run --rm --gpus all nvidia/cuda:12.9.2-base-ubuntu24.04 nvidia-smi

If that fails, the Dockerfile isn't the problem yet. The host can't expose the GPU to containers.

That CUDA tag is illustrative; NVIDIA publishes new CUDA versions often, so pin to whatever release your PyTorch wheel targets rather than copying the number here. One subtle trap: the container's CUDA runtime must not be newer than the host's NVIDIA driver supports, or the container fails with CUDA driver version is insufficient for CUDA runtime version. That mismatch lives on the host, not in your Dockerfile.

The gate that protects the contract

Add a local or CI gate that proves the image still builds and the score still matches:

terminal-9
1#!/usr/bin/env bash 2set -euo pipefail 3 4docker build -t access-rag:check . 5docker run --rm \ 6 -v "$PWD/eval:/app/eval:ro" \ 7 access-rag:check 8if docker compose version >/dev/null 2>&1; then 9 docker compose config --quiet 10else 11 echo "Docker Compose v2 plugin missing. Install docker-compose-plugin before enabling the compose gate." 12fi

This catches broken COPY paths, missing files, invalid Compose syntax, and scorer drift before a teammate pulls the repo. If your machine doesn't have the Compose plugin yet, keep the docker build and docker run lines as the mandatory gate, then install Compose before using the Compose part.

Failure modes to keep ready

SymptomMost common causeFix that belongs in the repo
ModuleNotFoundError inside the containerdependency missing from requirements.txtadd it to requirements.txt, rebuild, and keep dependency install before COPY scripts/
.env appears in the image context.dockerignore forgot .env*add .env*, rebuild, and check docker history before pushing
Permission denied on a mounted directorycontainer user can't read or write the host pathmount eval fixtures with :ro, use named volumes for writable data, or document the host permissions
each code edit reinstalls dependenciesCOPY . /app happens before dependency installcopy requirements.txt first, install dependencies, then copy application code
could not select device driver with capabilities: [[gpu]]NVIDIA Container Toolkit missing or host isn't NVIDIA Linuxdocument host GPU setup and keep the CPU scorer path working
Cloud Run starts but can't read configlocal .env was assumed to exist in productionuse Secret Manager or the deployment platform's secret mechanism, not a copied file

The important habit isn't memorizing each Docker flag. It's making the repo contain the diagnosis, the command, and the prevention.

The runtime contract

The runtime contract is explicit:

  1. git clone brings the code, the three-row eval, the scorer, the Dockerfile, .dockerignore, and docker-compose.yml.
  2. docker build -t access-rag:local . produces a version-constrained Python runtime. Add a verified base-image digest and locked dependency artifacts when exact rebuilds are required.
  3. docker run --rm access-rag:local returns the expected 0.667 from the starter scorer.
  4. docker compose run --rm scorer gives teammates one stable local command.
  5. Later GPU images, vector databases, API services, workers, and Cloud Run deployments must preserve the same habit: explicit runtime constraints, mounted data, runtime secrets, and a gate that proves the expected output.

The next chapter opens the Python scorer instead of leaving it hidden behind a command. Docker matters there because code bugs are hard enough without also wondering whether two machines are running different Python environments.

Reproducibility release checklist

Before publishing the image, build from a clean context, run the baked fixture and read-only mounted fixture, confirm both print 0.667 (2/3), inspect that no .env entered image history, and validate Compose configuration. For exact rebuilds, also pin the base image by digest and lock dependency artifacts.

Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.Two engineers have identical repo files, but one laptop uses a different Python minor version and lacks packages. Which setup directly turns the runtime assumptions into a portable contract?

Correct answer: Build from an explicit Python and OS image tag, install locked dependencies, and run the scorer through a fixed entrypoint.

Git can align scripts and fixtures, but it doesn't constrain Python, OS libraries, installed packages, or the command used to run the scorer. An explicit image tag, locked dependencies, and a fixed entrypoint make those assumptions part of the artifact instead of each developer's laptop. Pin the base image by digest when exact bytes must be reproducible.

2.A project root contains .env, .venv/, model weights, a local vector index, and a Dockerfile with a broad COPY . /app. What should be added before building?

Correct answer: A .dockerignore that excludes .env*, virtualenvs, caches, model weights, indexes, database files, and editor artifacts.

Docker reads .dockerignore before sending the build context to the daemon, so excluded files never enter the build. .gitignore is not a substitute for Docker context filtering, deleting a secret after copying can still leave it in layers, and build args are not the right channel for real secrets.

3.Editing scripts/score_access_requests.py makes pip install run again on every rebuild because the Dockerfile copies the whole repo before installing dependencies. Which structure fixes that?

Correct answer: Copy requirements first, install into a builder venv, then copy the venv plus app files into a clean runtime stage as appuser.

Docker cache reuse depends on earlier layers. Copying requirements.txt and installing dependencies before frequently edited app code prevents normal code edits from invalidating the dependency install. A clean runtime stage avoids carrying unnecessary build context, and a non-root user reduces permission and safety problems.

4.An image contains /app/eval, but a run bind-mounts host ./eval over /app/eval:ro. The host rows are approved/approved, blocked/escalated, and restored/restored. What should the gate prove?

Correct answer: It scores the mounted host fixture as 2/3 correct, prints 0.667, and gates on counts or the exact fraction.

A bind mount over /app/eval replaces the image's copied eval directory for that run. The listed host fixture has two exact matches out of three rows, so display rounding shows 0.667. The safer check should use counts or the exact 2/3 fraction, not equality to the rounded decimal literal.

5.Only the CPU scorer exists today, but the project will later add an API, worker, vector database, and GPU workloads. Which Compose workflow should be checked in now?

Correct answer: Define a scorer service that builds the Dockerfile, mounts ./eval:/app/eval:ro, validate it, and run docker compose run --rm scorer.

A checked-in Compose file should make the working service easy to run today. Validating the file catches syntax errors early, and docker compose run --rm scorer gives teammates one stable local command. Fake future services and premature CUDA requirements make the current reproducibility gate harder to use.

6.A Dockerfile uses ARG OPENAI_API_KEY and writes the value into a file during build. How should the API key be supplied for the scorer container instead?

Correct answer: Keep .env out of the build context and pass it at runtime with docker run --env-file .env or Compose env_file.

Secrets should reach the process when the container runs, not when the image is built. Build args and copied files can leak through layers, image history, registries, or a broad build context. Runtime env files keep the secret outside the image artifact.

7.A later PyTorch image fails the smoke test docker run --rm --gpus all nvidia/cuda:... nvidia-smi with could not select device driver with capabilities: [[gpu]]. What is the most likely next step?

Correct answer: The host cannot expose an NVIDIA GPU to containers yet; install and configure the NVIDIA toolkit or use the CPU path.

That failure is about the host's ability to expose NVIDIA devices to containers, not the scorer code or eval mount. CUDA workloads require a compatible Linux NVIDIA host, the NVIDIA Container Toolkit runtime hook, and --gpus; the CPU scorer should remain available when that platform is absent.

8.The container runs as non-root appuser and gets Permission denied when writing to a bind-mounted host directory. Which fix belongs in the repo's container workflow?

Correct answer: Keep eval fixtures read-only, use named volumes for writable data, or document host path ownership for appuser.

A non-root container user may not have permission to write to arbitrary host bind mounts. Read-only mounts are appropriate for eval fixtures; writable data should use named volumes or documented host permissions. Running as root hides the problem and can create root-owned files on teammates' machines.

8 questions remaining.

Next Step
Continue to Python for AI Engineering

The scorer now runs inside a portable, version-constrained image with a small build context, runtime secrets, and a non-root user. Next you'll open that scorer and build the Python validation, metric, command-line interface, and tests behind its `0.667` result.

PreviousGit, Shell, Linux for AI
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Docker Documentation.

Docker Inc. · 2026 · Official documentation

https://docs.docker.com/

Official Python Image Manifest

Docker Official Images Maintainers · 2026 · Official image manifest

https://github.com/docker-library/official-images/blob/master/library/python

Debian Trixie Release Information

Debian Project · 2025 · Official release information

https://www.debian.org/releases/trixie/

Building Best Practices

Docker Inc. · 2026 · Official documentation

https://docs.docker.com/build/building/best-practices/#pin-base-image-versions

NVIDIA Container Toolkit Installation Guide

NVIDIA · 2026 · Official documentation

https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.