Zum Inhalt springen

Eigene Runtime-Images

Manchmal fehlt dem Envoryx-Image genau ein Paket. Deine PDF-Bibliothek will Ghostscript, eine PHP-Erweiterung steht nicht in der Liste, oder das Team hat schon ein gehärtetes Basis-Image. Dafür kann eine Runtime statt des Envoryx-Images ein eigenes verwenden.

Eingestellt wird das im Bereich Laufzeit des Projekts, auf der Karte Runtime-Images ganz unten. Sie hat eine Zeile für jede Runtime, die das Projekt hat (PHP, Node.js, Python, Go, Ruby, Java, .NET), und das Feld Image bietet drei Möglichkeiten: Envoryx-Image (der Standard), Image aus einer Registry und Dockerfile im Projekt. Datenbanken, die anderen Dienste und der Webserver behalten immer die Envoryx-Images. Worker und Cron-Jobs laufen im Image ihrer Runtime, sie folgen also deiner Wahl.

Trag eine beliebige Referenz in Image-Referenz ein, etwa ghcr.io/acme/php:8.4, und speichere. Envoryx holt das Image sofort, ein inzwischen verschobener Tag wird also berücksichtigt, und jeder Neustart holt es erneut, genau wie bei den Envoryx-Images. Läuft das Projekt, werden seine Container gleich mit dem neuen Image neu erstellt; sonst greift es beim nächsten Start.

Zu dieser Variante würde ich zuerst greifen, weil das Dockerfile neben dem Code im Repository liegt und das ganze Team dasselbe Image bekommt. Gib den Pfad relativ zum Projektverzeichnis an; das Feld schlägt .envoryx/php.Dockerfile vor (oder node, python, … für die anderen Runtimes). Envoryx baut es und taggt das Ergebnis als envoryx-build/<runtime>:<hash>.

Starte vom Envoryx-Image deiner Version, dann behältst du alles, worauf Envoryx sich verlässt (Composer, Xdebug, Mail an Mailpit und so weiter), und ergänzt nur, was fehlt:

