Boring Stack


3 Min. Lesezeit

Ein neuer Rechner braucht Docker und sonst nichts

Die Entwicklung läuft in einem Container

Teil acht des Boring Stack. Die App ist Go, und templ und Tailwind erzeugen Code und CSS. Das sind drei Toolchains, bevor man eine Zeile schreibt. Dieser Text handelt davon, wie ich sie von meinem Rechner fernhalte.

Jedes Projekt, das ich baue, hat einen einzigen unterstützten Weg, es in der Entwicklung zu starten:

task dev

Das führt docker compose up --build aus. Dann öffne ich die App im Browser und fange an.

Was im Container läuft

Das Entwicklungsimage enthält Go, Node (nur für das Tailwind-Kommandozeilenwerkzeug) und alles andere, was das Projekt braucht. Der Projektordner ist in den Container eingebunden, also bearbeite ich die Dateien auf meinem Rechner mit meinem gewohnten Editor.

Beim Start des Containers passiert Folgendes:

  1. Die npm-Abhängigkeiten werden installiert, falls sie fehlen.
  2. Das CSS wird einmal gebaut.
  3. Der Tailwind-Watcher startet im Hintergrund.
  4. templ generate --watch läuft, erzeugt Go-Code neu, wenn sich ein Template ändert, startet den Server neu und lädt den Browser über einen kleinen Proxy neu.

Ein Template ändern, und die Seite lädt neu. Eine Go-Datei ändern, und der Server startet neu. Eine Klasse ändern, und das CSS wird neu gebaut.

Warum nur ein Weg

Es geht nicht um Docker. Es geht darum, dass es genau einen Weg gibt und dass er im Repository steht.

  • Ein neuer Rechner ist in Minuten bereit. Docker installieren, klonen, task dev. Kein Versionsmanager für Go, keiner für Node, kein «auf meinem Rechner läuft’s».
  • Die Versionen kommen aus dem Projekt. Die Go-Version ist in go.mod fixiert, die Werkzeuge mit Gos tool-Direktive, und die npm-Pakete kommen aus der Lock-Datei. Die Versionen auf meinem Rechner spielen keine Rolle.
  • Ein Projekt, das ich ein Jahr nicht angefasst habe, startet immer noch. Der Container hat die Toolchain, die das Projekt erwartet, nicht die, auf die ich inzwischen aktualisiert habe.

Details, die zählen

  • Caches in benannten Volumes. Die Modul- und Build-Caches von Go liegen in Docker-Volumes, überleben also docker compose down, und der zweite Start ist schnell.
  • node_modules berührt den Host nie. Der Ordner enthält plattformspezifische Binaries. Ein Ordner, der im Container für Linux gebaut wurde, funktioniert auf macOS nicht und umgekehrt. Ein eigenes Volume hält ihn im Container.
  • Erzeugte Dateien sind eingecheckt. Der Go-Code, den templ erzeugt, liegt im Repository, also funktionieren go build und go test auch direkt auf dem Host, falls Go dort installiert ist. Der Container ist der unterstützte Weg, nicht der einzig mögliche.

Überall dieselben Befehle

Ein Taskfile.yml enthält vier Tasks, identisch in allen meinen Projekten: dev, test, lint, down. Egal, welches Projekt ich öffne, die Befehle sind dieselben. Der Linter läuft in der CI, bevor irgendetwas gebaut wird, also stoppt ein Lint-Fehler einen Deploy.

Was es kostet

  • Docker Desktop auf macOS braucht Arbeitsspeicher und Akku. Auf einem Laptop merkt man das.
  • Das Beobachten von Dateien über einen eingebundenen Ordner ist langsamer als nativ. Bei der Grösse meiner Projekte ist das kein Problem.
  • Eine Schicht mehr, wenn etwas kaputtgeht. Ab und zu lautet die Frage: «Ist es mein Code oder der Container?» Die Antwort ist fast immer mein Code.

Wann ich anders entscheiden würde

Für einen einzelnen kleinen Go-Service ohne Templates oder CSS reicht go run, und Docker wäre Overhead. Sobald eine zweite Toolchain dazukommt, zahlt sich der Container aus.

Als Nächstes: wo alles läuft.

Mehr in Boring Stack

Teilen