11 KiB
Docker Containerization Roadmap
Ziel
Die Blender-Rendering-Pipeline soll vollständig containerisiert und später in eine verteilte Job-Infrastruktur integriert werden.
Wichtige Randbedingungen:
- Blender-Container sollen nur laufen, wenn tatsächlich Renderaufträge vorhanden sind.
- Verschiedene Jobtypen sollen unterschiedliche Container verwenden können.
- Die Infrastruktur soll zukünftig nicht nur Blender-Rendering, sondern auch andere Workloads (AI-Training, STL-Verarbeitung, Datensatz-Generierung, Batch-Konvertierungen usw.) unterstützen.
- Die Ausführung soll auf mehreren PCs/Worker-Nodes möglich sein.
- Die bestehende Python-Logik soll möglichst unverändert bleiben.
Review / Bewertung
Gesamteinschätzung: schlüssig und machbar. Die Zielarchitektur (Redis-Queue + Nomad-Scheduler, Container nur bei Bedarf, mehrere Workload-Typen, horizontale Skalierung) ist tragfähig und zukunftssicher. Es fehlen einige technische Punkte, die unten ergänzt sind.
Wichtigste Korrektur: Renderer und Pipeline sind ZWEI Container, nicht einer
Phase 1 spricht von „Rendering-Pipeline + Analyse-Pipeline" in einem Container. Das sollte getrennt werden — die beiden haben grundverschiedene Profile:
| Render-Container | Pipeline-Container | |
|---|---|---|
| Image | approbot/blender-renderer |
approbot/pose-pipeline |
| Basis | Blender 4.5 + bpy + cv2 + numpy (~1–2 GB) | python:3.11-slim + numpy/scipy/opencv (~200 MB) |
| GPU | ja (Cycles, CUDA/OPTIX) | nein |
| Zweck | Test-Datengenerator (nur Sim/Dev) | Produkt (läuft auch mit echten Webcam-Fotos!) |
| Änderungsrate | selten | häufig |
| CI-tauglich | nein (schwer, GPU) | ja (schnell, headless) |
Das ist keine Kosmetik: Die Pipeline ist das eigentliche Deliverable (Roboter-Pose aus Fotos) und wird real deployed; der Renderer ist nur Werkzeug zur Testdaten-Erzeugung. Getrennt heißt: die Pipeline bleibt schlank, schnell CI-testbar und ohne Blender-Ballast deploybar; der Renderer wird nur dort gestartet, wo eine GPU steht.
Datenaustausch zwischen beiden: gemeinsames Volume (Phase 1–3), später Object-Storage (MinIO/S3) im verteilten Betrieb.
Technische Schlüsselpunkte (bisher nicht in der Roadmap)
- cv2 in Blenders Python:
render_robot.pyimportiertcv2(ArUco-Generierung). Blender bringt sein eigenes gebündeltes Python mit —opencv-pythonmuss dort installiert werden (<blender>/python/bin/python -m pip install opencv-python), nicht ins System-Python. Häufige Stolperfalle. - ArUco = opencv-contrib: Die Pipeline nutzt
cv2.aruco. Im Pipeline-Containeropencv-contrib-python-headlessverwenden (nicht Basis-opencv-python), Version pinnen. - robot.json-Mutation ist im Parallelbetrieb ein Race:
render_Loop.pyschreibt pro Render in die gemeinsamerobot.json(Kamera, Pose, Auflösung). Laufen mehrere Render-Jobs parallel auf einem Node, überschreiben sie sich gegenseitig. Im Job-Modell muss jeder Job seine Parameter aus dem Job-Payload bekommen und in eine eigene temporäre Config schreiben — nicht in die geteilte robot.json. (Architektur-Fix, gehört vor Phase 4.) - GPU im Container & Scheduler:
--gpus all+ NVIDIA Container Toolkit; Nomad braucht das GPU-Device-Plugin, damit Render-Jobs nur auf GPU-Nodes landen. CPU-Fallback (Cyclesdevice='CPU') als Sicherheitsnetz behalten. - Versionen pinnen: Blender 4.5.x exakt,
requirements.txtmit festen Versionen (numpy/scipy/opencv) — sonst driften die Mess-Ergebnisse (vgl. der fy-Intrinsik-Bug). - Job-Granularität:
{"jobType":"blender-render","pose":8}rendert 7 Kameras pro Job. Feinkörniger (1 Job = 1 Kamera) parallelisiert besser über mehrere Nodes — abwägen.
Empfehlung: MVP vor Nomad
Redis + Nomad ist die richtige End-Vision, aber als Zwischenstufe genügt docker-compose
mit zwei Images + Profiles (Renderer on-demand via docker compose run, Pipeline als
schneller Service / CI-Step). Damit sind getrennte Container + Phase 1–3 produktiv nutzbar,
bevor die verteilte Orchestrierung (Phase 5–8) aufgebaut wird.
Phase 1 – Dockerisierung der bestehenden Rendering-Pipeline
Ziel
Die aktuelle Blender-Pipeline läuft vollständig innerhalb eines Docker-Containers.
Aufgaben
Code/Infrastruktur erstellt (Dateien in setup/generateSets/):
Dockerfile.renderer(Ubuntu + Blender 4.5 headless) undDockerfile.pipeline(slim Python)docker-compose.ymlmit beiden Services + gemeinsamemdata-Volume- cv2 in Blenders gebündeltem Python (im Renderer-Dockerfile) — nicht System-Python
requirements.pipeline.txt(numpy, scipy, opencv-contrib-python-headless), gepinnt- Pfad-/Config-env in
render_robot.py(ROBOT_JSON,RENDER_OUTPUT) undrender_Loop.py(BLENDER_EXE) pipeline/run_pipeline.py— plattformunabhängiger Orchestrator (1→2→3→3b→4), lokal getestetREADME.docker.mdmit Build-/Run-Anleitung- Portainer-Skript:
curl→curl.exe(PowerShell-Alias-Falle) gefixt
Im Container zu verifizieren (Docker/GPU lokal nicht testbar in der Entwicklung):
docker compose build(Blender-Download/-Version prüfen)render_Loop.py/render_robot.pyim Renderer-Container (STL-Import, PNG, NPZ, markers.json)pipeline/run_pipeline.pyim Pipeline-Container auf den gerenderten PNGs
Ergebnis
Zwei Container: approbot/blender-renderer erzeugt Bilder/npz/Ground-Truth,
approbot/pose-pipeline wertet sie aus — beide reproduzierbar, über ein gemeinsames
data-Volume verbunden. Der Pipeline-Orchestrator nutzt pro Kamera die eigene npz
(wichtig wegen der per-Kamera-Kalibrierfehler aus dem Linsenfehler-Feature A).
Phase 2 – Pfad-Unabhängigkeit
Ziel
Alle absoluten Benutzerpfade entfernen.
Aktuelle Situation
Beispiel:
Path.home() / "SynologyDrive" / ...
Ziel
Container-interne Pfade verwenden:
/workspace/data
/workspace/setup
/workspace/output
Aufgaben
- ROBOT_JSON_FILE auf Containerpfade umstellen
- OUTPUT_FILE auf Containerpfade umstellen
- STL-Suche auf Containerpfade umstellen
- Konfiguration über Environment-Variablen ermöglichen
- render_robot.py: Config-Pfad per env (
ROBOT_JSON) statt hardcodiert; und render_Loop.py: pro Render eine temporäre Config schreiben statt die geteilte robot.json zu mutieren (Voraussetzung für parallele Jobs, siehe Schlüsselpunkt 3) - BLENDER_EXE per env/PATH (aktuell hardcodierter Windows-Pfad)
Ergebnis
Die Pipeline ist vollständig unabhängig vom lokalen Benutzerprofil und parallel-tauglich.
Phase 3 – Repository-Struktur bereinigen
Ziel
Klare Trennung zwischen Code, Daten und Ergebnissen.
Zielstruktur
appRobotRendering/
├── data/
│ ├── robot/
│ ├── simulation/
│ └── surfaces/
│
├── setup/
│ └── generateSets/
│ ├── render_loop.py
│ ├── render_robot.py
│ ├── Dockerfile
│ └── docker-compose.yaml
│
├── jobs/
│
└── output/
Aufgaben
- Verzeichnisstruktur vereinheitlichen
- Dokumentation ergänzen
- Mountpoints definieren
Phase 4 – Job-Modell einführen
Ziel
Rendering-Aufträge werden als eigenständige Jobs beschrieben.
Beispiel
{
"jobType": "blender-render",
"pose": 8
}
Spätere Erweiterungen
{
"jobType": "dataset-generation"
}
{
"jobType": "stl-conversion"
}
{
"jobType": "ai-training"
}
Aufgaben
- Job-Format definieren
- Job-Metadaten definieren
- Retry-Konzept definieren
- Statusmodell definieren
Status
queued
running
completed
failed
timeout
Phase 5 – Redis als Queue
Ziel
Entkopplung zwischen Auftragserzeugung und Ausführung.
Aufgaben
- Redis bereitstellen
- Job-Queue definieren
- Job-Status speichern
- Retry-Mechanismus definieren
Hinweis
Redis startet keine Worker.
Redis dient ausschließlich als:
- Queue
- Statusspeicher
- Kommunikationsschicht
Phase 6 – Nomad Scheduler
Ziel
Container werden nur bei tatsächlichem Bedarf gestartet.
Architektur
Job Producer
│
▼
Redis
│
▼
Nomad
│
▼
Docker Container
Aufgaben
- Nomad Server aufsetzen
- Worker-Nodes registrieren
- Docker Driver aktivieren
- Batch-Jobs definieren
Ergebnis
Nomad entscheidet:
- welcher Node frei ist
- welcher Container gestartet wird
- wann ein Container beendet wird
Phase 7 – Blender als Nomad Batch Job
Ziel
Blender läuft nur während der Bearbeitung eines Auftrags.
Beispiel
Job:
blender-render
Container:
approbot/blender-renderer:latest
Ablauf:
- Job wird eingereicht
- Nomad startet Blender-Container
- Rendering läuft
- Ergebnisse werden gespeichert
- Container beendet sich
- Ressourcen werden freigegeben
Ergebnis
Keine dauerhaft laufenden Blender-Worker.
Phase 8 – Multi-Container Plattform
Ziel
Beliebige Jobtypen auf derselben Infrastruktur ausführen.
Beispiele
Blender Rendering
Container:
approbot/blender-renderer
AI Training
Container:
approbot/trainer
STL Processing
Container:
approbot/stl-worker
Dataset Generation
Container:
approbot/dataset-worker
Ergebnis
Der verwendete Container wird durch den Jobtyp bestimmt.
Zielarchitektur
Nomad
│
┌────────────────┼────────────────┐
│ │ │
Blender Job AI Job Dataset Job
│ │ │
Blender Training Dataset Worker
Container Container Container
└────────────────┼────────────────┘
│
Docker
│
Worker Nodes (PCs)
Eigenschaften:
- keine dauerhaft laufenden Blender-Container
- unterschiedliche Container pro Jobtyp
- horizontale Skalierung auf mehrere PCs
- saubere Trennung von Scheduling und Ausführung
- zukünftige Erweiterbarkeit für beliebige Workloads
Offene Punkte / nicht vergessen
- Cluster-Storage: geteiltes NFS/Volume (einfach) vs. Object-Storage MinIO/S3 (entkoppelt Nodes, skaliert). Ab >1 Worker-Node bevorzugt Object-Storage.
- robot.json als geteilter Mutable-State auflösen (Schlüsselpunkt 3) — Voraussetzung für parallele Render-Jobs auf einem Node.
- Reproduzierbarkeit: Blender- und Python-Versionen pinnen;
requirements.txteinchecken. - GPU-Headless: prüfen, ob Cycles im Container EGL braucht; sonst CPU-Fallback verifizieren.
- CI-Hook: Pipeline-Container in CI →
benchmark/run_benchmark.pygegen Ground-Truth bei jedem Commit (schnell, ohne Blender) — fängt Regressionen wie den fy-Bug automatisch. - Monitoring/Logs: Job-Logs zentral (stdout → Nomad/Loki), Render-Zeiten messen.
- Image-Registry: private Registry (Harbor o. Ä.) für die
approbot/*-Images.