Docker Essentials¶
Package code + its entire environment into a reproducible image, run it anywhere as a container. For data science: the same training code runs on your laptop, a CI runner, and a GPU box with zero "works on my machine."
Table of Contents¶
- Installation / Setup
- Core Syntax
- Common Operations
- Practical Examples
- Common Patterns
- Best Practices
- Common Mistakes
- Troubleshooting
- Related Cheat Sheets
- Official Documentation
Installation / Setup¶
# Docker Engine (Linux) or Docker Desktop (macOS/Windows — WSL2 backend)
docker --version
docker info # engine healthy?
docker run hello-world # sanity check
Mental model: Image = template (read-only layers). Container = a running instance of an image (writable layer on top). Build images once; run many containers.
Core Syntax¶
Images¶
| Command | Does |
|---|---|
docker images |
list local images |
docker pull python:3.12-slim |
download an image |
docker build -t myimage . |
build from a Dockerfile |
docker tag myimage repo/myimage:v1 |
tag an image |
docker rmi myimage |
remove an image |
docker history myimage |
show layers |
Containers¶
| Command | Does |
|---|---|
docker run myimage |
run (foreground) |
docker run -d myimage |
run detached (background) |
docker run --name train myimage |
name it |
docker ps / docker ps -a |
running / all containers |
docker exec -it <c> bash |
shell inside a running container |
docker logs <c> / -f |
container logs (follow) |
docker stop <c> / docker start <c> |
stop / restart |
docker rm <c> |
delete a stopped container |
docker inspect <c> |
full metadata |
Run flags that matter for data science¶
docker run --rm -it \
-p 8888:8888 \ # ports: host:container
-v "$PWD":/workspace \ # volumes: host dir -> container path
-e CUDA_VISIBLE_DEVICES=0 \ # environment variables
-w /workspace \ # working directory inside
--gpus all \ # GPU access (nvidia-container-toolkit)
--shm-size=8g \ # /dev/shm (PyTorch DataLoader!)
myimage python train.py --lr 0.001
Dockerfile¶
FROM python:3.12-slim # base image
WORKDIR /app # set working dir
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# Install deps FIRST for layer caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Then the code (changes often -> last layer)
COPY . .
CMD ["python", "train.py"] # default command
Build with docker build -t myimage . — each instruction becomes a layer; unchanged layers are cached.
Common Operations¶
Logs, exec, cleanup¶
docker logs -f --tail 100 train # follow training output
docker exec -it train python -c "import torch; print(torch.__version__)"
docker stats # live CPU/RAM of containers
docker top train # processes inside
Volumes & data¶
# Named volume (managed by Docker, survives container removal)
docker volume create mydata
docker run -v mydata:/data myimage
# Bind mount (host folder <-> container) — dev workflow
docker run -v "$PWD":/workspace myimage
# Copy files without volumes
docker cp results.csv train:/app/results.csv
docker cp train:/app/checkpoint.pt ./checkpoint.pt
docker volume ls && docker volume prune
| Volume type | Lives where | Use for |
|---|---|---|
| Named volume | Docker-managed | persistent DB/artifacts |
| Bind mount | your host path | live code, datasets |
| tmpfs | RAM | scratch only |
Networks & ports¶
docker network create mynet
docker run --network mynet --name api myimage
docker run --network mynet --name db postgres:16
# containers reach each other by name: api -> db:5432
docker port <c> # which host port maps where
docker network ls
Port publishing -p 8888:8888: host 8888 → container 8888. Omit -p and the container's port is not reachable from the host.
Registries (sharing images)¶
docker login # Docker Hub / GHCR / ECR ...
docker tag myimage ghcr.io/you/myimage:v1
docker push ghcr.io/you/myimage:v1
docker pull ghcr.io/you/myimage:v1
For private registries set credentials via docker login or CI secrets — never bake passwords into an image.
Practical Examples¶
1. Jupyter with GPU in one command¶
docker run --rm -d --gpus all \
-p 8888:8888 -v "$PWD":/home/jovyan/work \
-e JUPYTER_TOKEN=secret \
jupyter/datascience-notebook:latest
# open http://localhost:8888 (token: secret)
2. ML training image (multi-stage keeps it slim)¶
FROM python:3.12-slim AS base
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ ./src/
CMD ["python", "-m", "src.train"]
3. Two containers that talk (model + API) — see docker-compose.md for the sane way¶
docker network create appnet
docker run -d --network appnet --name api -p 8000:8000 myapi:latest
docker run --rm --network appnet -e API_URL=http://api:8000 myclient:latest
Common Patterns¶
# Interactive debugging of a build/runtime problem
docker run --rm -it --entrypoint bash myimage
docker run --rm -it myimage python
# Ephemeral throwaway run
docker run --rm -v "$PWD":/w -w /w python:3.12 python script.py
# Rebuild + rerun loop during development
docker build -t myimage . && docker run --rm -v "$PWD":/workspace myimage
# Cleanup (careful — see cleanup)
docker container prune -f # stopped containers
docker image prune -f # dangling images
docker system df # what's taking space
Best Practices¶
- Order Dockerfile for caching: requirements first, code last; use
--no-cache-dir. - Prefer slim images (
python:3.12-slim) and multi-stage builds — smaller attack surface, faster pulls. - Never store secrets in images — use
-e, env files, or secrets mounts. - Run as a non-root user in production images (
USER 1000). - One process per container; manage several with Docker Compose.
- Always mount data (volumes) rather than
COPYing large datasets into images. - Pin base-image tags (
python:3.12-slim, notlatest) for reproducibility. - Set
--shm-sizefor PyTorch multi-worker DataLoaders. - Tag with a version (
:v1) or commit SHA for deployment; use.dockerignore(.git,data/,.venv/).
Common Mistakes¶
| Mistake | Consequence | Fix |
|---|---|---|
COPY . . before installing deps |
Every code change rebuilds pip install | Order: deps → code |
No .dockerignore |
.venv, data, .git copied in → huge images |
Add .dockerignore |
Forgetting -p |
Can't reach the service | Publish the port |
| Writing to the container FS | Data lost on rm |
Mount a volume |
latest tags everywhere |
Non-reproducible deploys | Pin versions |
| Running as root | Security risk | USER non-root |
| PyTorch DataLoader hangs/crashes | /dev/shm too small |
--shm-size=8g |
docker run without --rm accumulation |
Disk fills with stopped containers | --rm + periodic prune |
Troubleshooting¶
| Symptom | Cause | Fix |
|---|---|---|
Cannot connect to the Docker daemon |
Engine not running / perms | Start Docker Desktop/daemon; sudo usermod -aG docker $USER + logout |
no space left on device |
Full image cache | docker system prune -af |
CUDA error: no kernel image available |
Image built for wrong CUDA | Match base image to driver; rebuild |
| Container exits immediately | App crashed or no foreground process | docker logs <c>; run -it to see |
port is already allocated |
Two containers, one port | Change -p or stop the other |
| Can't reach service in another container | Wrong network | Same docker network; use container name, not localhost |
permission denied on mounted files |
Host file perms vs container user | chmod on host; run with matching --user |
| Image build slow every time | Cache busted by early COPY | Reorder; check .dockerignore |
Related Cheat Sheets¶
- docker-compose.md — multi-service apps (ML + DB + UI)
- DevOps · github-actions.md — build & push in CI
- MLOps — serving models as containers
- linux-commands.md — shell inside containers
- Home · Central Navigation Index
Official Documentation¶
Last Updated¶
2026-09-06 — Initial version.