.envoryx/php.Dockerfile
FROM ghcr.io/envoryx/envoryx-php:8.4
RUN apt-get update && apt-get install -y --no-install-recommends ghostscript \
&& rm -rf /var/lib/apt/lists/*
COPY conf/ /usr/local/etc/php/conf.d/

Das Verzeichnis des Dockerfiles ist der Build-Kontext, und es geht komplett an Docker. Deshalb gehört das Dockerfile in ein eigenes Verzeichnis wie .envoryx/ und nicht ins Projektverzeichnis selbst: Ein Kontext mit mehr als 5000 Dateien oder 512 MB wird abgelehnt. Symbolische Links darin bleiben außen vor, und eine .dockerignore wird nicht gelesen. Envoryx baut mit dem klassischen Builder von Docker, Syntax, die nur BuildKit kennt, etwa RUN --mount=… oder Heredocs, funktioniert also nicht.

Der Hash im Tag deckt das Dockerfile und jede Datei daneben ab. Änderst du eine davon, baut der nächste Start oder Neustart ein neues Image; lässt du sie in Ruhe, wird nichts zweimal gebaut. Ein Neustart baut, bevor er irgendetwas stoppt, ein kaputtes Dockerfile lässt das laufende Projekt also, wie es ist. Ein fehlgeschlagener Build behält deine Einstellung und zeigt seine Ausgabe aufgeklappt unter der Zeile, mit dem Hinweis Build fehlgeschlagen. Du korrigierst die Datei und versuchst es noch einmal. Projekte mit demselben Kontext teilen sich das Image, und eine Branch-Umgebung baut das Dockerfile ihres eigenen Branches.

Ohne Cache neu bauen baut noch einmal, mit frisch geholten Basis-Images und ohne den Build-Cache von Docker. Das brauchst du, wenn sich in deinem Kontext nichts geändert hat, aber in der Welt drumherum: ein neues Envoryx-Image unter demselben Tag oder ein apt-get, das neuere Pakete holen soll.

Envoryx erwartet ein paar Programme in einem Runtime-Image und prüft deshalb jedes Image, wenn du es einstellst, und nach jedem Build. Dazu startet es das Image einmal mit sh -c und sucht nach:

Runtime Nötig Fehlt es, gibt es kein …
alle sh git (git im Terminal, Pakete aus Git-Repositorys), socat (Warten auf die Datenbank beim Start, SSH-Portweiterleitung), ssh (git über SSH mit dem Deploy-Key), rsync (rsync über SSH)
PHP php, php-fpm composer (Composer-Installationen), msmtp (mail() an Mailpit), die Xdebug-Erweiterung (Step-Debugging)
Node.js node, npm corepack (pnpm und Yarn)
Python python3 (oder python) pip (pip-Installationen), uv (uv-Projekte)
Go go air (Live-Reload), dlv (Debugging), gotestsum (Test-Reports)
Ruby ruby, bundle rdbg (Debugging)
Java java mvn, gradle (Maven- und Gradle-Projekte ohne Wrapper)
.NET dotnet netcoredbg (Debugging), dotnet-ef (EF-Core-Migrationen)

Außerdem schaut es sich das Image selbst an. Ein ENTRYPOINT, der weder tini noch dumb-init noch einer der Entrypoints der offiziellen Images ist, wird genannt, weil er vor jedem Befehl läuft, den Envoryx startet, und mit exec "$@" enden muss. Ein PHP-Image, das nicht auf dem Envoryx-PHP-Image aufbaut, bekommt den Hinweis, dass die Erweiterungs-Schalter in der PHP-Karte bei ihm nichts bewirken, und ein Image, das auf dem Envoryx-Image einer anderen Runtime aufbaut, wird ebenfalls erwähnt.

Was fehlt, steht unter Dem Image fehlt, was Envoryx erwartet, jede Zeile mit dem, was dann nicht funktioniert, zum Beispiel socat is missing: no waiting for the database at start and SSH port forwarding (diese Meldungen kommen vom Server und sind englisch). Das ist eine Warnung, keine Ablehnung: Envoryx verwendet das Image trotzdem. Fehlt nichts, steht in der Zeile Alles, was Envoryx braucht, ist da.

Für ein Image hinter einem Login trägt ein Admin der Instanz die Registry unter Einstellungen → Private Registries mit Zugang hinzufügen ein: den Host (ghcr.io, registry.example.com:5000 oder docker.io für Docker Hub), einen Benutzernamen und ein Passwort oder Token. Bei GHCR ist das ein Token mit read:packages. Envoryx nutzt den Zugang zum Holen der Images und gibt ihn an Builds für ihre FROM-Images weiter, ein Dockerfile kann also auch von einem privaten Basis-Image starten. Das Passwort wird nie wieder angezeigt; speicherst du die Karte ohne, bleibt das hinterlegte. Stellst du ein Image ein, das sich mangels Login nicht holen lässt, verweist dich die Fehlermeldung auf diese Karte. Ist der Login eingetragen, speicherst du dasselbe Image am Projekt einfach noch einmal: Envoryx holt es dann, prüft es und setzt es ein. Ein Neustart tut dasselbe.

Ein Image einzustellen oder zum Envoryx-Image zurückzukehren braucht die Admin-Rolle im Projekt, wie das Ändern einer Runtime. Entwickler dürfen Ohne Cache neu bauen. Gebaute Images, die niemand mehr benutzt, tauchen auf der Seite Docker bei den anderen ungenutzten Images auf; Images aus deinen Registries entfernt Envoryx nie.

In der envoryx.yml nimmt jede Runtime image: oder dockerfile:, nie beides:

php:
version: "8.4"
dockerfile: .envoryx/php.Dockerfile
node:
version: "24"
image: ghcr.io/acme/node-tools:24

Git-Operationen und Templates verwenden übrigens weiter das Envoryx-Image. Sie brauchen dessen Werkzeuge, und ein Dockerfile aus dem Repository gibt es vor dem Klonen noch nicht.