Datei Dockerfile im Projektordner (neben pyproject.toml und uv.lock):
dockerfile
FROM python:3.13-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /app
# Zuerst nur die Abhängigkeiten installieren: bleibt im Cache, solange sie sich nicht ändern
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-install-project
# Dann den eigenen Code
COPY . .
# Nicht als root laufen lassen
RUN useradd --create-home app && chown -R app /app
USER app
EXPOSE 8000
CMD ["uv", "run", "--frozen", "--no-dev", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
| Anweisung | Bedeutung |
|---|---|
FROM python:3.13-slim |
Basis-Image. slim ist deutlich kleiner als das volle Image (ca. 130 MB statt 1 GB) |
COPY --from=... /uv /usr/local/bin/uv |
Holt uv aus dem offiziellen Image |
WORKDIR /app |
Arbeitsordner im Container |
COPY quelle ziel |
Kopiert Dateien vom Rechner ins Image |
RUN befehl |
Führt beim Bauen des Images einen Befehl aus |
USER app |
Ab hier läuft alles als normaler Benutzer, nicht als root |
EXPOSE 8000 |
Dokumentiert den Port, öffnet ihn aber nicht von selbst |
CMD [...] |
Befehl, der beim Start des Containers läuft |
Der Server muss auf 0.0.0.0 lauschen, nicht auf 127.0.0.1. Sonst ist er von außerhalb des Containers nicht erreichbar.
Die Datei .dockerignore hält unnötiges und Geheimes aus dem Image:
text
.venv
__pycache__
.git
.env
*.pyc