Django-Docker-Builds optimieren mit uv
Inhaltsverzeichnis
Wer in Docker-Containern Python-Abhängigkeiten mit pip verwaltet, sollte einen Blick auf uv von Astral werfen. Dieses Tool bietet deutlich schnellere Installationen und robustere Verwaltung der Abhängigkeiten. Besonders für Django-Projekte in der CI oder Produktion kann das Build-Tempo spürbar verbessert werden. Auch die Pflege und das Aktualisieren der Abhängigkeiten werden einfacher.
uv im Dockerfile einbinden
Die empfohlene Methode nutzt ein Multi-Stage-Build, um das aktuelle uv-Binary direkt ins Image zu kopieren:
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
So spart man sich die Installation via pip oder Paketmanager und bleibt immer aktuell.
Wichtige Umgebungsvariablen
Im Dockerfile werden zentrale Umgebungsvariablen gesetzt:
ENV UV_PROJECT_ENVIRONMENT=/venv \
UV_NO_MANAGED_PYTHON=1 \
UV_PYTHON_DOWNLOADS=never \
VIRTUAL_ENV=/venvUV_NO_MANAGED_PYTHON=1:uvverwaltet Python nicht selbst.UV_PYTHON_DOWNLOADS=never: Downloads werden komplett deaktiviert.UV_PROJECT_ENVIRONMENT=/venv: Virtuelle Umgebung wird unter/venvverwaltet.
Performance-Verbesserungen
ENV UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy \
UV_CACHE_DIR=/app/.cache/uv- Bytecode wird beim Installieren erzeugt (
.pyc), schnellere Startzeit. - Hardlink-Probleme werden durch Kopieren vermieden.
- Caching via Docker-Mounts beschleunigt Builds enorm.
Sicherheit und Reproduzierbarkeit
ENV UV_FROZEN=1 \
UV_REQUIRE_HASHES=1 \
UV_VERIFY_HASHES=1- Nur exakt definierte Versionen werden installiert.
- Jeder Download wird über einen kryptografischen Hash abgesichert.
Abhängigkeiten installieren
RUN uv venv $VIRTUAL_ENV
RUN --mount=type=cache,target=/app/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --no-install-project --no-editableDiese Befehle installieren exakt die in der uv.lock Datei festgelegten Pakete.
Dev- und Test-Abhängigkeiten verwalten
Mit dependency-groups lassen sich verschiedene Umgebungen differenzieren:
[project] dependencies = ["django~=5.2"]
[dependency-groups]
dev = [“django-debug-toolbar”] test = [“pytest”]
[tool.uv]
default-groups = []
Mit Build-Argumenten lassen sich Gruppen gezielt installieren:
ARG BUILD_GROUPS=""
RUN --mount=type=cache,target=/app/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv venv $VIRTUAL_ENV && \
uv sync --no-install-project --no-editable $BUILD_GROUPSBeispielaufrufe:
# Nur Produktivabhängigkeiten $ docker build . # Mit Entwicklungswerkzeugen $ docker build --build-arg BUILD_GROUPS="--group dev" # Mit Testumgebung $ docker build --build-arg BUILD_GROUPS="--group test"
Migration von pip
Bestehende Projekte lassen sich überführen mit:
uv add --requirements requirements.txt uv add --group dev --requirements requirements-dev.txt uv lock
Pflege und Updates
Veraltete Pakete prüfen:
uv pip list --outdated
Lock-Datei aktualisieren:
uv lock --upgrade
Damit bleibt die Abhängigkeitsverwaltung reproduzierbar, sicher und wartbar.
Diese Methode spart Zeit, Bandbreite und sorgt für eine klar strukturierte und abgesicherte Docker-Infrastruktur für Python-Projekte wie Django. Wer auf schnelle CI/CD-Pipelines, reproduzierbare Builds und saubere Produktionsimages setzt, findet in uv eine moderne und effiziente Lösung.
Hier das finale Dockerfile
### BUILD IMAGE ###
FROM python:3.13-slim AS builder
ENV DJANGO_SETTINGS_MODULE=myproj.settings \
PATH="/venv/bin:$PATH" \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
UV_CACHE_DIR=/root/.cache/uv \
UV_COMPILE_BYTECODE=1 \
UV_FROZEN=1 \
UV_LINK_MODE=copy \
UV_NO_MANAGED_PYTHON=1 \
UV_PROJECT_ENVIRONMENT=/venv \
UV_PYTHON_DOWNLOADS=never \
UV_REQUIRE_HASHES=1 \
UV_VERIFY_HASHES=1 \
VIRTUAL_ENV=/venv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
RUN <<EOT
apt-get update -y && \
apt-get install -y --no-install-recommends \
build-essential \
# other build dependencies here
EOT
WORKDIR /app
ARG BUILD_GROUPS=""
RUN --mount=type=cache,target=/app/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv venv $VIRTUAL_ENV && \
uv sync --no-install-project --no-editable $BUILD_GROUPS
# Copy what's needed to run collectstatic.
COPY myproj /app/myproj
COPY media /app/media
COPY manage.py /app/
RUN DEBUG=False ./manage.py collectstatic --noinput
### FINAL IMAGE ###
FROM python:3.13-slim
ARG PORT=8000
ENV DJANGO_SETTINGS_MODULE=myproj.settings \
PATH="/venv/bin:$PATH" \
PORT=${PORT} \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
VIRTUAL_ENV=/venv
EXPOSE ${PORT}
ENTRYPOINT ["/bin/bash", "/app/bin/run"]
CMD ["prod"]
WORKDIR /app
RUN <<EOT
apt-get clean -y && \
apt-get update -y && \
apt-get install -y --no-install-recommends \
# OS dependencies, e.g. bash, db clients, etc.
bash && \
apt-get autoremove -y && \
apt-get clean -y && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
EOT
# Copy selectively from builder to optimize final image.
# --link enables better layer caching when base image changes
COPY --link --from=builder /venv /venv
COPY --link --from=builder /app/myproj /app/myproj
COPY --link --from=builder /app/static /app/static
COPY --link --from=builder /app/manage.py /app/manage.py
Leave a Reply