Kleinere Docker Images mit uv
Die CI/CD-Pipeline dauert ewig? Das lokale Bauen eines Container-Images dauert viel zu lange? Ein möglicher Grund dafür könnte die Größe der Container-Images sein – oft sind sie unnötig aufgebläht. In diesem Artikel werden verschiedene Strategien vorgestellt, um Images zu optimieren und effizienter und schneller zu gestalten. 🚀
Keine unnötigen Dependencies
Ein gewachsenes Projekt mit zahlreichen Abhängigkeiten in der pyproject.toml kann schnell unübersichtlich werden. Bevor der nächste Schritt – beispielsweise die Containerisierung mit Docker – angegangen wird, lohnt es sich zunächst zu prüfen, welche Abhängigkeiten tatsächlich noch benötigt werden und welche mittlerweile obsolet sind. So lässt sich die Codebasis verschlanken, potenzielle Sicherheitsrisiken reduzieren und die Wartbarkeit verbessern.
Eine Möglichkeit wäre, alle Dependencies sowie das Virtual Environment zu löschen und anschließend den Quellcode Datei für Datei durchzugehen, um nur noch die wirklich benötigten Abhängigkeiten hinzuzufügen. Eine effizientere Strategie bietet das Command-Line-Tool deptry
. Es übernimmt diese mühsame Aufgabe und hilft dabei, überflüssige Abhängigkeiten schnell zu identifizieren. Die Installation erfolgt mit
uv add --dev deptry
Anschließend lässt sich die Analyse des Projekts direkt im Projektordner mit folgendem Befehl starten
deptry .
Danach listet deptry die Dependencies auf die nicht mehr benutzt werden
Scanning 126 files... pyproject.toml: DEP002 'pandas' defined as a dependency but not used in the codebase Found 1 dependency issue.
In diesem Fall scheint pandas
nicht mehr genutzt zu werden. Es empfiehlt sich, dies zu überprüfen und anschließend alle nicht mehr benötigten Abhängigkeiten zu entfernen.
uv remove pandas
Alternativer Index
Wenn ein Paket wie pytorch
, docling
oder sparrow
genutzt wird, das torch(vision) als Abhängigkeit enthält, und ausschließlich die CPU zum Einsatz kommen soll, kann auf die Installation der CUDA-Bibliotheken verzichtet werden. Dies lässt sich erreichen, indem für torch(vision) ein alternativer Index angegeben wird. uv sucht das Paket dann zunächst dort, wobei in diesem Index keine Abhängigkeiten zu den CUDA-Bibliotheken für torch(vision) definiert sind. Dazu wird in der pyproject.toml unter dependencies folgender Eintrag ergänzt:
[tool.uv.sources] torch = [ { index = "pytorch-cpu" }, ] torchvision = [ { index = "pytorch-cpu" }, ] [[tool.uv.index]] name = "pytorch-cpu" url = "https://download.pytorch.org/whl/cpu"
So sehen die Images mit und ohne alternativem Index aus:
REPOSITORY TAG IMAGE ID CREATED SIZE sample_torchvision gpu f0f89156f089 5 minutes ago 6.46GB sample_torchvision cpu 0e4b696bdcb2 About a minute ago 657MB
Mit dem alternativen Index ist das Image nur noch 1/10 so groß!
Das richtige Dockerfile
Unabhängig davon, ob das Python-Projekt gerade erst startet oder bereits länger besteht, lohnt sich ein Blick auf die von uv bereitgestellten Beispiel-Dockerfiles: uv-docker-example.
Diese bieten eine sinnvolle Grundkonfiguration und sind darauf optimiert, möglichst kleine Images zu erzeugen. Sie sind ausführlich kommentiert und nutzen ein minimales Base-Image mit vorinstalliertem Python und uv. Dependencies und das Projekt werden in separaten Befehlen installiert, sodass das Layer-Caching optimal funktioniert. Dabei werden nur die regulären Dependencies installiert, während Dev-Dependencies wie das oben installierte deptry ausgelassen werden.
Im Multi-Stage-Sample werden zudem nur das Virtual Environment und die Projektdateien in das Runtime-Image kopiert, sodass keine überflüssigen Build-Artefakte im finalen Image landen.
Bonustipp für Azure WebApp Nutzer
Dieser Tipp verkleinert zwar nicht das Image, kann einem aber im Ernstfall einige Kopfschmerzen ersparen.
Wenn das Docker-Image in einer Azure WebApp deployed wird, sollte /home oder darunterliegende Pfade nicht als WORKDIR
verwenden. Der /home-Pfad kann genutzt werden, um Daten über mehrere WebApp-Instanzen hinweg zu teilen. Dies wird durch die Umgebungsvariable WEBSITES_ENABLE_APP_SERVICE_STORAGE
gesteuert. Ist diese auf true gesetzt, wird der gemeinsame Speicher nach /home
gemountet, wodurch die im Image enthaltenen Dateien im Container nicht mehr sichtbar sind.
(Wenn das Dockerfile sich an den uv-Beispielen orientiert, dann ist das WORKDIR
bereits korrekt unter „/app“ konfiguriert.)