Start / Seminare / Docker, Podman und Kubernetes für Entwickler
Modul
Containerisierte Entwicklungs-Workflows
6 Kapitel in diesem Modul-Video · Laufzeit
Transkript
Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.
Containerisierte Entwicklungs-Workflows
0:00 Bis hierhin haben wir Images gebaut und uns für eine Engine entschieden. Beides sind Vorbereitungen. In diesem Modul geht es um den Alltag: Wie sieht ein Arbeitstag aus, wenn Container nicht das Thema sind, sondern das Werkzeug? Wir bringen einen ganzen Verbund aus Anwendung und Datenbank mit einem Befehl hoch, wir klären, welche Daten einen Container überleben, wir sorgen dafür, dass Startreihenfolgen verlässlich funktionieren, und wir lassen Tests ihre Datenbank selbst mitbringen.
0:27 Am Ende heben wir denselben Bauvorgang in eine Pipeline — auf eine Maschine ohne Gedächtnis. Das ist der Punkt, an dem aus lokaler Bequemlichkeit eine belastbare Lieferkette wird.
Ein Full-Stack als Compose-Aufbau
0:37 Fangen wir mit der Datei an, die im letzten Modul nur eine Nebenrolle hatte. Jetzt steht sie im Mittelpunkt: vier Bauteile, eine Datei, ein Befehl. Und damit eine Entwicklungsumgebung, die man nicht mehr beschreiben muss, sondern nur noch starten. Eine Compose-Datei ist im Kern eine Beziehungsbeschreibung. Sie sagt für jeden Dienst, welches Image oder welcher Bauplan gilt, welche Umgebungswerte gesetzt sind, welche Ports nach außen führen und wer auf wen wartet.
1:05 Ein einziger Befehl bringt den ganzen Verbund hoch. Der eigentliche Gewinn ist aber keine technische Eigenschaft, sondern eine kulturelle: Ihre Entwicklungsumgebung wird ein versionierter Bestandteil des Projekts. Sie hört auf, mündliche Überlieferung zu sein — jenes Wiki-Kapitel, das seit zwei Jahren nicht mehr stimmt, und jener Kollege, der weiß, welche Datenbankfassung man wirklich braucht.
1:28 Hier steht das kleinste sinnvolle Beispiel: unsere Kartenwerk-API und ihre Datenbank. Achten Sie weniger auf die Schlüssel als auf eine Stelle — die Datenbankadresse. Dort steht nicht eine IP-Adresse und nicht localhost, sondern schlicht der Name des anderen Dienstes. Das ist der Kern von Compose: Jeder Dienstname ist gleichzeitig ein Rechnername im internen Netz, und die Auflösung übernimmt die Engine.
1:52 Zwei Dienste, die einander kennen, ohne dass jemand Adressen verteilen musste. Und die zweite Beobachtung: Der eine Dienst wird gebaut, der andere gezogen. Beides steht friedlich nebeneinander in derselben Datei. Compose kennt Dutzende Schlüssel, aber diese sieben tragen die Arbeit. Sortieren Sie sie im Kopf nach ihrer Rolle: Die ersten beiden bestimmen, woher der Container kommt.
2:15 Die nächsten drei bestimmen, was er sieht — Werte, Ports, Ablagen. Und die letzten zwei steuern, wann er überhaupt läuft. Zwei Hinweise aus der Praxis: profiles ist unterschätzt und löst ein echtes Problem — Sie können damit den Lasttest-Generator in derselben Datei beschreiben, ohne dass er morgens mitstartet. Und image und build schließen sich nicht aus. Zusammen ergeben sie einen Bauplan mit Veröffentlichungsziel, was in Pipelines sehr praktisch ist.
2:43 Das ist eine der angenehmsten Neuerungen der letzten Jahre und noch wenig verbreitet. Bisher hatten Sie zwei Möglichkeiten: entweder ein Verzeichnis einbinden und darauf hoffen, dass Ihr Nachladen im Container greift — oder bei jeder Änderung neu bauen. Jetzt beschreiben Sie, was bei welcher Änderung passieren soll: Quelldateien werden hineinsynchronisiert, eine geänderte Paketliste löst dagegen einen echten Neubau aus.
3:06 Genau diese Unterscheidung ist die Pointe, denn sie entspricht der Wirklichkeit. Gestartet wird das mit dem watch-Befehl. Ein Hinweis: Das Synchronisieren greift nur bei Diensten, die einen eigenen Bauplan haben — bei gezogenen Images gibt es nichts zu synchronisieren. Diese vier Punkte sind derselbe Gedanke in vier Tonarten, und wir hatten ihn schon bei den Devcontainern: Wissen, das in einer Datei steht, veraltet sichtbar — Wissen im Wiki veraltet unsichtbar.
3:33 Ein Klonen und ein Befehl genügen. Die Versionen von Datenbank und Zwischenspeicher sind überprüfbar statt zufällig. Der dritte Punkt ist der, den ich am wertvollsten finde: Der Aufbau wandert mit dem Zweig. Ein Fehlerzweig von vor einem Jahr startet mit den Ständen von vor einem Jahr, ohne dass jemand etwas rekonstruieren muss.
3:51 Und insgesamt schrumpft der Abstand zwischen Ihrem Arbeitsplatz und der Pipeline auf das Nötige. Der erste Punkt ist der wichtigste, weil die Datei ins Repository gehört und Zugangsdaten dort eben nicht: Lesen Sie sie aus einer eigenen, nicht eingecheckten Datei. Der zweite kommt aus Modul 1 zurück — ein bewegliches Standard-Tag beim Datenbank-Image bedeutet, dass irgendwann eine neue Hauptfassung hochkommt, und zwar ohne Ankündigung.
4:16 Der dritte ist Alltag in Firmen mit vielen Projekten: Fest veröffentlichte Ports kollidieren, sobald zwei Aufbauten gleichzeitig laufen sollen. Und der vierte betrifft ein Missverständnis, das Compose-Neulinge oft haben: Die Verbindung läuft über Dienstnamen, nicht über Verzeichnisstrukturen oder Reihenfolge in der Datei.
Volumes und Bind-Mounts
4:34 Jetzt zu einem Thema, das für die meisten rätselhaften Nachmittage verantwortlich ist: Was überlebt einen Container, und was nicht? Verlorene Testdaten und unerklärliche Rechteprobleme haben fast immer hier ihre Ursache. Die Grundeigenschaft eines Containers ist Flüchtigkeit — und das ist gewollt. Ersetzen Sie ihn, bleibt nichts zurück.
4:55 Wer Daten behalten will, braucht also einen Ort außerhalb: eine benannte Ablage, die die Engine verwaltet. Wer dagegen Quellcode vom eigenen Rechner in den Container reichen will, bindet ein Verzeichnis ein. Und jetzt kommt der Grund, warum dieses Kapitel existiert: Beides sieht in der Compose-Datei fast gleich aus — eine Zeile, ein Doppelpunkt, zwei Pfade.
5:16 Verhält sich aber völlig verschieden, bei Rechten, bei Lebensdauer, bei Portierbarkeit. Diese optische Ähnlichkeit bei inhaltlicher Verschiedenheit ist die eigentliche Falle. Trotz der Überschrift stehen hier vier Zeilen, und die vierte ist die interessanteste — dazu gleich. Sortieren Sie nach der Frage: Wer bestimmt, wo die Daten wirklich liegen?
5:37 Bei der benannten Ablage die Engine, bei einem Verzeichnis Sie selbst, beim Arbeitsspeicher niemand, denn dort bleibt nichts. Diese letzte Variante ist erstaunlich nützlich für Zwischendateien und Geheimnisse: Was nie auf eine Platte geschrieben wird, kann von dort auch nicht gelesen werden. Und die dritte Zeile ist eine Warnung: Namenlose Ablagen entstehen, wenn man nur ein Ziel angibt und keine Quelle.
6:00 Sie sammeln sich unbemerkt an und belegen irgendwann viele Gigabyte. Hier stehen die zwei Varianten direkt untereinander, und ich empfehle, diese Anordnung zu übernehmen: Die Datenbank bekommt eine benannte Ablage, der Quellcode ein eingebundenes Verzeichnis. Beachten Sie den Block am Ende — eine benannte Ablage muss zusätzlich deklariert werden, und genau das ist die Sichtbarkeit, die Sie wollen.
6:23 Der eigentliche Hinweis steckt aber in den zwei Buchstaben am Ende der Quellcode-Zeile: nur lesend eingebunden. Der Container kann Ihre Quelldateien nicht verändern. Das kostet nichts, verhindert eine ganze Klasse von Überraschungen — und ist eine der Gewohnheiten, die ich Ihnen uneingeschränkt empfehle. Vier Faustregeln, und die zweite und dritte gehören zusammen, weil sie zusammen einen der häufigsten Fehler verhindern.
6:48 Datenbankdateien in eine benannte Ablage, sonst ist Ihr Teststand beim nächsten Ersetzen weg. Quellcode als eingebundenes Verzeichnis, sonst greift kein Nachladen und Sie bauen bei jeder Änderung neu. Aber — und das ist der dritte Punkt — Abhängigkeiten gehören ins Image, nicht in ein eingebundenes Verzeichnis. Warum das so wichtig ist, sehen Sie auf der nächsten Folie.
7:09 Und die vierte Regel: Was nur zur Laufzeit gebraucht wird, darf im Arbeitsspeicher liegen und einfach verschwinden. Der erste Punkt ist der Klassiker unter allen Compose-Fehlern und der Grund für die Regel von der letzten Folie: Wenn Sie Ihr Projektverzeichnis über die im Image installierten Abhängigkeiten binden, verdecken Sie sie.
7:29 Sie sind noch da, aber unsichtbar — und der Dienst startet nicht mehr, mit einer Meldung, die nirgends auf ein Volume hinweist. Der zweite ist die Kennungsabbildung aus Modul 2, die hier zurückkommt. Der dritte trifft, wer beim Aufräumen zu großzügig ist und die Ablagen mitnimmt. Und der vierte ist ein hartnäckiges Missverständnis: Ein Neubau des Images erneuert die benannte Ablage nicht. Die alte Datenbank bleibt genau, wie sie war.
Healthchecks und Startreihenfolge
7:54 Jetzt kommt der Unterschied, an dem fast jede erste Pipeline scheitert — und der gleichzeitig so einleuchtend ist, dass man ihn übersieht: Gestartet heißt nicht bereit. Auf dem Notebook fällt das kaum auf. Auf einer langsamen Bau-Maschine fällt es sofort auf. Ein Healthcheck ist im Grunde eine Frage, die in festem Takt gestellt wird: Kannst du schon? Die Engine führt dazu einen Befehl im Container aus.
8:18 Solange er fehlschlägt, gilt der Dienst als nicht bereit; nach einer festgelegten Zahl von Fehlversuchen als krank. Das Bild dazu: Der Kellner fragt nicht, ob das Licht in der Küche an ist — er fragt, ob das Essen fertig ist. Und erst mit dieser Antwort lässt sich eine Reihenfolge formulieren, die nicht auf den Startbefehl wartet, sondern auf tatsächliche Bereitschaft.
8:39 Ohne Healthcheck können Sie Reihenfolgen nur hoffen, nicht steuern. Sechs Zeilen, und alle fünf Parameter haben eine Aufgabe. Der Befehl fragt die Datenbank tatsächlich, ob sie Anfragen annimmt — nicht, ob ein Port offen ist. Der Takt bestimmt, wie oft gefragt wird, die Frist, wie lange auf eine Antwort gewartet wird, und die Zahl der Versuche, wann Geduld in Diagnose umschlägt.
9:02 Am wichtigsten ist die letzte Zeile, und sie wird am häufigsten vergessen: die Anlaufzeit. In dieser Spanne zählen Fehlversuche nicht als krank. Eine Datenbank, die beim ersten Start ihr Verzeichnis anlegt, braucht Sekunden bis Minuten — ohne Anlaufzeit gilt sie in dieser Zeit als kaputt. Das ist die Einlösung des Versprechens von vorhin, und die Datei liest sich plötzlich wie ein Satz: Warte, bis die Datenbank bereit ist, und bis die Wanderung erfolgreich durchgelaufen ist.
9:30 Achten Sie auf die zweite Bedingung — sie ist der saubere Weg für Datenbank-Wanderungen. Kein Startskript, das irgendetwas selbst versucht, sondern ein eigener Dienst, der einmal läuft und sich beendet. Und der Hinweis darunter ist eine Falle, in die alle einmal tappen: Diese Bedingung kann nur greifen, wenn im Ziel-Dienst überhaupt ein Healthcheck hinterlegt ist.
9:51 Fehlt er, wartet Compose ins Nichts — auf eine Antwort, die niemand gibt. Die ersten drei Zeilen sind eine Steigerung, und Sie sollten sie in dieser Reihenfolge im Kopf haben: Startbefehl abgesetzt, tatsächlich bereit, erfolgreich beendet. Die erste ist die Voreinstellung und sagt am wenigsten — sie bedeutet nur, dass der Container gestartet wurde, nicht dass darin etwas funktioniert.
10:13 Die dritte ist die für Wanderungen: Der Dienst hat seine Arbeit getan und sich beendet, und zwar fehlerfrei. Die letzten beiden Zeilen sind Schalter, die man selten braucht und dann dringend: Der eine erneuert abhängige Dienste mit, der andere entscheidet, ob ein fehlender Dienst den Start abbricht oder nur eine Notiz erzeugt.
10:31 Der rote Faden hier ist Ehrlichkeit gegenüber sich selbst. Schritt eins ist der entscheidende, und der Hinweis unten sagt, warum: Ein Befehl, der nur auf einen offenen Port sieht, meldet Bereitschaft, die es nicht gibt. Ein Port ist oft lange vor der Anmeldung offen. Fragen Sie also nach etwas, das wirklich funktionieren muss.
10:50 Die Schritte zwei bis vier sind Kalibrierung — Takt, Anlaufzeit, Fehlversuche gegen die erwartete Schwankung. Und Schritt fünf ist der, den man aus Zeitnot weglässt und der die Arbeit erst belegt: den Verbund von Null starten und die Reihenfolge im Protokoll nachlesen. Nicht schätzen, nachlesen. Diese Übung hat einen ausdrücklichen Gegner, und den nennen wir gleich: die Schlafpause im Startskript.
11:13 Das ist der übliche Reflex, sie funktioniert auf dem eigenen Rechner, und sie ist auf der Bau-Maschine zu kurz. Ihre Aufgabe ist, Startreihenfolge über nachgewiesene Bereitschaft zu steuern statt über Wartezeiten. Geschafft ist es, wenn der Verbund aus dem leeren Zustand zehnmal hintereinander fehlerfrei startet, ohne dass ein Dienst wartend abbricht. Zehnmal, weil einmal Glück sein kann.
11:35 Wer schneller fertig ist, verlangsamt die Datenbank künstlich und prüft die Anlaufzeit erneut — das ist die Probe, die wirklich etwas beweist. Der erste Punkt ist der Gegner aus der Übung, und ich betone ihn, weil er so verbreitet ist: Eine feste Wartezeit ist immer entweder zu kurz oder Zeitverlust — meistens beides, an unterschiedlichen Tagen.
11:55 Der zweite ist der aus der Code-Folie: Warten auf Bereitschaft ohne Healthcheck im Ziel-Dienst kann nicht funktionieren. Der dritte ist eine Übertreibung mit Folgen — ein zu knapper Takt beschäftigt Ihre Datenbank im Sekundentakt mit Prüfungen und verfälscht sogar Messungen. Und der vierte schließt den Kreis zum Vorgehen: Ein Prüfbefehl, der nur den Port sieht und nicht die Anmeldung, ist schlimmer als keiner. Er lügt zuverlässig.
Integrationstests mit Testcontainers
12:20 Jetzt zu dem Punkt, an dem Tests aufhören, von der Maschine abhängig zu sein. Jeder kennt den Satz „bei mir läuft der Test" — und die Ursache ist fast immer eine Datenbank, die auf einem Rechner läuft und auf einem anderen nicht. Die Lösung ist verblüffend direkt: Der Test bringt seine Datenbank selbst mit. Testcontainers ist eine Bibliothek, die aus dem Testcode heraus echte Dienste als Container startet und nach dem Lauf wieder abräumt. Zwei Dinge sind daran wichtig.
12:47 Erstens: echte Dienste. Keine Attrappe, kein Ersatz im Arbeitsspeicher — dieselbe Datenbankfassung wie in der Produktion, mit denselben Eigenheiten bei Sortierung, Zeitzonen und Transaktionen. Zweitens: Der Test bekommt die zugewiesene Adresse zur Laufzeit, statt sie zu erwarten. Das klingt nach einem Detail und ist die ganze Idee — genau dadurch braucht niemand vorher etwas einzurichten, und genau dadurch stören sich zwei gleichzeitige Läufe nicht.
13:15 Vier Zeilen für ein ganzes Konzept. Sie starten die Datenbank im Testaufbau, Sie fragen sie anschließend nach ihrer Adresse, und Sie räumen am Ende ab. Die zweite Zeile ist die entscheidende, und sie ist es, weil sie fragt statt festzulegen. Der veröffentlichte Port wird nämlich zufällig gewählt — und das ist Absicht, nicht Nachlässigkeit.
13:34 Ein zufälliger Port kann nicht kollidieren, also können zwei Testläufe auf derselben Maschine friedlich nebeneinander existieren, in der Pipeline genauso wie auf Ihrem Notebook. Merken Sie sich die Konsequenz: Ein fester Port darf in diesem Aufbau nirgends stehen. Vergleichen wir mit dem, was viele Teams heute haben: eine Testdatenbank, die irgendwo läuft und die alle benutzen.
13:56 Der erste Punkt räumt damit auf — jeder Lauf hat seine eigene Instanz, also stören sich zwei Läufe nicht. Der zweite beendet den Unterschied zwischen Arbeitsplatz und Pipeline. Der dritte ist der, der mich am meisten überzeugt, und er ist unangenehm konkret: Ein vergessener Datenrest kann einen später laufenden Test grün färben.
14:16 Solche Tests sind schlimmer als keine, weil sie Vertrauen erzeugen, das nicht gedeckt ist. Und der vierte: Der Stand der Datenbank steht im Test und ist damit versioniert. Diese Tabelle brauchen Sie in genau einem Moment — wenn Testcontainers nicht mit Docker sprechen soll, sondern mit Podman. Die erste Zeile kennen wir schon aus Modul 2: dieselbe Socket-Adresse, dieselbe Brücke.
14:38 Die zweite ist für den Fall, dass Ihr Test selbst in einem Container läuft und von dort Container starten will — ein Aufbau, der in Pipelines häufiger ist, als man denkt. Die dritte klärt, auf welchem Rechner die Ports erscheinen. Und die vierte schaltet das Aufräum-Bauteil ab; dazu gleich mehr. Praktisch ist der Hinweis darunter: Diese Werte gehen auch aus einer Datei im Heimverzeichnis, nicht nur aus der Umgebung.
15:03 Drei Zeilen, und für rootless Podman braucht es tatsächlich alle drei. Die ersten beiden sind die vertraute Socket-Adresse. Die dritte ist erklärungswert: Testcontainers startet normalerweise einen kleinen Wächter mit, der nach einem abgebrochenen Testlauf die zurückgelassenen Container aufräumt. Unter rootless Podman funktioniert dieser Wächter nicht zuverlässig, und die Dokumentation nennt das Abschalten ausdrücklich.
15:27 Wichtig ist, was daraus folgt: Sie geben damit den automatischen Aufräumdienst auf. In der Pipeline müssen Sie ihn selbst ersetzen — sonst füllen sich die Bau-Maschinen langsam mit Leichen abgebrochener Läufe. Das Wort ohne Vorbedingung ist hier der Kern: Der Test soll seine Abhängigkeiten selbst mitbringen und auf jeder Maschine gleich laufen.
15:47 Geschafft ist es, wenn der Test auf einem Rechner ohne laufende Datenbank fehlerfrei durchläuft — und wenn nach dem Lauf kein Container übrig ist. Der zweite Teil ist genauso wichtig wie der erste. Wer schneller fertig ist, lässt zwei Testläufe gleichzeitig starten und prüft, ob beide grün bleiben; das ist die eigentliche Probe auf die zufälligen Ports.
16:07 Und ein Vorschlag: Lassen Sie sich nach dem Lauf gemeinsam die Container auflisten. Das leere Ergebnis ist der halbe Lerneffekt. Der erste Punkt widerspricht direkt der Mechanik: Ein festgeschriebener Port kann nicht funktionieren, wenn der Port bei jedem Lauf neu vergeben wird — und trotzdem ist es der häufigste Anfängerfehler.
16:25 Der zweite kostet Laufzeit ohne Gegenwert: Pro Testdatei einen eigenen Verbund zu starten vervielfacht die Wartezeit, wo eine gemeinsame Instanz je Lauf genügt. Der dritte ist die Folge aus der letzten Code-Folie und wird regelmäßig übersehen — wer das Aufräum-Bauteil abschaltet, übernimmt die Verantwortung dafür. Und der vierte ist ein Selbstbetrug: Mit einem beweglichen Standard-Tag behaupten Sie Gleichheit mit der Produktion, ohne sie zu haben.
Devcontainers nach der Spezifikation
16:50 In Modul 2 haben wir Devcontainer nur gestreift — als Einstellung im Editor. Jetzt sehen wir uns die Sache selbst an: die Werkbank, die neben dem Quellcode liegt, und die Datei, die sie beschreibt. Die ist nämlich offen spezifiziert und gehört keinem Werkzeug. Die Datei benennt vier Dinge: woher die Umgebung kommt — Image oder Compose-Dienst —, wo im Container gearbeitet wird, welche Bausteine nachinstalliert werden, und welche Befehle zu festen Zeitpunkten laufen.
17:18 Der Satz, auf den es mir hier ankommt, ist der letzte: Die Spezifikation ist werkzeugneutral. Sie ist keine Editor-Konfiguration, auch wenn sie so entstanden ist. Editoren lesen sie, Pipelines lesen sie, Kommandozeilenwerkzeuge lesen sie. Das ist derselbe Gedanke wie beim offenen Container-Format aus Modul 1 — und es ist der Grund, warum diese Datei ins Repository gehört, während die Wahl der Engine es nicht tut.
17:43 Diese Datei tut etwas Kluges: Sie beschreibt die Umgebung nicht selbst, sondern verweist auf die Compose-Datei, die wir schon haben. Genau das ist die Empfehlung. Denn die Alternative — eine eigene Beschreibung für den Devcontainer — bedeutet zwei Wahrheiten über dieselbe Umgebung, und die laufen zuverlässig auseinander.
18:01 Beachten Sie außerdem zwei Schlüssel: die Bausteine, über die Werkzeuge geprüft dazukommen, und den Befehl nach dem Erzeugen, der die Abhängigkeiten installiert. Warum ausgerechnet an dieser Stelle und nicht irgendwo anders, klärt die nächste Folie — sie hat mit dem Lebenszyklus zu tun und mit dem Cache. Sechs Zeitpunkte, und die Reihenfolge ist die Botschaft — deshalb steht sie so in der Tabelle. Ganz oben, und nur dort, läuft etwas auf Ihrem eigenen Rechner, vor dem Container.
18:30 Alles Übrige läuft darin. Der wichtigste praktische Unterschied ist der zwischen den Befehlen beim Erzeugen und denen bei jedem Start: Was einmalig ist — Abhängigkeiten installieren, Datenbank vorbereiten — gehört nach oben. Was jedes Mal nötig ist, nach unten. Wer das verwechselt, zahlt bei jedem einzelnen Start eine Minute Wartezeit für etwas, das schon erledigt war.
18:52 Und der letzte Zeitpunkt greift erst, wenn sich ein Werkzeug verbindet. Bausteine sind kleine, versionierte Installationsrezepte, die andere pflegen — und der Gewinn ist nicht Bequemlichkeit, sondern Arbeitsteilung. Der erste Punkt ist der offensichtliche: Sie pflegen keine Installationsbefehle für fünf Werkzeuge mehr. Der zweite ist wichtiger, als er klingt — Ihre Beschreibung bleibt lesbar und zeigt Absichten statt Befehle. Wer sie in einem Jahr öffnet, versteht sofort, was gemeint war.
19:22 Der dritte ist der praktische: Dieselbe Datei trägt auch die Pipeline, die den Container ohne Editor baut. Und der vierte ist die Probe darauf, ob es funktioniert — ein Wechsel der Laufzeitfassung ist eine Zeile, kein Umbau. Der erste Punkt ist der aus Modul 1 wiederkehrende Cache-Gedanke, hier in neuer Kleidung: Wer die Einrichtung in den Bauplan legt statt in die Lebenszyklus-Befehle, verliert die Möglichkeit, sie unabhängig vom Image zu wiederholen.
19:48 Der zweite ist die Verwechslung aus der Tabelle — Abhängigkeiten beim Verbinden statt beim Erzeugen installieren verlängert jeden Start. Der dritte ist eine Team-Frage, die schnell politisch wird: Editor-Einstellungen sind ein Vorschlag, keine Pflicht, denn eine Kollegin mit anderem Werkzeug liest sie nie. Und der vierte ist banal und ärgerlich: Ein Arbeitsverzeichnis, das nicht zu dem des Compose-Dienstes passt, und plötzlich fehlt der halbe Quellcode.
Bauen in der Pipeline
20:13 Zum Abschluss verlassen wir den eigenen Rechner. Derselbe Bauplan, aber eine fremde Maschine ohne Gedächtnis — kein Cache, kein Basis-Image, keine lokal installierten Werkzeuge. Und das ist gleichzeitig der Übergang in die Lieferkette, um die es im nächsten Modul geht. Stellen Sie sich eine Küche vor, die vor jedem Gericht komplett neu eingerichtet wird — leerer Kühlschrank, kein Vorrat, nichts.
20:37 Genau so arbeitet ein Pipeline-Läufer: frisch aufgesetzt, kein Zwischenspeicher, kein vorhandenes Basis-Image, kein Verlass auf lokale Werkzeuge. Das ist der Preis für Reproduzierbarkeit, und er ist gerechtfertigt. Damit die Bauzeit trotzdem erträglich bleibt, wird der Zwischenspeicher ausgelagert — in den Speicher der Pipeline oder in die Registry selbst.
20:58 Und ein Nebeneffekt wird hier zum ersten Mal spürbar: Der Build-Kontext aus Modul 1 wandert übers Netz. Er wird von einer Kleinigkeit zu einer messbaren Größe. Dieser Block ist kürzer, als man erwartet, weil zwei fertige Bausteine die Arbeit machen: einer richtet das Bau-Backend ein, der andere baut und veröffentlicht. Die eigentliche Pointe stehen in den letzten zwei Zeilen. Sie sagen: Nimm den Zwischenspeicher von dort, und lege ihn danach dorthin zurück.
21:26 Ohne diese zwei Zeilen baut jeder Lauf alle Schichten neu — auch die unveränderten, auch die Paketinstallation, jedes Mal. Das ist der Unterschied zwischen einer Pipeline, die zwei Minuten braucht, und einer, die zwölf braucht. Und es sind wirklich nur diese zwei Zeilen. Vier Ziele, und die Wahl folgt einer einfachen Frage: Wer soll den Speicher sehen?
21:47 Das erste Ziel ist der Speicher der Pipeline selbst — nichts einzurichten, und für den Anfang genau richtig. Das zweite legt ihn in die Registry, und das lohnt sich, sobald mehrere Projekte oder Zweige denselben Unterbau bauen. Das dritte packt ihn ins Image, was schlank ist, aber nur die letzte Schichtenfolge abdeckt. Das vierte ist für eigene Läufer.
22:08 Wichtiger als die Wahl ist der Hinweis darunter: Erst der Zusatz für den vollständigen Modus nimmt auch die Zwischenetappen mit. Ohne ihn wandert nur das Ergebnis, und genau das erklärt enttäuschende Messungen. Diese Tabelle ist eine Sicherheitsabwägung, und sie hat eine klare Empfehlung. Der erste Weg — ein eigener Dienst je Auftrag — verlangt weitgehende Rechte, und in geteilten Umgebungen bekommen Sie die zu Recht nicht.
22:33 Der zweite ist der bequeme und der gefährliche: Wer den Socket in einen Container einbindet, gibt den ganzen Rechner preis. Ich sage das so deutlich, weil die Dokumentation es ebenso deutlich sagt — sie nennt es ausdrücklich einen Weg zur Rechteausweitung. Wer diesen Socket erreicht, kann beliebige Container mit beliebigen Rechten starten. Der dritte Weg baut ohne Hintergrunddienst und ist der empfohlene Ausweg. Nehmen Sie ihn.
22:58 Fünf Schritte, und ihr roter Faden ist: nicht behaupten, messen. Wir nehmen die Ausgangswerte eines kalten Laufs, ergänzen die Ausschlussliste, messen erneut. Dann lagern wir den Zwischenspeicher aus und fahren einen zweiten Lauf ohne jede Änderung — und das ist die eigentliche Probe, deshalb steht der Hinweis darunter: Dieser zweite Lauf sollte kaum Zeit brauchen.
23:19 Tut er das nicht, greift Ihr Cache nicht, und Sie wissen es sofort statt nach drei Wochen. Schritt vier prüft die Feinheit aus Modul 1: ab welcher Schicht wirklich neu gebaut wird. Und Schritt fünf hält die Zahlen fest, damit die nächste Diskussion Daten hat. Diese Übung schließt das Modul und verbindet es mit Modul 1. Richten Sie einen Bauvorgang so ein, dass er auf einer Maschine ohne Gedächtnis reproduzierbar und zügig läuft.
23:44 Geschafft ist es, wenn die Pipeline das Image unter einem Versions-Tag veröffentlicht und ein zweiter Lauf ohne Quelländerung messbar kürzer ist als der erste. Wer schneller fertig ist, ergänzt einen Lauf für zwei Prozessorfamilien und vergleicht die Zeiten. Und ein Vorschlag zum Ablauf: Schätzen Sie die Zeiten vorher. Der zweite Lauf überrascht fast alle — meist deutlich nach unten, und das ist ein sehr überzeugendes Argument für die zwei Cache-Zeilen.
24:09 Der erste Punkt ist die häufigste vertane Gelegenheit: Wer den Zwischenspeicher nicht auslagert, wundert sich über konstant lange Bauzeiten und hält sie für normal. Der zweite ist ein echter Sicherheitsfehler und kommt aus Modul 1 zurück — Zugangsdaten als Bau-Argument bleiben in der Bau-Historie sichtbar. Nehmen Sie Geheimnisse.
24:27 Der dritte ist der Kontext, den wir gerade gemessen haben: Wer das ganze Projekt übergibt, verbringt die halbe Bauzeit mit Übertragen. Und der vierte ist eine Messfalle, die ich oft sehe: Auf dem Arbeitsplatz mit warmem Cache zu messen und die Zahl als Pipeline-Zeit weiterzugeben. Das sind zwei verschiedene Welten.
Was ab hier trägt
24:45 Vier Sätze aus diesem Modul. Die Entwicklungsumgebung ist eine versionierte Datei, keine Anleitung — das ist der kulturelle Kern des ganzen Tages. Gestartet und bereit sind zwei Zustände, und nur der zweite trägt eine Reihenfolge. Tests bringen ihre Abhängigkeiten selbst mit und lassen nichts zurück. Und in der Pipeline entscheidet der ausgelagerte Zwischenspeicher über die Bauzeit. Im nächsten Modul drehen wir die Frage: Bisher ging es darum, dass etwas funktioniert.
25:14 Jetzt geht es darum, ob wir dem trauen können, was wir ausliefern — Schwachstellen, Stücklisten, Signaturen, und eine Lieferkette, die prüfbar ist.
Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →