Kursteilnehmer, die nichts installieren müssen
Der Dozent lädt ein ZIP mit dem Kursmaterial hoch. Daraus entsteht automatisch eine fertige Cloud-IDE, und die Teilnehmer öffnen die Lektion im Browser und programmieren sofort, mit den richtigen Paketversionen und den Daten schon an ihrem Platz.
Ausgangslage
Jeder, der schon mal einen Programmierkurs gegeben hat, kennt die erste halbe Stunde: Paket lässt sich nicht installieren, falsche Sprachversion, unter Windows geht etwas anders als unter macOS, und die Firewall des Arbeitgebers blockt den Download. Bei einem Live-Format mit vielen Teilnehmern gleichzeitig kostet das genau den Teil der Sitzung, für den die Leute gekommen sind.
Ziel
Teilnehmer sollen eine Lektion öffnen und loslegen können. Kein Setup, keine Installation, und es spielt keine Rolle, was auf dem eigenen Rechner läuft.
Die Rahmenbedingungen gibt größtenteils Posit Workbench vor, samt einer kommerziellen Lizenz, die pro Server eingespielt werden muss.
Lösung
Für den Dozenten sieht es nach wenig aus. Er lädt zu einer Lektion oder einem Webinar ein ZIP hoch, das neben dem Kursmaterial eine kleine Konfigurationsdatei enthält: R oder Python oder beides, welche Versionen, welche Systempakete, welche Setup-Schritte, welche IDE-Extensions. Danach übernimmt ein Hintergrundjob, dessen Status im Admin-Bereich der Lernplattform mitläuft, bis die Umgebung erreichbar ist. Bei Webinaren entsteht zusätzlich ein kleiner Preview-Server, auf dem er vorher nachsehen kann, ob alles so aussieht wie gedacht.
Für die Teilnehmer sieht es nach noch weniger aus. Sie öffnen die Lektion, es gibt keinen zweiten Login, und nach einem kurzen Ladebildschirm mit Fortschrittsanzeige sitzen sie in einer laufenden Positron-Session, die schon im Kursordner geöffnet ist. Beim ersten Aufruf wird im Hintergrund ihr Konto samt Home angelegt und eine eigene Kopie der Kursdateien hineingelegt. Was sie darin ändern, überlebt einen Session-Neustart.
Ergebnis
Wo es knifflig wurde
Eine gebaute Umgebung für Hunderte eigener Home-Verzeichnisse
Workbench legt pro Teilnehmer einen eigenen Linux-Nutzer mit eigenem Home an. Der naheliegende Weg, die Pakete beim Build als root zu installieren, scheitert lautlos: die üblichen Installationspfade der R- und Python-Toolchains landen im Home von root und sind für die Session-Nutzer nicht lesbar. Bemerkt wird das erst zur Laufzeit, mitten im Kurs, als „Permission denied“ oder als fehlendes Paket. Der zweite naheliegende Weg, jedem sein eigenes Environment zu geben, dupliziert mehrere Gigabyte pro Person und ist bei einem Live-Kurs nicht tragbar. Die Umgebung liegt deshalb genau einmal außerhalb aller Homes, lesbar für alle und für niemanden beschreibbar; kopiert wird nur das Kursmaterial.
Konfiguration, die in der Session nie ankommt
Sessions startet der Job Launcher über PAM, am Container-Entrypoint vorbei. Damit stimmt die Grundannahme nicht mehr, dass Environment-Variablen aus dem Dockerfile in der Session ankommen. Das Tückische daran: nichts schlägt fehl. Die Session startet, nur findet R seine Library nicht und die Python-Konsole kommt gar nicht hoch. Unangenehm zu debuggen, weil dieselbe Konfiguration in einer Shell im Container völlig korrekt aussieht.
Direkt in einer laufenden IDE landen, im iframe, cross-site
Workbench zeigt nach dem Login normalerweise eine Projektübersicht, und eine frisch gestartete Session braucht einen Moment, bis sie bedienbar ist. Für einen Kurs ist beides unbrauchbar. Dazu läuft die IDE eingebettet auf einer anderen Domain, wo die Cookie-Defaults aktueller Browser den Login-Flow kaputtmachen. Einfach durchproxyen und weiterleiten endet je nach Zustand in einem Redirect-Loop, einem leeren iframe oder abgewiesenen Session-Requests. Der Proxy schließt den Login deshalb serverseitig ab, stößt den Session-Start selbst an und überbrückt die Wartezeit mit einer eigenen Ladeseite.
Technische Umsetzung
Drei Ebenen, klar getrennt. Der Build läuft einmal pro Bundle: herunterladen, hashen, gegen die Registry prüfen, entpacken, die Konfiguration validieren, daraus ein Dockerfile generieren, bauen, in eine private Registry pushen. Der Image-Tag ist ein Hash aus dem Bundle, den Plattform-Configs und der Generator-Version, also content-addressed: zwei identische Bundles ergeben denselben Tag und werden nicht zweimal gebaut, und eine Änderung am Generator invalidiert alte Images automatisch mit.
Der Deploy erzeugt pro Server eine VM, die über cloud-init einen Reverse Proxy mit automatischem TLS installiert, das Image pullt und den Container ausschließlich an localhost bindet. Danach wird ein DNS-Eintrag gesetzt und so lange gepollt, bis ein HTTPS-Check durchgeht. Erst dann gilt der Deploy als fertig, und das ist ein deutlich verlässlicheres Kriterium als „der Container läuft“. Drei Servertypen mit eigener Lebensdauer: Lektion, Preview für 24 Stunden und Webinar-Slots, die anderthalb Stunden vor dem Termin entstehen und anderthalb Stunden danach wieder verschwinden.
Zur Laufzeit sitzt vorn ein eigener Auth-Proxy in Node, dahinter Workbench, dahinter der Job Launcher, dahinter je Teilnehmer eine Positron-Session. Der Proxy ist die einzige Stelle, die Identität feststellt: er verwirft mitgeschickte Identitäts-Header und setzt sie selbst aus einem Token, das die Lernplattform signiert hat.
Die Reproduzierbarkeit ist der eigentliche Gewinn dieses Aufbaus. Base-Image auf ein konkretes
Release gepinnt, uv auf eine feste Version, die R-Version aus der Kurskonfiguration,
R-Pakete aus dem renv-Lockfile und Python-Pakete aus dem uv-Lockfile im
frozen mode. Ein Kurs, der heute läuft, läuft im nächsten Semester genauso.
Betrieb und Weiterentwicklung
Vom Upload bis zur erreichbaren URL gibt es keinen manuellen Schritt. Ein Cronjob sammelt neue Bundles ein. Schlägt eines fehl, landet der komplette Output des fehlgeschlagenen Kommandos am Datensatz und ist im Admin-Bereich lesbar, ohne dass der Lauf für die anderen stoppt. Preview- und Webinar-Server räumen sich selbst wieder ab, DNS-Eintrag inklusive. Bricht das ab, kann der Job einfach noch mal laufen.
Zwischen den Teilnehmern liegt echte Isolation: eigener Linux-Account, eigenes Home, und die Rechte auf dem Verzeichnis darüber sind so gesetzt, dass niemand die Namen der anderen auflisten kann. Ein Resource-Profil begrenzt Speicher und Prozesse pro Person, damit eine Endlosschleife bei einem Teilnehmer nicht die Sitzung für alle ruiniert.