Docker-Architektur & Build-Caching¶
Diese Seite beschreibt die Docker-Build-Strategie von LLARS und wie das Layer-Caching funktioniert.
Übersicht¶
LLARS besteht aus 17 Docker-Services. Davon werden 9 lokal gebaut, der Rest nutzt offizielle Images.
graph TD
subgraph "Lokal gebaute Images"
FLASK["Flask Backend<br/>14 GB"]
VUE["Vue Frontend<br/>1.5 GB"]
YJS["YJS Server<br/>420 MB"]
NGINX["Nginx<br/>92 MB"]
SUPER["Supervisor<br/>280 MB"]
MKDOCS["MkDocs<br/>276 MB"]
MARIA["MariaDB x2<br/>528 MB"]
LKAGENT["LiveKit Agent<br/>500 MB"]
end
subgraph "Offizielle Images"
AUTH["Authentik Server/Worker"]
PG["PostgreSQL"]
REDIS["Redis x2"]
MATOMO["Matomo"]
LK["LiveKit Server"]
end
Start-Befehle¶
| Befehl | Was passiert | Wann nutzen |
|---|---|---|
./start_llars.sh |
Startet Container mit vorhandenen Images. Kein Build, kein Dockerfile-Check. | Standard. Code-Änderungen kommen über Volume-Mounts. |
./start_llars.sh --build |
Docker prüft alle Dockerfiles. Unveränderte Layer werden aus dem Cache genommen, nur geänderte Layer werden neu gebaut. | Nach Änderungen an requirements.txt, package.json, Dockerfiles oder docker-compose.yml. |
./start_llars.sh --update |
Baut nur Backend + Frontend neu und startet sie. Andere Services bleiben laufen. | Schnelles Update nach Dockerfile-Änderung an Flask oder Vue. |
Zusätzliche Flags¶
| Flag | Beschreibung |
|---|---|
--detach |
Start im Hintergrund (ohne Docker Watch) |
dev / prod |
Erzwingt Development- oder Production-Modus |
Variablen¶
| Variable | Beschreibung |
|---|---|
REMOVE_LLARS_VOLUMES=True |
Löscht alle LLARS-Daten und erzwingt --build automatisch |
PRUNE_LLARS_SYSTEM=True |
Löscht alle LLARS-Container, Images, Volumes und Build-Cache |
Layer-Caching-Strategie¶
Docker baut Images in Layern. Jeder RUN, COPY oder ADD Befehl erzeugt einen Layer. Wenn sich ein Layer nicht geändert hat, wird er aus dem Cache genommen. Sobald sich ein Layer ändert, werden alle folgenden Layer ebenfalls neu gebaut.
Deshalb ist die Reihenfolge entscheidend: Selten geänderte Dinge zuerst, häufig geänderte zuletzt.
Flask Backend (14 GB)¶
Das Backend hat die komplexeste Layer-Struktur:
Layer 1: texlive-full (~5 GB) ← Ändert sich fast nie
Layer 2: System-Pakete (~200 MB) ← Ändert sich selten
Layer 3: Schwere ML-Pakete (~4 GB) ← torch, transformers, flair, chromadb
(requirements-heavy.txt) Ändert sich sehr selten
Layer 4: Python-Pakete (~500 MB) ← requirements.txt
(mit BuildKit Cache-Mount) Ändert sich gelegentlich
Layer 5: Playwright Chromium (~300 MB) ← Ändert sich selten
Layer 6: App-Code (~500 MB) ← Ändert sich häufig
Effekt: Eine Code-Änderung baut nur Layer 6 neu (~Sekunden). Eine Dependency-Änderung baut Layer 4+6 neu. texlive-full und die ML-Pakete bleiben gecacht.
Vue Frontend (1.5 GB)¶
Layer 1: Start-Scripts ← Ändert sich fast nie
Layer 2: npm ci (~400 MB) ← Nur bei package.json-Änderung
(mit BuildKit Cache-Mount)
Layer 3: Source-Code ← Ändert sich häufig
YJS Server (420 MB)¶
Identische Strategie wie Vue.
BuildKit Cache-Mounts¶
Alle Dockerfiles nutzen BuildKit Cache-Mounts:
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
RUN --mount=type=cache,target=/root/.npm \
npm ci
Vorteil: Selbst wenn sich requirements.txt ändert, werden nur die geänderten Pakete heruntergeladen. Der pip/npm Download-Cache bleibt zwischen Builds erhalten.
Build-Context (.dockerignore)¶
Der Build-Context ist das, was Docker beim Bauen an den Daemon sendet. Alles im Projektverzeichnis, das nicht in .dockerignore steht, wird übertragen.
Aktuelle Größe: ~1.3 GB (durch .dockerignore von 6.8 GB reduziert)
Ausgeschlossene große Verzeichnisse:
| Verzeichnis | Größe | Grund |
|---|---|---|
docs/docs/projekte/anonymize/models/ |
2.1 GB | Wird via Volume gemountet |
app/data/rag/ |
638 MB | Laufzeitdaten |
Paper/ |
430 MB | Nicht für Builds benötigt |
app/models/oncoco/model.safetensors |
2.1 GB | Wird via Volume gemountet |
llars-frontend/node_modules |
variabel | Wird im Container installiert |
yjs-server/node_modules |
22 MB | Wird im Container installiert |
npm install beim Start¶
Im Development-Modus mounted Docker das Host-Verzeichnis (./llars-frontend:/vue), was die im Image installierten node_modules überschreibt. Deshalb prüfen die Start-Scripts ob ein Re-Install nötig ist:
# start_vue.sh / start_yjs.sh
if [ ! -d node_modules ] || [ ! -f node_modules/.package-lock.json ]; then
npm install # node_modules fehlen
elif [ package-lock.json -nt node_modules/.install-stamp ]; then
npm install # Dependencies haben sich geändert
else
echo "Skipping" # Alles aktuell
fi
Beim ersten Start nach einem frischen Build wird npm install ausgeführt (~5s für Vue, ~1s für YJS). Bei weiteren Starts wird es übersprungen.
Tipp
Wenn du npm install lokal auf dem Host ausführst, sind die node_modules beim nächsten Container-Start sofort verfügbar.
Service-Abhängigkeiten¶
Die Startup-Reihenfolge wird durch Healthchecks gesteuert:
graph LR
DB["MariaDB"] -->|healthy| FLASK["Flask"]
REDIS["Redis"] -->|healthy| FLASK
FLASK -->|healthy| SUPER["Supervisor"]
FLASK -->|healthy| VUE["Vue Frontend"]
FLASK -->|healthy| LKAGENT["LiveKit Agent"]
AUTH_DB["Postgres"] -->|healthy| AUTH["Authentik"]
AUTH -->|healthy| YJS["YJS"]
AUTH -->|healthy| AUTH_INIT["Authentik Init"]
VUE -->|healthy| NGINX["Nginx"]
FLASK -->|healthy| NGINX
YJS -->|healthy| NGINX
Kritischer Pfad: MariaDB → Flask → Vue → Nginx (~30s)
Image-Größen¶
| Image | Größe | Base Image |
|---|---|---|
| Flask Backend | 14.2 GB | python:3.10-slim + texlive-full |
| Vue Frontend | 1.55 GB | node:23-slim |
| YJS Server | 419 MB | node:23-slim |
| LiveKit Agent | ~500 MB | python:3.11-slim |
| Supervisor | 281 MB | python:3.10-slim |
| MkDocs | 276 MB | python:3.12-alpine |
| Nginx | 92 MB | nginx:alpine |
| MariaDB | 528 MB | mariadb:11.2.6 |
Troubleshooting¶
Build ist langsam¶
# Prüfe Build-Cache-Auslastung
docker system df
# Build-Cache aufräumen (nur nicht verwendete Layer)
docker builder prune
# Alles bereinigen und neu bauen
PRUNE_LLARS_SYSTEM=True ./start_llars.sh --build
Layer-Cache wird nicht genutzt¶
Häufige Ursachen:
- Base Image Update: Wenn
python:3.10-slimein neues Digest hat, werden alle Layer invalidiert. - Reihenfolge: Wenn sich eine Datei ändert, die vor den Dependencies kopiert wird, wird alles danach neu gebaut.
- Build-Context: Große Dateien in
.dockerignorevergessen → langsame Context-Übertragung.
Image zu groß¶
npm install läuft bei jedem Start¶
Prüfe ob node_modules/.install-stamp existiert:
Falls nicht, läuft npm install bei jedem Start. Das passiert wenn das Host-Verzeichnis keine node_modules hat.
Lösung: Einmal lokal cd llars-frontend && npm install ausführen.