Auf den Schultern von Titanen
Rainer Vehns Die Zukunft der IDEs – aus Sicht eines „Java-EE-Entwicklers“ und Jonas Hecht Development Containers & GitHub Codespaces kill the “works on my machine” problem haben Dev Container 2022 schon mal sehr gut sortiert und durchleuchtet: Rainer etwas allgemeiner mit remote (Cloud) IDE und Jonas mit einem Deep Dive Development Container (Dev Container).
Obwohl thematisch eng verwandt, lassen wir Remote IDE in diesem Post aussen vor und fokussieren auf Dev Container.
Kein RFC - Aber Quasi-Standard mit Open Source Spezifikation
Microsoft hat die VS Code Dev Container - Specification als Open Source 2021 offengelegt und pflegt die Spezifikation. IntelliJ implementiert diese Spezifikation ebenfalls, d.h. die Dev Container der beiden aktuellen Schwergewichte unter den IDE’s basieren auf dieser einen Spezifikation. Viele der Remote IDE’s implementieren im Backend entweder VS Code oder IntelliJ Engines. Auf diese Weise ist die VS Code Dev Container Spezifikation eigentlich so etwas wie ein Quasi-Standard.
VS Code - Flexibler Umgang
VS Code pflegt inzwischen einen sehr flexiblen Umgang mit Dev Containern: Man kann in bestehende Container “hooken” und ihn so zu einem Dev Container machen, VS Code erzeugt und verwaltet dann für jeden Dev Container eine Definition in einer eigenen devcontainer.json. Oder man verwendet eine eigene vorgegebene Dev Container Definition mit devcontainer.json, die VS Code direkt starten/öffnen kann.
IntelliJ - Am Start, aber noch nicht am Ziel
Dev Container sind für IntelliJ als Dev Containers Plugin (241.15989.20) verfügbar. IntelliJ setzt zwingend eine initiale bzw. minimale Dev Container Definition mit einer devcontainer.json
voraus. Das macht man entweder händisch oder sucht sich ein passendes Template unter https://github.com/devcontainers/templates, die überwiegend auf Images von mcr.microsoft.com/devcontainers basieren. Kann man diskutieren, ob Vor- oder Nachteil: Wenn keine speziellen Images notwendig sind, spart das einiges an Zeit & Mühe.
Mit der richtigen devcontainer.json
kann IntelliJ auch eine eigene, spezielle Umgebung als Dev Container nutzen. Allerdings erfordert das etwas Denk- und Handarbeit, weil IntelliJ keine Setup-Scripts direkt nutzen oder auf bestehende Container zugreifen kann, sondern ausschließlich devcontainer.json
basiert arbeitet:
- Setup-Aktionen wie z.B. eine DB in einem anderen Nicht-Dev Container inital befüllen oder einen Cache in einen bestimmten Zustand bringen etc. müssen entweder vollständig im Kontext von docker-compose ausgeführt werden oder im Kontext von
devcontainer.json
als Dev Container Lifecycle Scripts im Container realisiert werden werden. Bedeutet für- docker-compose - ggf.
ENTRYPOINT
imdocker-compose.yml
(via command) überschreiben und/oder ggf. Service Spezifikationen imdocker-compose.yml
für Aktionen “missbrauchen” - devcontainer.json - Setup Aktionen als Dev Container Lifecycle Scripts ausführen bedeutet aber letztlich eine engere Verzahnung von Dev Container und containerisierter Umgebung. Als eigenständige Referenzumgebung z.B. im Issue nur noch bedingt bzw. nicht ohne Dev Container IDE nutzbar.
- docker-compose - ggf.
- Das
Dockerfile
, alle Ressourcen, die vom Dockerfile für den Build benötigt werden (Scripts, Config-Files etc.),docker-compose.yml
unddevcontainer.json
müssen im Zugriffspfad der IDE IntelliJ liegen.
Und Eclipse?
Die Grau- bzw. Weißhaarigen unter uns erinnern sich vielleicht vage an diese IDE. Aktuell aber scheint Eclipse nicht über die Funktionalität des Remote System Explorer hinausgekommen zu sein oder sich in Richtung Dev Container zu entwickeln.
Recap - Warum der Aufwand? Welche Use-Case?
Isolation - Die Entwicklungsumgebung nicht “vollmüllen” mit Installation unterschiedlicher Tools und Versionen aus unterschiedlichen Projekten (z.B. Python 2 und 3 Projekte oder der ganze Node.js Module-Zoo etc.). Das ist aber kein neues Thema: Vor dem Aufkommen der Container war diese Isolation durch Auslagerung der Projekte in Virtuelle Maschinen auf den Entwicklungsrechnern üblich. Oder noch früher unter Unix/Linux für Command Line Junkies mit chroot
.
100% reproduzierbares Setup - Windows, Unix/Linux und MacOS kompatibel. Kein mühsames Fixen seltsamer Seiteneffekte auf dem Entwicklungsrechner mehr, weil irgendein längst vergessenes Tool in einer Version mit inkompatiblen Dependencies installiert ist - “Works-on-My-Machine” heisst: Läuft auch bei allen anderen.
Ein gepflegtes Dockerfile
und docker
oder docker-compose
reduzieren die Setup- und Update-Aufwände auf Entwicklungsumgebungen drastisch.
Debugging - Eine lokale, isolierte und debugbare Entwicklungsumgebung zur Fehlersuche aufzusetzen ist leider selten trivial. Neben bestimmten Versionen der Komponenten und dem Code für das Debuggen müssen oft auch bestimmte Zustände (Daten) hergestellt werden. Das lässt sich, isoliert im Container, einfacher/strukturierter/gezielter realisieren und vor allem gut automatisieren (Script).
In The Wild: Drupal debuggen - Den Affen im Sack entlausen.
Nach all der grauen Theorie haben wir natürlich auch für alle, die gerade ein angenehmes Zucken in den Fingerspitzen verspüren, ein ganz praktisches Beispiel für den hilfreichen Dev Container Einsatz aus den (Un)Tiefen des Alltags geborgen.
Das Problem
Drupal ist ein OpenSource Content Management System (CMS), in PHP mit Symfony geschrieben. Drupal lebt von und mit unzähligen Erweiterungen (Module), die Drupal funktional erweitern.
Im konkreten Fall wurde das Modul az_blob_fs
hinzugefügt, um Ressourcen wie Bilder oder Videos direkt auf einem Azure Blob Storage abzulegen und von dort auch wieder lesen zu können.
Mit der Erweiterung konnten Bilder vom Azure Blob Storage unter bestimmten, reproduzierbaren Bedingungen nicht mehr angezeigt werden, siehe auch https://www.drupal.org/project/az_blob_fs/issues/3444134
Debuggen oder Loggen?
Mit statischer Codeanalyse und Logging (\Drupal::logger()
und serialize()
) konnte in diesem Fall das Problem auf eine fehlerhafte Berechtigungsprüfung eingegrenzt werden.
Berechtigungen werden in Drupal von Hooks geprüft, die auf verschiedenen Ebenen u.a. auch auf Modul Ebene implementiert werden. Der Call-Stack dieser Hooks ist zur Laufzeit dynamisch und lässt sich deshalb mit statischer Codeanalyse und Logging zur Laufzeit nur bedingt analysieren.
Also lieber: Mit der IDE klassisch debuggen - und das in genau einem der laufenden Container der Analyse Umgebung.
VS Code für Dev Container Vorbereiten
Es wurde VS Code mit dem Dev Container Plugin. verwendet. Docker bzw. Docker-Desktop oder Rancher-Desktop wird als gegeben angenommen.
Step 1: Start der Drupal Analyse-Umgebung
Für die Analyse wurde ein minimales Drupal Environment zusammengestellt und in einem GitLab Repository abgelegt. Das muss lokal geklont werden, anschließend wird die Umgebung mit einem Bash Script gestartet (unter Windows besser im WSL):
git clone https://github.com/codecentric/drupal-bug-reproduction.git
cd drupal-bug-reproduction
./quick-local-setup.sh
Wenn alles funktioniert hat, dann sollten folgende Container zu sehen sein:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6f871b072ea1 quick-local-setup/nginx:latest "/docker-entrypoint.…" 37 minutes ago Up 37 minutes 0.0.0.0:80->8080/tcp, 0.0.0.0:30007->8080/tcp drupal-min-setup-debug-nginx-1
66ea06fbf210 mcr.microsoft.com/azure-storage/azurite:3.28.0 "docker-entrypoint.s…" 37 minutes ago Up 37 minutes 0.0.0.0:10000-10002->10000-10002/tcp drupal-min-setup-debug-azure_storage-1
013a1612db8a quick-local-setup:latest "docker-php-entrypoi…" 37 minutes ago Up 37 minutes 9000/tcp drupal-min-setup-debug-php-1
59d1c1a58a54 bitnami/mariadb "/opt/bitnami/script…" 37 minutes ago Up 37 minutes 0.0.0.0:3306->3306/tcp drupal-min-setup-debug-db-1
Nach einer Drupal Installation liegt der komplette Drupal PHP Code im Image quick-local-setup:latest
im Verzeichnis /opt/drupal/
. Um den Code nicht nur für VS Code innerhalb des Containers sondern auch ausserhalb des Images verfügbar zu machen, wird ein temporärer Container mit diesem Image gestartet und der Drupal PHP Code aus dem Container heraus in ein lokales Verzeichnis ./container-src/opt/drupal
kopiert. Zum Schluss wird der eigentliche Drupal Container gestartet und das Volume mit der Kopie des PHP Codes unter /opt/drupal
gemountet. Damit wird nicht nur der Code, sondern auch die spätere VS Code spezifische Projekt-Konfiguration unabhängig vom Lifecycle des Containers persistiert.
Step 2: Mit VS Code in den PHP Container hooken
VS Code kann sich mit einem laufenden Container verbinden und alle Nötige installieren (remote VS Code Engine, Plugins etc.) um diesen Container als Dev Container zu verwenden. VS Code merkt sich in einer devcontainer.json
, welche Komponenten installiert wurden.
Auf das Remote Explorer
Symbol klicken (Icon in der linken Leiste unterhalb "Extensions") und dann mit dem Container drupal-min-setup-debug-php-1
verbinden (Pfeil-Icon rechts):
Um später die Verbindung zum Dev Container wieder zu beenden, auf die blaue "Remote Connection" Status Bar links unten klicken und "Disconnect Remote" aus dem Drop-Down Menü wählen:
Step 3: VS Code Plugin Im Container Installieren: PHP Debug (Xdebug)
VS Code arbeitet jetzt innerhalb des Dev Containers drupal-min-setup-debug-php-1
.
Im Container ist bereits der PHP Debugger Xdebug
installiert (via Dockerfile). Um jetzt PHP Code mit VS Code in der IDE grafisch debuggen zu können, muss für VS Code im Dev Container remote noch das Plugin PHP Debug Xdebug installiert werden. Das macht man wie gewohnt in der IDE. VS Code merkt sich diese remote Installation und stellt beim erneuten Verbinden zu dem Container falls nötig die remote Installation wieder her.
Step 4: Debug/Launch Konfiguration: .vscode/launch.json
VS Code braucht diese Konfiguration, um Projekte zu starten oder zu debuggen.
Damit diese Debug Konfiguration im richtigen Ordner angelegt wird, muss in VS Code innerhalb des Dev Containers zuallererst in den Ordner /opt/drupal
gewechselt werden (der wie in Step 1 beschrieben auf ein externes Volume gemountet ist). Die Projekt- bzw. VS Code spezifische Debug/Launch Konfiguration wird dort in .vscode/launch.json
wie folgt erweitert (oder ggf. neu angelegt):
1{ 2 "version": "0.2.0", 3 "configurations": [ 4 5 ... 6 7 { 8 "name": "Debug Drupal", 9 "type": "php", 10 "request": "launch", 11 "runtimeArgs": [ 12 "-dxdebug.mode=debug", 13 "-dxdebug.start_with_request=yes", 14 "-S", 15 "localhost:8000" 16 ], 17 "program": "", 18 "cwd": "/opt/drupal/web", 19 "port": 9003, 20 "serverReadyAction": { 21 "pattern": "Development Server \\(http://localhost:([0-9]+)\\) started", 22 "uriFormat": "http://localhost:%s", 23 "action": "openExternally" 24 } 25 }, 26 27 ... 28 29 ] 30}
Step 5: Debuggen
Aus dem Hauptmenü "File" -> "Open ..." im Verzeichnis /opt/drupal/web
die Datei index.php
öffnen:
Dort in z.B. in Zeile 16 $kernel = new DrupalKernel('prod', $autoloader);
eine Breakpoint setzen und das Debugging starten mit Konfiguration Debug Drupal
.
Der Debugger startet einen internen Webserver an http://localhost:8000
, öffnet einen neuen Tab im Standard-Browser mit dieser URL und stoppt dann sofort am Breakpoint.
Unter /opt/drupal
liegt nun der komplette Drupal PHP Code und man kann mit dem Debugger und Breakpoints in die Tiefen der Eingeweide von Drupal und der Erweiterung az_blob_fs
abtauchen.
Fazit
Auf den ersten Blick gerät man in Versuchung, sich irgendwie an Wackersteine im Rucksack zu erinnern: Wozu der extra Aufwand? Richtig, durchaus berechtigte Frage für Einzelkämpfer im lang laufenden Projekt.
Alle anderen profitieren von schnellem und funktionierendem Ramp Up und Update im Team sowie reproduzierbaren, portablen und flexiblen Environments, die man lokal einfacher debuggen kann.
VS Code zeigt den effektiven und flexiblen Umgang mit Dev Containern, IntelliJ ist noch nicht ganz am Ziel und Eclipse nimmt das Thema irgendwie nicht richtig wahr. Ein bisschen mehr Qual der Wahl wäre nicht schlecht.
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog-Autor*in
Karl Södler
Software-Architect
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.