1. Der gesamte Kurs hält sich an ein einziges Starter-Repo
Es gibt zwei gleichermaßen schlechte Wege, ein Infrastrukturthema zu lehren. Der erste – in abstrakten Beispielen leben, die einem normalen Backend nicht ähneln. Der zweite – den Studenten zuerst einen komplett neuen Service schreiben lassen und dann Docker erst „irgendwo gegen Ende" zeigen. Beide Varianten stehlen einfach die Aufmerksamkeit vom Wesentlichen.
Ein Starter-Repo löst dieses Problem sehr ehrlich. Es ist bereits real genug, um daran das Verhalten eines normalen Boot-Service zu sehen: HTTP-Layer, Konfiguration, Profile, Export in eine Datei, Actuator, technische Signale. Dabei wird es absichtlich nicht zu einem eigenen Kurs über Domänenmodell, JPA, Security oder Messaging. Wir brauchen hier einen Service als Träger des Container-Themas, nicht als neue große Fachdomäne.
Genau deshalb ist ein Repository methodisch stärker als fünf „Mini-Demos". Du verschwendest keine Kraft damit, dich ständig neu mit einem neuen Projekt, einem neuen Paket, einem neuen Kontext und einer neuen Geschäftslogik vertraut zu machen. Stattdessen siehst du, wie ein und dieselbe Anwendung schrittweise aus Runtime- und Infrastrukturperspektive reift.
2. Wie man das Repository liest, ohne in Details zu versinken
Der erste Blick auf das Starter-Repo sollte nicht wie Archäologie aussehen, sondern wie eine Karte. Zuerst ist es wichtig, die oberste Ebene zu verstehen: Welche Dateien sind für den Start zuständig, wo liegen die Anfragen für schnelle Prüfungen, wo ist das Datei-Szenario, wo ist der Code selbst und welche Artefakte entstehen daneben im Laufe des Kurses.
Die typische Struktur auf oberster Ebene sieht so aus:
# Wurzel des Repositories (Projektordner)
container-ready-catalog-service/
├── Dockerfile # Anleitung zum Bauen des Docker-Image (wird später im Kurs benötigt)
├── compose.yaml # Compose-Beschreibung der Umgebung (z.B. app + DB)
├── requests/ # Schnelle HTTP-Anfragen für Smoke-Checks und reproduzierbare Tests
├── scripts/ # Hilfsskripte für wiederholbare Aktionen rund um den Service
├── data/exports/ # Verzeichnis, in das der Service Exporte schreiben kann (Datei-Szenario)
└── src/main/ # Quellcode der Spring Boot-Anwendung
Zu Beginn sollte man das nicht als trockene Dateiliste wahrnehmen. Jedes Element hat seine Rolle. src/main/ – dort lebt die Anwendung selbst. requests/ – das sind schnelle HTTP-Prüfungen, damit der Baseline nicht „aus dem Gedächtnis", sondern mit den Händen reproduzierbar ist. scripts/ – ein Platz für kleine wiederholbare Operationen rund um den Service. data/exports/ – eine Erinnerung, dass der Service auch ein Dateileben hat und nicht nur REST. Dockerfile und compose.yaml liegen nicht der Schönheit halber daneben: Genau sie werden später den Container-Teil dieses Projekts ausmachen.
Hier ist noch ein Punkt wichtig. Wir lesen Docker-Artefakte nicht zu früh, sehen aber bereits, dass sie neben dem Code liegen. Das ist die richtige Projektintuition. Containerisierung sollte keine „persönliche Magie des Autors" in einem separaten Ordner mit unverständlichen Skripten sein. Sie sollte Teil desselben Repositories sein wie der Service. ⚙️
3. Der Service ist sehr einfach
Die Domäne des Projekts ist absichtlich sehr ruhig gewählt. Wir haben einen Katalog von Elementen und ein Szenario, diesen Katalog in eine Datei zu exportieren. Das ist genau genug, um an einem einzigen Service mehrere für den Kurs wichtige Linien zu sehen: eine normale HTTP-API, einen Datenzustand, Startmodi, das Dateisystem und Betriebssignale.
Einfacher gesagt: Der Service tut nicht „alles auf der Welt", sondern nur das, was für das Container-Thema benötigt wird. Er kann eine Liste von Katalogelementen liefern, grundlegende Operationen mit ihnen ausführen und einen Export starten. Hier geht es nicht darum, dich mit der Komplexität der Geschäftslogik zu beeindrucken. Im Gegenteil, die Domäne bleibt bewusst in einfachen Grenzen, damit die Aufmerksamkeit nicht abgelenkt wird. 🧪
Das ist ein wichtiger Teil des Verständnisses. Ein guter Kurs tut nicht so, als müsste man Containerisierung anhand eines halben Backends, einer Security-Matrix, dreier Microservices und acht Datenbanktabellen erklären. Ein normaler Service mit verständlichem Verhalten reicht. Und der Container-Ready Catalog Service ist genau so aufgebaut.
4. standalone und postgres: zwei Modi
Das Starter-Repo hat mindestens zwei grundlegende Modi, und es ist sehr wichtig, sie bereits am ersten Tag zu sehen. standalone wird für einen schnellen Start ohne externe Datenbank benötigt: Die Daten leben im Arbeitsspeicher, der Service kann schnell hochgefahren und sein HTTP-Verhalten fast sofort überprüft werden. postgres ist bereits ein realistischerer Modus, bei dem der Service eine externe Abhängigkeit bekommt und die gesamte Runtime etwas erwachsener wird.
Der entscheidende Punkt ist, dass das nicht zwei verschiedene Anwendungen sind. Es entsteht kein separater „Docker-Service" und kein separater „lokaler Service". Controller, Logik und der allgemeine Charakter des Verhaltens bleiben dieselben. Die Startbedingungen ändern sich. Und das ist eine sehr wichtige Gewohnheit: ein Service, verschiedene Umgebungsvoraussetzungen.
Dieselbe Idee wird sich durch den gesamten Kurs ziehen. Wenn man anderes Umgebungsverhalten braucht, sollte man das Projekt nicht klonen oder einen zweiten Codepfad anlegen. Man sollte die Runtime ein und desselben Service steuern können. Genau hier fängt Container-Denken an, reif und nicht kosmetisch auszusehen.
5. Minimaler Betriebsbaseline
Es ist sehr verlockend, einen Service als „lebendig" zu betrachten, wenn er eine einzige Tatsache beweist: Der Prozess ist nicht abgestürzt, und in den Logs tauchte eine Startzeile auf. Aber das ist ein zu schwaches Kriterium. Für einen ordentlichen Baseline braucht man mindestens zwei Signale: ein geschäftliches und ein technisches.
Das geschäftliche Signal beantwortet die Frage „macht der Service wirklich das, wofür er existiert?". Für unser Starter-Repo funktioniert GET /api/catalog/items als solches Signal hervorragend. Das technische Signal beantwortet die Frage „hat die Anwendung überhaupt gestartet und kann sie ehrlich über ihren Zustand berichten?". Dafür braucht man GET /actuator/health.
Genau dieses Paar liefert einen guten Smoke-Check-Baseline. Antwortet der geschäftliche Endpoint, dann leben der Web-Layer und ein Minimum an Logik. Antwortet health, hat der Service zumindest einen grundlegenden Betriebsvertrag. Zusammen geben diese beiden Prüfungen ein viel ehrlicheres Gefühl von „der Service ist hochgefahren" als die bloße Tatsache, dass der Java-Prozess noch nicht beendet wurde.
Auf dem ersten Level reicht das bereits. Wir brauchen keine komplexen Diagnosemuster und auch keine tiefe Analyse von Actuator. Bisher ist es nützlich, nur eine Sache zu sehen: Ein lebendiger Service ist nicht einfach „nicht abgestürzt", sondern „antwortet auf die wichtigsten Lebenszeichen".
6. Der Plan für heute 🍹
Jetzt kann man eine sehr kleine Aktion durchführen, die das erste greifbare Ergebnis ohne Überlastung liefert. Zunächst das Starter-Repo lokal auf die Art hochfahren, die für dich im Spring Boot-Projekt bereits gewohnt ist. Wir brauchen gerade keinen neuen Build-Workflow – wichtig ist nur, einen funktionierenden lokalen Baseline zu bekommen.
Danach zwei schnelle Prüfungen durchführen. Bei einem Standard-Port können sie so aussehen:
# Geschäftlichen Endpoint prüfen: Service liefert wirklich Katalogdaten
curl http://localhost:8080/api/catalog/items
# Technischen Zustand prüfen: Actuator meldet, dass die Anwendung "lebt"
curl http://localhost:8080/actuator/health
Wer lieber mit Postman oder .http-Dateien arbeitet, kann die requests/ aus dem Repository verwenden – der Sinn ist derselbe. Die erste Prüfung beantwortet die Frage „lebt der geschäftliche Pfad", die zweite – „sieht der Service sich selbst als lebendige Anwendung".
Das ist das erste bedeutsame Ergebnis des Tages. Du hast noch kein Image gebaut, kein Dockerfile geschrieben und kein Compose hochgefahren, kannst aber bereits das Starter-Repo als betriebliches Objekt betrachten und nicht nur als Ordner mit Code. Und das ist ein sehr guter Start für einen Docker-Kurs.
7. Baseline-Karte vor der Containerisierung
Unten eine Karte, die man nicht nur für dieses Projekt, sondern für fast jeden zukünftigen Boot-Service verwenden kann. Sie hilft, nicht zu früh zu Docker zu springen, und schnell zu fixieren, was genau man danach containerisieren wird.
| Was man jeden Boot-Service vor der Containerisierung fragen sollte | Wie das im Container-Ready Catalog Service aussieht |
|---|---|
| Was genau startet? | Spring Boot-Anwendung mit einem klaren Einstiegspunkt |
| Welcher minimale Business-Smoke-Check? | GET /api/catalog/items |
| Welcher minimale technische Smoke-Check? | GET /actuator/health |
| Welche Startmodi sind wichtig zu unterscheiden? | standalone und |
| Welche externen Voraussetzungen gibt es bereits? | Port, bei postgres – Datenbank, für Export – Verzeichnis |
| Wo nach der ersten Betriebsbestätigung suchen? | Startlogs + Antworten auf beide Endpoints |
Das scheint eine einfache Tabelle zu sein, spart in der Praxis aber sehr viel Kraft. Sobald man diese Fragen schnell beantworten kann, hört die Containerisierung auf, ein Sprung ins Unbekannte zu sein. Der Baseline ist bereits vorhanden, und Docker wird ihn danach nicht ersetzen, sondern stabilisieren.
8. Die Entwicklungsleiter des Projekts
Und jetzt das Angenehmste: Man kann den Kurs als eine einzige fortlaufende Linie sehen, nicht als eine Sammlung von Themen. Unten eine kurze Karte, wie genau derselbe Container-Ready Catalog Service reifen wird:
| Stufe | Was sich an demselben Service ändert | Was du bekommst |
|---|---|---|
| Jetzt | Lokaler Spring Boot-Baseline + Smoke-Check | Ein klares Containerisierungsobjekt |
| Weiter | Erstes Image und erster Container | Reproduzierbare Runtime eines einzelnen Service |
| Danach | Ordentliches Dockerfile, Cache, Multi-Stage, Layer, Buildpacks | Professionelle Verpackung eines Java-Service |
| Dann | Externalized Config, Dateien, Logs, Health, Shutdown | Kontrolliertes Verhalten eines einzigen Image in verschiedenen Modi |
| Danach | app + PostgreSQL über Compose | Einen ordentlichen lokalen Backend-Stand |
| Noch weiter | Redis und RabbitMQ hinzufügen | Fähigkeit, ohne Chaos mit Infrastrukturabhängigkeiten zu leben |
| Finale | Wiederverwendbare Vorlage und Fähigkeit zur systematischen Problemanalyse | Reproduzierbarer Baseline für eigene Services |
Ein und derselbe Service geht den gesamten Weg – vom lokalen Start bis zur container-reifen Vorlage. Und genau dadurch fühlt sich jeder nächste Schritt nicht wie ein neues Thema von Null an, sondern wie eine natürliche Fortsetzung eines bereits bekannten Kontexts.
Wenn man nach dem ersten Tag nur eine Sache im Gedächtnis behalten will, dann diese: Containerisiert wird nicht Docker um Dockers willen, sondern ein konkreter Spring Boot-Service mit einem verständlichen Baseline. Morgen wird dieser Baseline bereits damit beginnen, sich in ein technisches Objekt mit eigenem Lebenszyklus, Logs und beobachtbarem Verhalten in der Container-Umgebung zu verwandeln.
9. Typische Fehler 🚧
Fehler Nr. 1: Das Starter-Repo als eine Sammlung zufälliger Ordner lesen.
Zuerst braucht man immer eine Karte der obersten Ebene: Wo ist der Code, wo sind die Anfragen, wo ist das Datei-Szenario, wo sind die zukünftigen Container-Artefakte. Fängt man sofort an, in Klassen und Paketen zu versinken, verliert man sehr leicht den eigentlichen Lernzweck des Projekts.
Fehler Nr. 2: standalone und postgres als zwei verschiedene Anwendungen betrachten.
Das ist ein Service, keine zwei parallelen Codebasen. Die Lebensbedingungen unterscheiden sich, nicht seine Natur. Dieser Gedanke wird später für die Container-Konfiguration und Compose kritisch wichtig sein.
Fehler Nr. 3: Den Service als „lebendig" nur durch den Prozessstart betrachten.
Der Prozess kann starten, ohne nützliches Verhalten zu zeigen. Deshalb ist es immer besser, den minimalen Baseline mit mindestens einem Paar Anfragen zu fixieren: Business-Endpoint plus Health-Endpoint.
Fehler Nr. 4: Dockerfile und Compose anschauen, bevor der Service selbst verstanden ist.
Das ist eine sehr häufige Falle. Man will sofort zum „interessanten Container-Teil" übergehen, aber ohne einen lokalen Baseline wird er zum Raten. Zuerst muss man verstehen, was man containerisiert und an welchen Signalen man erkennt, dass der Service lebt.
GO TO FULL VERSION