Docker provides a consistent runtime environment for all projects, and Make turns common multi-step workflows into single commands. Together they eliminate “it works on my machine” problems and make projects reproducible.
make run, make test) hide the complexity of Docker flags.Modern Dockerfile with uv
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
WORKDIR /app
# Copy dependency files
COPY pyproject.toml uv.lock ./
# Install dependencies using uv
RUN uv sync --frozen --no-dev
# Copy source code
COPY . .
# Default command
CMD ["uv", "run", "python", "app.py"]
Best practices
uv base image for fast, modern Python package management.WORKDIR (/app) to keep paths consistent.pyproject.toml and uv.lock first, install dependencies, then copy source — leverages Docker layer caching.uv sync --frozen --no-dev for reproducible builds from lock files.uv run to execute Python commands within the managed environment.Running with volume mounts
docker run --rm -it -v $(pwd):/app -w /app clinic-demo uv run python script.py
-v $(pwd):/app mounts the local repo into the container.-w /app sets the working directory.IMAGE=clinic-demo
TAG=latest
.PHONY: build run test lint shell clean sync
# Build Docker image
build:
docker build -t $(IMAGE):$(TAG) .
# Run the main application
run:
docker run --rm -it -v $(PWD):/app -w /app $(IMAGE):$(TAG) uv run python app.py
# Run tests
test:
docker run --rm -it -v $(PWD):/app -w /app $(IMAGE):$(TAG) uv run pytest -q
# Run linting
lint:
docker run --rm -it -v $(PWD):/app -w /app $(IMAGE):$(TAG) uv run ruff check .
# Interactive shell in container
shell:
docker run --rm -it -v $(PWD):/app -w /app $(IMAGE):$(TAG) bash
# Sync dependencies (run after updating pyproject.toml)
sync:
docker run --rm -it -v $(PWD):/app -w /app $(IMAGE):$(TAG) uv sync
# Clean up Docker images
clean:
docker rmi $(IMAGE):$(TAG) || true
Wrap common Docker commands in a Makefile at the repo root:
make build → builds image with uv dependenciesmake run → runs app with volume mount for dev loopmake test → runs pytest in container via uvmake lint → runs ruff via uvmake shell → interactive shell in containermake sync → updates dependencies from pyproject.tomlmake clean → removes Docker imagesDependency management:
pyproject.toml instead of requirements.txtuv.lock) ensure reproducible buildsuv sync replaces pip install -r requirements.txtExecution:
uv run python script.py instead of direct python script.py[project.optional-dependencies]Performance benefits:
examples/minimal-make/ for a complete working setup with a Dockerfile, Makefile, and pyproject.toml using the modern uv workflow.