Zurück zum Katalog
Season 29 18 Episoden 1h 9m 2026

Docker Masterclass

Edition 2026. Ein umfassender Audiokurs über Docker, der Container-Grundlagen, Images, Dockerfile, Networking, Compose, CI/CD und die neuesten KI-Funktionen wie MCP Toolkit, Docker Sandboxes und Docker Agent abdeckt.

Containerisierung DevOps
Docker Masterclass
Aktuelle Wiedergabe
Click play to start
0:00
0:00
1
Das Versprechen: Dev gleich Prod
Entdecke, warum Docker die Softwareentwicklung grundlegend verändert hat. Diese Episode behandelt den zentralen Mehrwert der Trennung von Anwendungen und Infrastruktur sowie das Erreichen perfekter Parität zwischen Entwicklungs- und Produktionsumgebungen.
3m 33s
2
Container vs. Virtuelle Maschinen
Verstehe die architektonischen Unterschiede zwischen Containern und VMs. Erfahre, wie Container Isolation erreichen, indem sie den Host-Kernel teilen, was sie im Vergleich zu traditionellen Hypervisoren unglaublich leichtgewichtig macht.
3m 58s
3
Die Anatomie eines Docker Images
Erkunde, was ein Docker Image eigentlich ist. Diese Episode erklärt die Prinzipien der Image-Unveränderlichkeit und der Layer-Komposition und zeigt, wie Dateisystemänderungen gestapelt werden, um ein Container-Template zu erstellen.
4m 05s
4
Der Dockerfile-Bauplan
Lerne, wie man ein Dockerfile schreibt, um eigene Images zu erstellen. Wir behandeln wesentliche Anweisungen wie FROM, RUN und CMD und erklären den entscheidenden Unterschied zwischen shell- und exec-Formen.
3m 43s
5
Den Build Cache meistern
Optimiere deine Image Builds mit dem Docker Build Cache. Erfahre, warum die Reihenfolge der Anweisungen in deinem Dockerfile entscheidend ist, um unnötige Abhängigkeitsinstallationen zu vermeiden.
2m 50s
6
Multi-Stage Builds
Halte deine Produktions-Images schlank und sicher. Diese Episode führt Multi-Stage Builds ein und demonstriert, wie du deine ressourcenintensive Kompilierungsumgebung von deiner minimalen Laufzeitumgebung trennst.
2m 59s
7
Ausführen und Interagieren
Lerne die praktische Mechanik beim Ausführen von Containern. Wir behandeln den Detached- versus Interactive-Modus, grundlegendes Port Publishing und wie man Shell-Befehle innerhalb eines laufenden Containers ausführt.
4m 27s
8
Grundlagen der Datenpersistenz
Verhindere katastrophalen Datenverlust, wenn Container gelöscht werden. Diese Episode vergleicht Bind Mounts für lokales Development Hot-Reloading mit Docker Volumes für sichere Datenbankpersistenz.
3m 44s
9
Container-Netzwerke
Verstehe, wie Docker den Netzwerkverkehr handhabt. Lerne die Grundlagen des Port Publishings an den Host und wie Container über isolierte Bridge-Netzwerke sicher miteinander kommunizieren.
4m 04s
10
Einführung in Docker Compose
Gehe über einzelne Container-Befehle hinaus. Erfahre, wie Docker Compose eine deklarative YAML-Datei verwendet, um mehrere Services gleichzeitig zu definieren, zu vernetzen und zu orchestrieren.
4m 29s
11
Docker in der CI/CD-Pipeline
Eliminiere unzuverlässige Tests mit containerisierten Build-Umgebungen. Diese Episode behandelt die Verwendung von Docker in Continuous Integration-Pipelines, um perfekt reproduzierbare automatisierte Tests zu garantieren.
3m 39s
12
Multi-Platform Images
Löse die Diskrepanz zwischen Apple Silicon und Cloud-Servern. Erfahre, wie Docker Buildx es dir ermöglicht, Anwendungen gleichzeitig für ARM- und AMD64-Architekturen zu cross-kompilieren und zu paketieren.
3m 59s
13
Das Docker MCP Toolkit
Verbinde deine KI-Agenten sicher mit lokalen Tools. Diese Episode stellt das Docker Model Context Protocol (MCP) Toolkit vor und erklärt, wie man containerisierte MCP-Server mithilfe von Katalogen und Profilen verwaltet.
3m 49s
14
Dynamic MCP Auto-Discovery
Erkunde Dynamic MCP, ein experimentelles Feature, das es KI-Clients ermöglicht, den Docker MCP Catalog zu durchsuchen und während einer Konversation dynamisch neue Tool-Server ohne manuelle Einrichtung zu installieren.
4m 18s
15
Docker Sandboxes für KI
Verstehe die Architektur von Docker Sandboxes. Erfahre, warum autonome KI-Coding-Agenten isolierte MicroVMs mit dedizierten Docker-Daemons anstelle von Standard-Container-Namespaces benötigen.
4m 15s
16
KI-Agenten-Teams aufbauen
Verlasse dich bei komplexen Aufgaben nicht mehr auf ein einziges KI-Modell. Diese Episode führt das Docker Agent Framework ein und zeigt, wie man spezialisierte, in YAML definierte Agenten-Teams zusammenstellt.
4m 02s
17
Agent Toolsets und Workflows
Mache deine KI-Agenten wirklich nützlich, indem du ihnen die richtigen Einschränkungen gibst. Lerne, wie du Dateisystem-Toolsets konfigurierst und strukturierte Entwicklungs-Workflows in Docker Agent erzwingst.
4m 01s
18
KI-Modelle in Compose
Behandle deine lokalen LLMs genau wie jede andere Anwendungsabhängigkeit. Lerne, wie du KI-Modelle direkt in deiner Docker Compose YAML-Datei deklarierst, konfigurierst und bindest.
3m 29s

Episoden

1

Das Versprechen: Dev gleich Prod

3m 33s

Entdecke, warum Docker die Softwareentwicklung grundlegend verändert hat. Diese Episode behandelt den zentralen Mehrwert der Trennung von Anwendungen und Infrastruktur sowie das Erreichen perfekter Parität zwischen Entwicklungs- und Produktionsumgebungen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 1 von 18. Du hast gerade drei Tage damit verbracht, einen Fehler aufzuspüren, der nur auf dem Staging-Server auftritt. Der Code läuft einwandfrei auf deinem Laptop, aber sobald er in die Deployment-Pipeline gelangt, crasht er. Die Ursache ist fast immer eine inkompatible System-Library, eine andere Runtime-Version oder eine fehlende Environment Variable. Genau diese Reibungsverluste soll Docker eliminieren, indem es das "Dev equals Prod"-Versprechen einlöst. Docker ist eine offene Plattform für das Entwickeln, Shippen und Ausführen von Anwendungen. Sein Hauptzweck ist es, deine Anwendungen von deiner Infrastruktur zu trennen. Früher schrieben Entwickler den Code und Operations-Teams stellten die Server bereit. Die Entwickler übergaben die Anwendung, und das Operations-Team verbrachte Stunden oder Tage damit, die Host-Machine so zu konfigurieren, dass sie den Softwareanforderungen entsprach. Dieses manuelle Angleichen der Environments ist fehleranfällig und langsam. Docker löst das, indem es die Anwendung zusammen mit ihren Dependencies, System-Tools, Libraries und der Runtime in eine standardisierte Einheit verpackt, die Container genannt wird. Du assoziierst dieses Konzept vielleicht mit traditionellen Virtual Machines. Obwohl beide das Ziel haben, Anwendungen zu isolieren, sind Container deutlich leichtgewichtiger, da sie kein vollständiges Guest Operating System benötigen. Diesen Architekturunterschied behandeln wir in der nächsten Folge. Im Moment konzentrieren wir uns darauf, was dieses Packaging bewirkt. Hier ist die entscheidende Erkenntnis: Da der Container sowohl den Code als auch das exakte Environment für dessen Ausführung enthält, wird die zugrunde liegende Host-Machine weitgehend irrelevant. Docker stellt sicher, dass ein Container, der auf deinem lokalen Development-Laptop läuft, exakt genauso auf einem QA-Server und exakt genauso in einem Production Data Center funktioniert. Du eliminierst den Satz "It works on my machine", weil deine Machine und die Production-Machine nun das exakt gleiche Execution Environment bereitstellen. Der Workflow sieht so aus: Ein Entwickler schreibt lokal Code und definiert das benötigte Environment in einer einfachen Plain-Text-Config-Datei. Docker liest diese Datei und baut ein statisches Artefakt, ein sogenanntes Image. Genau dieses einzelne, immutable Image wird getestet. Wenn die Tests durchlaufen, wird exakt dasselbe Image in Production deployed. Du kopierst keinen Code auf einen Server und führst kein Setup-Script aus. Du verschiebst das gesamte Working Environment als eine geschlossene Einheit. Diese Portabilität verändert, wie Systeme skalieren. Da Container standardisiert und leichtgewichtig sind, lassen sich neue Instanzen einer Anwendung als Reaktion auf einen Traffic Spike in Sekundenschnelle hochfahren. Du kannst Workloads problemlos zwischen verschiedenen Environments verschieben und eine Anwendung von einem lokalen Testing-Server zu einem Cloud Provider umziehen, ohne eine einzige Zeile Code zu ändern oder den Host neu zu konfigurieren. Das wichtigste Takeaway ist, dass Docker Infrastruktur in eine vorhersehbare Commodity verwandelt und eine strikte Grenze zieht, bei der Entwickler das komplette Environment innerhalb des Containers besitzen und Operations einfach nur die Compute Power bereitstellt, um ihn auszuführen. Wenn du die Show unterstützen möchtest, such auf Patreon nach DevStoriesEU. Das war's für diese Folge. Danke fürs Zuhören und keep building!
2

Container vs. Virtuelle Maschinen

3m 58s

Verstehe die architektonischen Unterschiede zwischen Containern und VMs. Erfahre, wie Container Isolation erreichen, indem sie den Host-Kernel teilen, was sie im Vergleich zu traditionellen Hypervisoren unglaublich leichtgewichtig macht.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 2 von 18. Du musst kein komplettes Betriebssystem booten, nur um ein einzelnes Python-Skript laufen zu lassen. Jahrelang haben Entwickler jedoch einen hohen Overhead und langsame Boot-Zeiten in Kauf genommen, um ihre Applications voneinander zu isolieren. Heute ändern wir das, indem wir uns Container vs. Virtual Machines ansehen. Stell dir vor, du lässt einen komplexen Stack lokal laufen. Du brauchst ein React-Frontend, eine Python-API und eine PostgreSQL-Datenbank, die alle gleichzeitig laufen. Wenn du sie direkt auf deiner Host-Machine installierst, riskierst du Dependency-Konflikte. Die API braucht vielleicht eine bestimmte Version einer System-Library, die mit den Anforderungen deiner Datenbank kollidiert. Ein Container löst das, indem er als sandboxed Prozess agiert. Hier ist der entscheidende Punkt: Ein Container ist kein Mini-Computer. Er ist schlichtweg ein Prozess, der nativ auf deiner Host-Machine läuft. Die Magie liegt in der Isolation. Durch Features, die ins Betriebssystem eingebaut sind, bekommt dieser Prozess sein eigenes privates Filesystem, seinen eigenen Networking-Stack und eine isolierte Sicht auf das System. Für die Python-API, die darin läuft, sieht es so aus, als wäre sie die einzige Software auf der Maschine. Für dein Host-Betriebssystem ist es einfach nur ein weiterer Standardprozess, genau wie dein Webbrowser oder Texteditor. Weil ein Container nur ein Prozess ist, teilt er sich den Kernel des Host-Betriebssystems. Wenn die PostgreSQL-Datenbank in einem Container Memory allokieren oder einen Record auf die Disk schreiben muss, spricht sie direkt mit dem Host-Kernel. Es gibt keinen Middleman und kein zweites Betriebssystem, das im Hintergrund bootet. Das ist der Grund, warum ein Container fast augenblicklich startet. Es dauert exakt so lange wie das Starten der reinen Application selbst. Vergleich das jetzt mal direkt mit einer Virtual Machine. Eine Virtual Machine erreicht Isolation, indem sie Hardware simuliert. Sie verlässt sich auf einen Hypervisor – das ist eine Software, die eine virtuelle CPU, virtuellen Memory und ein virtuelles Disk-Drive bereitstellt. Oben auf dieser simulierten Hardware musst du ein komplettes Guest OS installieren. Wenn du dieselbe Python-API in einer isolierten VM laufen lassen willst, musst du eine komplette Linux-Distribution booten. Die VM lädt ihren eigenen, separaten Kernel, initialisiert Device-Driver und startet Background-Services, bevor sie überhaupt daran denkt, deinen Python-Code auszuführen. Jedes Mal, wenn die Application ein File lesen muss, geht der Request durch das Guest OS, runter zum Hypervisor und schließlich zur Host-Hardware. Das bietet eine unglaublich starke Security-Isolation, aber es hat einen hohen Preis bei CPU-Cycles, Memory-Usage und Boot-Zeit. Wegen dieser Unterschiede gibt es oft den Irrglauben, dass du dich für das eine oder das andere entscheiden musst. In der Realität schließen sich Container und Virtual Machines nicht gegenseitig aus. In modernen Cloud-Environments werden sie fast immer zusammen genutzt. Wenn du eine Cloud-Instance provisionierst, mietest du eine Virtual Machine. Diese Virtual Machine bietet eine starke Hardware-Level-Grenze, die deinen Workload von anderen Kunden auf demselben physischen Server trennt. Dann installierst du eine Container-Runtime in dieser Virtual Machine, um dein React-Frontend, deine API und deine Datenbank laufen zu lassen. Die Virtual Machine isoliert die Infrastruktur, während die Container die einzelnen Applications isolieren. Die Unterscheidung läuft letztendlich auf Grenzen hinaus. Virtual Machines virtualisieren die Hardware, um mehrere Betriebssysteme laufen zu lassen, während Container das Betriebssystem virtualisieren, um mehrere isolierte Prozesse laufen zu lassen. Danke, dass du ein paar Minuten mit mir verbracht hast. Bis zum nächsten Mal, mach's gut.
3

Die Anatomie eines Docker Images

4m 05s

Erkunde, was ein Docker Image eigentlich ist. Diese Episode erklärt die Prinzipien der Image-Unveränderlichkeit und der Layer-Komposition und zeigt, wie Dateisystemänderungen gestapelt werden, um ein Container-Template zu erstellen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 3 von 18. Du deployst eine Application, und sie funktioniert perfekt. Zwei Wochen später startest du genau dieselbe Application auf demselben Rechner neu, und sie stürzt ab, weil sich eine System-Library im Hintergrund geupdatet hat. Genau diesen stillen Environmental Drift eliminieren wir, wenn wir die Anatomie eines Docker-Images verstehen. Lass uns zuerst das häufigste Missverständnis klären. Ein Image ist kein Container. Ein Image ist ein statisches Template. Es enthält deinen Application-Code, deine Libraries, deine System-Tools und deine Runtime. Ein Container ist einfach eine laufende Instanz dieses Images. Du kannst tausend Container aus einem Image starten, aber das Image selbst liegt einfach auf der Disk und wartet darauf, gelesen zu werden. Das entscheidende Merkmal eines Docker-Images ist Immutability. Sobald ein Image erstellt ist, wird es nie wieder modifiziert. Du kannst keine Config-Datei innerhalb eines bestehenden Images ändern. Wenn du ein Image ändern willst, musst du ein komplett neues bauen. Diese Immutability garantiert, dass sich ein Image, das du auf deinem Laptop getestet hast, in Production absolut identisch verhält. Das Template kann nicht mit der Zeit driften. Wenn du ein Image nicht modifizieren kannst, musst du neue bauen. Ein Docker-Image ist keine einzelne, riesige Datei. Es ist eine Zusammensetzung aus mehreren unabhängigen Layern, die übereinander gestapelt sind. Jeder Layer repräsentiert ein bestimmtes Set an Filesystem-Änderungen, was bedeutet: Dateien hinzufügen, modifizieren oder entfernen. Nehmen wir als Beispiel eine Node dot js Application. Du baust das Betriebssystem selten selbst. Stattdessen startest du mit einem Base-Image. Dieses Base-Image enthält eine minimale Linux-Distribution und die Node-Runtime. Diese Basis besteht eigentlich aus ihren eigenen Layern, aber für dich fungiert sie als Fundament. Wenn du deine Application zu diesem Fundament hinzufügst, speichert Docker deine Änderungen als neue Layer, die oben drauf gestapelt werden. Zuerst fügst du deine Dependency-Config-Datei hinzu. Das erzeugt einen neuen Layer. Als Nächstes weist du das System an, deine Dependencies herunterzuladen und zu installieren. All diese heruntergeladenen Libraries werden in den nächsten Layer gepackt. Zum Schluss kopierst du deinen Application-Source-Code. Das bildet den obersten Layer. Wenn du einen Container startest, stapelt Docker diese Layer mithilfe eines Union-Filesystems. Dadurch sehen all die unabhängigen Layer wie eine einzige Standard-Verzeichnisstruktur aus. Wenn exakt derselbe File-Path in zwei Layern existiert, verdeckt die Version im oberen Layer die Version im unteren Layer. Hier ist die wichtigste Erkenntnis. Weil Layer immutable sind, werden sie stark gecacht und geteilt. Wenn du deinen Application-Source-Code updatest und ein neues Image baust, berechnet Docker, was sich geändert hat. Es sieht, dass das Base-Linux-Image, die Node-Runtime und dein Dependency-Layer identisch zum vorherigen Build sind. Es verwendet diese existierenden Layer sofort wieder und erstellt nur einen neuen Layer für deinen geupdateten Code. Das macht aus einem Deployment, das Minuten dauern könnte, eine Operation von Millisekunden. Diese Architektur spart außerdem Speicherplatz und Netzwerk-Bandbreite. Wenn du dein neues Image auf einen Server pushst, überträgst du nur den einzigen Layer, der den neuen Source-Code enthält. Der Server hat bereits die Base-Layer. Durch das Erzwingen von immutable Layern garantiert Docker, dass sich deine Application-Environment nicht stillschweigend ändern kann, und stellt gleichzeitig sicher, dass du immer nur die exakten Bytes überträgst oder speicherst, die du modifiziert hast. Das war's für diese Folge. Bis zum nächsten Mal!
4

Der Dockerfile-Bauplan

3m 43s

Lerne, wie man ein Dockerfile schreibt, um eigene Images zu erstellen. Wir behandeln wesentliche Anweisungen wie FROM, RUN und CMD und erklären den entscheidenden Unterschied zwischen shell- und exec-Formen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 4 von 18. Die gesamte Betriebsumgebung für deine komplexe Application lässt sich in nur zehn Zeilen Plain Text ausdrücken. Du übergibst einem Build System ein einziges File, und heraus kommt ein perfekt konfiguriertes System, das überall einsatzbereit ist. Das ist der Dockerfile Blueprint. Ein Dockerfile ist ein Textdokument, das alle Commands enthält, die ein User auf der Command Line aufrufen könnte, um ein Image zu bauen. Das Format ist simpel. Jede Zeile beginnt mit einer Instruction, die per Konvention in Großbuchstaben geschrieben wird, gefolgt von den Arguments für diese Instruction. Docker liest dieses File Zeile für Zeile, von oben nach unten. Jedes gültige Dockerfile muss mit einer Basis beginnen. Diese definierst du mit der FROM Instruction. Wenn du FROM ubuntu schreibst, pullt Docker das offizielle Ubuntu Image und nutzt es als Startpunkt. Jede weitere Zeile in deinem File modifiziert dieses Base Environment. Sobald deine Basis steht, musst du normalerweise Dependencies installieren. Das machst du mit der RUN Instruction. Die RUN Instruction führt einen beliebigen Command innerhalb des aktuellen Images aus und committet das Ergebnis. Wenn du RUN apt-get update schreibst, gefolgt von deinen Commands zur Package-Installation, fährt Docker die Umgebung hoch, führt den Package Manager aus, installiert die Software und speichert den neuen State. Als Nächstes brauchst du deine eigentliche Application. Ein Betriebssystem mit installierten Dependencies ist ohne deinen Code nutzlos. Die COPY Instruction übernimmt das. Du gibst einen Source Path aus deinem lokalen Workspace und einen Destination Path innerhalb des Images an. Docker nimmt deine Files und kopiert sie direkt in das Container Filesystem. Das Bauen des Images ist nur die erste Phase. Du musst Docker außerdem mitteilen, welche Application gestartet werden soll, wenn ein Container hochfährt. Dieses Default-Verhalten definierst du entweder mit der CMD oder der ENTRYPOINT Instruction. Hier ist die wichtigste Erkenntnis. Es gibt zwei verschiedene Arten, diese Execution Instructions zu formatieren, und wenn man sie verwechselt, führt das zu subtilen Bugs. Der erste Ansatz ist die Shell Form. Du schreibst die Instruction, gefolgt von dem Command, genau so, wie du ihn in ein Terminal eintippen würdest. Wenn Docker das sieht, wrappt es deinen Command in eine Shell und führt ihn über bin slash sh aus. Das ist praktisch, weil Environment Variables automatisch expandiert werden. Allerdings sitzt der Shell-Prozess zwischen Docker und deiner Application. Wenn Docker ein Signal sendet, um den Container graceful zu stoppen, fängt die Shell es ab und deine Application empfängt es nie, was zu forced Terminations führt. Der zweite Ansatz ist die Exec Form. Diese wird als JSON Array geschrieben. Du formatierst sie mit eckigen Klammern, wobei das Executable als erster String und seine Arguments als nachfolgende Strings übergeben werden. Wenn du die Exec Form nutzt, umgeht Docker die Shell komplett. Es führt dein Executable direkt aus. Deine Application wird zur Process ID eins innerhalb des Containers. Das garantiert, dass System-Signale direkt an deine Application weitergegeben werden, was für reibungslose und vorhersehbare Shutdowns sorgt. Wenn du einen stabilen Production Container willst, nutze für deine finalen Commands immer die Exec Form, damit deine Application ihren eigenen Lifecycle kontrolliert. Das war es für diese Folge. Danke fürs Zuhören, und keep building!
5

Den Build Cache meistern

2m 50s

Optimiere deine Image Builds mit dem Docker Build Cache. Erfahre, warum die Reihenfolge der Anweisungen in deinem Dockerfile entscheidend ist, um unnötige Abhängigkeitsinstallationen zu vermeiden.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 5 von 18. Wenn dein Docker Build jedes Mal zehn Minuten dauert, wenn du auch nur eine einzige Zeile Source Code änderst, machst du etwas falsch. Die Lösung liegt komplett darin, wie du dein File strukturierst, und das bedeutet, den Build Cache zu beherrschen. Wenn du einen Docker Build triggerst, verarbeitet der Builder dein Dockerfile sequenziell von oben nach unten. Jede einzelne Instruction, egal ob du ein Directory kopierst oder ein Script ausführst, erzeugt einen separaten Layer im resultierenden Image. Weil das Ausführen dieser Schritte Compute-Zeit und Netzwerkbandbreite kostet, speichert Docker den Output von jedem Schritt automatisch in einem lokalen Build Cache. Bei nachfolgenden Builds versucht die Engine, diese gespeicherten Layer wiederzuverwenden, um redundante Arbeit zu überspringen. Um festzustellen, ob ein Cache Hit möglich ist, evaluiert Docker jede Instruction anhand der bestehenden Cache History. Bei Instructions, die Commands ausführen, checkt Docker, ob der Command String selbst identisch mit dem aus dem vorherigen Build ist. Bei Instructions, die Files von deiner Host Machine in das Image kopieren, geht Docker noch einen Schritt weiter. Es berechnet eine Checksum für den Inhalt und die Metadaten jedes kopierten Files. Dann vergleicht es diese neue Checksum mit der Checksum der Files im zuvor gecachten Layer. Wenn die Checksums perfekt übereinstimmen, verwendet Docker den gecachten Layer wieder und geht zur nächsten Zeile über. Wenn auch nur ein einziges Byte abweicht, wird der Cache invalidiert. Pass an dieser Stelle gut auf. Cache Invalidation ist eine strikte Kettenreaktion. In dem Moment, in dem Docker eine Änderung erkennt und einen Layer invalidiert, schaut es sich den Cache für den Rest des Builds nicht mehr an. Jede einzelne Instruction, die nach dem invalidierten Layer kommt, muss von Grund auf neu ausgeführt werden. Das passiert, weil jeder Layer auf dem exakten State des vorherigen Layers aufbaut. Diese Kettenreaktion diktiert, wie du dein Dockerfile organisieren musst. Stell dir eine Node-Applikation vor, in der du externe Dependencies managst. Ein häufiger Fehler ist es, eine einzige Instruction zu nutzen, um deinen kompletten Projektordner in das Image zu kopieren, gefolgt von einer Instruction, die deinen Package Installation Command ausführt. Wenn du eine einzige Zeile in einem Textfile irgendwo in deinem Source Code änderst, ändert sich die Checksum für die Copy Instruction. Der Cache bricht an dieser Stelle. Folglich muss die nächste Instruction ausgeführt werden. Du wartest darauf, dass hunderte Megabyte an Dependencies erneut heruntergeladen werden, obwohl deine eigentliche Liste an Dependencies komplett unangetastet blieb. Der optimale Ansatz isoliert die Dependencies vom Application Code. Zuerst fügst du eine Instruction hinzu, die nur dein Dependency Configuration File, genauer gesagt dein Package Manifest, in das Image kopiert. Zweitens führst du den Command aus, um die Dependencies herunterzuladen. Drittens fügst du eine separate Instruction hinzu, um den Rest deines allgemeinen Source Codes zu kopieren. Wenn du nun dasselbe Textfile änderst und einen Rebuild machst, evaluiert Docker die erste Instruction. Das Dependency Manifest hat sich nicht verändert, also wird der Cache genutzt. Es geht weiter zum Installationsschritt. Da der vorherige Layer ein Cache Hit war und der Command String identisch ist, wird der Cache hier erneut genutzt und der massive Download übersprungen. Der Cache bricht erst bei der letzten Instruction, wo der Builder deine aktualisierten Source Files kopiert. Aus zehn Minuten Wartezeit wird ein Zwei-Sekunden-Update. Der effektivste Weg, deine Pipeline zu beschleunigen, ist, deine Instructions strikt danach zu ordnen, was sich am unwahrscheinlichsten ändert, bis hin zu dem, was sich am wahrscheinlichsten ändert. Das war's für diese Folge. Danke fürs Zuhören, und keep building!
6

Multi-Stage Builds

2m 59s

Halte deine Produktions-Images schlank und sicher. Diese Episode führt Multi-Stage Builds ein und demonstriert, wie du deine ressourcenintensive Kompilierungsumgebung von deiner minimalen Laufzeitumgebung trennst.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 6 von 18. Deinen Compiler in Production zu deployen, ist ein enormes Sicherheitsrisiko und bläht deine Containergröße um Gigabytes auf. Du schreibst zwar sauberen Code, aber dein finales Artifact wird durch all die schweren Tools belastet, die nur für den Build gebraucht werden. Die Lösung dafür sind Multi-Stage Builds. Wenn du Applications in kompilierten Sprachen wie Java, Go oder C++ baust, braucht der Kompilierungsprozess Build-Tools, Software Development Kits und den rohen Source Code. Früher haben Developer einen Standardansatz genutzt, bei dem sie all diese Dependencies in den Container installiert, den Code kompiliert und dann die Application ausgeführt haben. Das Problem ist, dass all diese Build-Tools im finalen Production Image bleiben. Am Ende deployst du deinen Compiler, deinen Package Manager und Intermediate Files zusammen mit deiner eigentlichen Application. Das macht deinen Container riesig. Große Container brauchen länger, um übers Netzwerk gepullt zu werden, und verbrauchen mehr Storage. Noch schlimmer: Es entsteht eine riesige Angriffsfläche. Wenn ein Angreifer in deinen Container eindringt, hat er plötzlich eine voll ausgestattete Development-Umgebung zur Verfügung. Ein häufiger Irrtum ist, dass man dafür zwei separate Files pflegen muss – ein File, um die Software zu bauen, und ein Script, um das Ergebnis zu extrahieren und an ein zweites File für das Deployment zu übergeben. Das ist nicht der Fall. Multi-Stage Builds übernehmen diese komplette Separation of Concerns innerhalb eines einzigen Files. Hier ist der entscheidende Punkt. Ein Multi-Stage Build erlaubt es dir, mehrere verschiedene Umgebungen, oder Stages, nacheinander zu definieren. Jede Stage beginnt mit der Definition eines eigenen Base Images. Du startest die erste Stage mit einem schweren Base Image, das all deine Development-Tools enthält. Du gibst dieser Stage einen Namen, zum Beispiel builder. Innerhalb dieser builder Stage kopierst du deinen Source Code von deiner lokalen Maschine und führst deine Compile-Commands aus. Die builder Stage übernimmt die harte Arbeit und generiert das finale Executable. Dann, weiter unten in genau demselben File, definierst du ein zweites Base Image. Das initiiert eine brandneue Stage. Für diese Stage wählst du ein minimales Runtime Image. Diese Umgebung enthält nur genau die Dependencies, die zum Ausführen der Application gebraucht werden, mit null Build-Tools. Anstatt wieder Files von deiner lokalen Maschine zu kopieren, nutzt du eine spezielle Copy Instruction. Diese Instruction sagt der Build Engine, dass sie in die builder Stage zurückgreifen, sich nur das fertige, kompilierte Artifact schnappen und es in deine neue, minimale Stage packen soll. Wenn die Build Engine fertig ist, produziert sie einen Container, der ausschließlich auf der finalen Stage basiert. Alles aus der ersten Stage – der Compiler, die heruntergeladenen Packages, der Source Code – wird komplett verworfen. Es landet niemals in deinem Production Image. Schauen wir uns ein konkretes Szenario mit einer Java Spring Boot Application an. In deinem File nutzt deine erste Stage ein umfangreiches Maven Image. Innerhalb dieser Stage führst du den Maven Command aus, um deine Application zu packagen. Maven lädt alle nötigen Project Dependencies herunter, kompiliert den Java-Code und packt ihn in ein fertiges JAR-File. Als Nächstes startest du die zweite Stage mit einem schlanken Java Runtime Environment Base Image. Du installierst Maven nicht in dieser Umgebung. Du kopierst deine Java Source Files nicht hierher. Stattdessen weist du die Engine an, nur das kompilierte JAR-File direkt aus der Maven Stage in diese minimale Runtime-Umgebung zu kopieren. Zum Schluss setzt du den Default Command, um dieses JAR-File auszuführen. Durch die strikte Trennung der Build-Umgebung von der Runtime-Umgebung garantierst du, dass dein Production Container komplett von deinen Build-Tools isoliert ist. Das finale Image sieht immer nur das kompilierte Artifact und die absolute Minimum-Runtime, was dein Deployment schnell, schlank und hochsicher hält. Das war's für diese Folge. Bis zum nächsten Mal!
7

Ausführen und Interagieren

4m 27s

Lerne die praktische Mechanik beim Ausführen von Containern. Wir behandeln den Detached- versus Interactive-Modus, grundlegendes Port Publishing und wie man Shell-Befehle innerhalb eines laufenden Containers ausführt.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 7 von 18. Einen Prozess im Hintergrund zu starten, ist genau das, was du für einen Production-Webserver willst. Aber wenn dieser Server sich weigert, deine Seite zu laden, brauchst du eine Möglichkeit, die Scheibe einzuschlagen, in die Environment einzusteigen und zu sehen, was eigentlich kaputt ist. In dieser Folge geht es darum, Container auszuführen und mit ihnen zu interagieren. Der wichtigste Befehl, um einen Container zu starten, ist docker run. Standardmäßig, wenn du einen Container ausführst, hängt er seine Ausgabe direkt an deinen Terminal-Screen an. Er übernimmt deinen Prompt, und wenn du Control C drückst, wird der Container beendet. Für einen lang laufenden Service wie einen Nginx-Webserver ist das völlig unpraktisch. Du willst, dass der Server im Hintergrund läuft. Das erreichst du mit dem Detached-Mode-Flag, das du als einzelnes dash d eintippst. Wenn du dash d übergibst, startet Docker den Container, gibt eine lange, eindeutige Container-ID auf deinem Screen aus und gibt dir sofort deinen Terminal-Prompt zurück. Der Container läuft leise im Hintergrund weiter. Dieser laufende Container ist jedoch isoliert. Selbst wenn Nginx innerhalb des Containers aktiv Traffic auf Port 80 serviert, kann deine Host-Maschine ihn nicht sehen. Du musst explizit ein Loch durch diese Netzwerk-Isolation schlagen. Das machst du mit dem Publish-Flag, das als dash p eingetippt wird. Das erlaubt es dir, einen bestimmten Port auf deinem Host-Laptop auf einen bestimmten Port innerhalb des Containers zu mappen. Wenn du dash p 8080 Doppelpunkt 80 angibst, fängt Docker jeglichen Web-Traffic ab, der auf deinem Laptop auf Port 8080 ankommt, und routet ihn direkt an Port 80 innerhalb des Containers. Jetzt hast du einen detached Webserver, den du erfolgreich von deinem lokalen Browser aus erreichen kannst. Aber was passiert, wenn du die Seite lädst und einen Konfigurationsfehler siehst? Dein Nginx-Server läuft im Hintergrund, aber du musst die Konfigurationsdateien auf seinem Filesystem lesen. Hier ist die wichtigste Erkenntnis. Du musst einen Container nicht stoppen, um hineinzuschauen. Stattdessen benutzt du den docker exec Command. Während docker run einen brandneuen Container erstellt, führt docker exec einen brandneuen Command innerhalb eines bereits existierenden, laufenden Containers aus. Um ein nützliches, funktionierendes Terminal zu bekommen, musst du zwei spezifische Flags zu dash i t kombinieren. Das i steht für interactive. Das hält den Standard-Input-Kanal offen, was es dir erlaubt, tatsächlich Commands in den Container einzutippen. Das t alloziert ein Pseudo-TTY. Das gaukelt dem Container vor, er wäre mit einem physischen Terminal verbunden, was notwendig ist, damit Command-Prompts und Textformatierungen korrekt angezeigt werden. Wenn du docker exec dash i t ausführst, gefolgt vom Container-Namen und dem Command slash bin slash bash, landest du sofort in einem Command-Prompt innerhalb des laufenden Nginx-Containers. Du bist jetzt in der Box. Du kannst Konfigurationsdateien lesen, Error-Logs checken und das Filesystem inspizieren, genau wie du es auf einem Standard-Linux-Server tun würdest. Wenn du fertig bist, schließt die Eingabe von exit deine temporäre Shell-Session. Der Nginx-Container selbst bleibt davon völlig unberührt und läuft weiterhin im Hintergrund. Irgendwann musst du aufräumen. Das Ausführen von docker stop mit dem Container-Namen sendet ein Termination-Signal, was der Application Zeit gibt, gracefully herunterzufahren. Einen Container zu stoppen, löscht ihn jedoch nicht von deinem System. Der gestoppte Container bleibt auf deiner Festplatte und behält seine Logs und alle internen Filesystem-Änderungen. Um ihn dauerhaft zu löschen und diesen Speicherplatz freizugeben, führst du den docker rm Command aus. Die wichtigste Unterscheidung, die du dir merken musst, ist der Unterschied zwischen run und exec. Docker run bootet ein brandneues, isoliertes System, während docker exec es dir erlaubt, in ein System einzusteigen, das bereits atmet. Danke fürs Zuhören. Macht's gut, Leute.
8

Grundlagen der Datenpersistenz

3m 44s

Verhindere katastrophalen Datenverlust, wenn Container gelöscht werden. Diese Episode vergleicht Bind Mounts für lokales Development Hot-Reloading mit Docker Volumes für sichere Datenbankpersistenz.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 8 von 18. Du deployst eine Datenbank in einem Container, schreibst Tausende von Rows, und alles läuft perfekt. Dann löschst du den Container, um das Image zu updaten, und deine gesamte Datenbank ist für immer verschwunden. Standardmäßig ist der Container-Storage rein temporär. Um Datenverlust zu verhindern, brauchen wir die Data Persistence Basics. Wenn ein Container startet, erstellt er einen writable Layer über seinem zugrunde liegenden Image. Alle Files, die der Container erstellt oder ändert, werden in genau diesem Layer gespeichert. Wird der Container zerstört, wird dieser Layer gleich mit zerstört. Die Daten sind komplett ephemeral. Sie existieren nicht außerhalb des eigenen Lifecycles des Containers. Um die Daten sicher zu halten, musst du sie aus dem Container raus und auf die Host-Machine routen. Docker bietet dafür zwei primäre Mechanismen: Bind Mounts und Managed Volumes. Ein Bind Mount mappt einen spezifischen, expliziten Pfad auf deiner Host-Machine direkt auf einen Pfad im Container. Du sagst Docker ganz genau, welcher Ordner auf deinem Laptop in der Container-Environment auftauchen soll. Das ist stark abhängig von deinem Host-Betriebssystem und der lokalen File-Struktur. Die Host-Machine behält die volle Kontrolle über die Files. Dieser Ansatz ist perfekt für die lokale Entwicklung. Du bind-mountest dein lokales Source-Code-Directory in den Web-Application-Pfad deines Containers. Wenn du ein Skript auf deinem Laptop bearbeitest und speicherst, liest der Container das geupdatete File sofort. Du bekommst instant Hot-Reloading, ohne das Container-Image jedes Mal neu zu builden, wenn du eine Zeile Code änderst. Der zweite Mechanismus ist ein Managed Volume. Anstatt auf einen bestimmten Pfad auf deiner Festplatte zu verweisen, den du kontrollierst, sagst du Docker, dass es eine Storage-Entity erstellen soll. Docker provisioniert den Space auf der Host-Machine und managt ihn komplett. Du musst nicht wissen, wo Docker die Files physisch auf deinem Host-System ablegt. Du gibst dem Volume einfach einen Namen und sagst dem Container, wo er es intern mounten soll. Volumes sind die Standardlösung für Database Persistence. Wenn du PostgreSQL laufen lässt, erstellst du ein Volume mit einem simplen Command und gibst ihm einen Identifier, wie db-data. Wenn du dann deinen Container startest, übergibst du ein Configuration-Flag, das dieses db-data Volume mit dem internen Pfad verlinkt, in den Postgres seine Table-Records schreibt. Wenn du den Database-Container stoppst und löschst, lässt Docker das Volume komplett in Ruhe. Wenn du später einen neuen Container hochfährst, attachst du einfach dieses existierende Volume, und alle deine Records sind intakt. Hier ist der entscheidende Punkt: Die Wahl zwischen diesen beiden Methoden läuft darauf hinaus, wer auf die Files zugreifen muss. Nutze Bind Mounts, wenn deine Host-Machine aktiv mit den Daten interagieren muss, wie ein Developer, der Source Code bearbeitet. Nutze Managed Volumes, wenn der Container die Daten besitzt, wie eine Database-Engine, die Records schreibt, und du einfach nur willst, dass Docker diese Files über Container-Restarts hinweg sicher aufbewahrt. Ephemere Container sind eine Design-Entscheidung, kein Fehler, denn sie zwingen dich, deine Daten von deinem Runtime-Compute zu entkoppeln. Geh immer davon aus, dass dein Container sofort zerstört wird, und mappe deinen persistenten State explizit außerhalb davon. Wenn du diese Episoden hilfreich findest, kannst du die Show unterstützen, indem du auf Patreon nach DevStoriesEU suchst. Das war's für diese Folge. Danke fürs Zuhören, und keep building!
9

Container-Netzwerke

4m 04s

Verstehe, wie Docker den Netzwerkverkehr handhabt. Lerne die Grundlagen des Port Publishings an den Host und wie Container über isolierte Bridge-Netzwerke sicher miteinander kommunizieren.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 9 von 18. Standardmäßig ist ein laufender Container komplett von der Außenwelt abgeschottet. Er sitzt in einer privaten Blase, und wenn du willst, dass das Internet ihn erreicht, musst du absichtlich Löcher in diese Isolation bohren. Diese Löcher und die Verbindungen zwischen den Containern zu managen, ist der Job von Container Networking. Wenn ein Container startet, weist Docker ihm eine interne IP-Adresse zu. Der Container kann normalerweise aufs Internet zugreifen, um Updates herunterzuladen oder Network Calls zu machen, aber nichts von außerhalb der Host-Maschine kommt nach innen durch. Um eingehenden Traffic zu akzeptieren, nutzt du Port Publishing. Publishing nimmt einen Port auf deiner physischen Host-Maschine und bindet ihn direkt an einen Port im Container. Wenn du einen Webserver-Container hast, der intern auf Port achtzig lauscht, kannst du ihn auf Port achtzig-achtzig auf deinem Host publishen. Wenn ein User einen Request an deine Host-Maschine auf Port achtzig-achtzig schickt, fängt Docker ihn ab und leitet ihn direkt durch die Firewall an den Container auf Port achtzig weiter. Du konfigurierst dieses Mapping beim Start mit dem Publish-Flag. Ohne dieses Flag bleibt der Container für das externe Netzwerk unerreichbar. Damit hätten wir den externen Traffic abgedeckt. Der zweite Teil davon ist die interne Kommunikation. Applications laufen selten als einzelner, isolierter Prozess. Meistens hast du mehrere Container, die Daten teilen müssen. Standardmäßig hängt Docker jeden neuen Container an ein integriertes Netzwerk namens Default Bridge. Eine Bridge ist ein softwarebasierter Network Switch, der auf deiner Host-Maschine läuft. Sie verbindet Container, damit sie Pakete austauschen können, und isoliert sie gleichzeitig von externen Netzwerken. Hier ist der entscheidende Punkt: Die Default Bridge erlaubt es Containern, über ihre internen IP-Adressen zu kommunizieren, aber Container-IP-Adressen ändern sich jedes Mal, wenn ein Container neu startet oder ein Update bekommt. Eine IP-Adresse in deiner Application Config zu hardcoden, wird dein System fast sofort crashen. Um das zu lösen, erstellst du ein User-defined Bridge Network. Wenn du mehrere Container an eine Custom User-defined Bridge hängst, bietet Docker eine automatische interne DNS Resolution. Das bedeutet, dass Container sich über ihre exakten Containernamen finden können. Stell dir ein Szenario vor, in dem du einen Backend Application Container und einen Database Container hast. Du erstellst ein einziges Custom Bridge Network und hängst beide Container daran. In deinem Backend Application Code schreibst du keinen Database Connection String mit einer fragilen IP-Adresse. Du nutzt einfach den Namen des Database Containers als Host Address. Docker fängt die DNS Query ab, findet den Database Container auf dieser spezifischen Bridge und routet den Traffic dynamisch an die korrekte interne IP-Adresse. Dieses Design gibt dir die totale Kontrolle über die Application Security. Das Backend und die Database können über die Custom Bridge frei miteinander reden, aber kein externer Traffic kann die Database erreichen. Um deine Application sicher laufen zu lassen, lässt du die Database versteckt auf der privaten internen Bridge, ohne Ports zu publishen. Dann publishst du nur den Port des Backend Containers auf deine Host-Maschine. Externe User greifen auf den Public Backend Port zu, und das Backend fragt die Database sicher über die private Bridge ab. Die Architektur deiner Application diktiert deine Network Topology: Nutze published Ports, um externe User einzuladen, und Custom User-defined Bridges, damit deine internen Container sicher über ihren Namen miteinander reden können. Das wär's für diese Folge. Danke fürs Zuhören und keep building!
10

Einführung in Docker Compose

4m 29s

Gehe über einzelne Container-Befehle hinaus. Erfahre, wie Docker Compose eine deklarative YAML-Datei verwendet, um mehrere Services gleichzeitig zu definieren, zu vernetzen und zu orchestrieren.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 10 von 18. Du solltest kein Textdokument voller komplexer Terminal Commands brauchen, nur um deine lokale Development Environment zu starten. Sich auf die Shell History zu verlassen, um sich die genauen Flags, Ports und Netzwerknamen für mehrere Container zu merken, ist eine fragile Art zu arbeiten. Die Einführung in Docker Compose löst dieses Problem, indem sie deinen gesamten Application Stack in eine einzige deklarative Datei verwandelt. Wenn du eine Application ausführst, existiert sie selten isoliert. Normalerweise hast du einen Webserver, eine Database und vielleicht einen Caching Layer. Sie manuell zu starten, erfordert das Ausführen mehrerer einzelner Commands. Du musst ein Custom Network erstellen, jeden Container daran anbinden, die richtigen Ports exposen und Storage Drives mounten. Wenn du bei einem dieser Schritte einen Tippfehler machst, können die Container nicht kommunizieren und die Application schlägt fehl. Docker Compose ersetzt diesen imperativen Prozess durch eine deklarative YAML-Datei, die normalerweise compose dot yaml genannt wird. Anstatt Docker Schritt für Schritt genau zu sagen, was zu tun ist, deklarierst du den gewünschten Endzustand deines gesamten Systems. Docker Compose findet dann die notwendigen Schritte heraus, um diesen Zustand zu erreichen. Die YAML-Datei ist in drei strukturelle Hauptabschnitte unterteilt. Der erste und wichtigste Abschnitt heißt services. Ein Service ist einfach eine Definition für einen bestimmten Container in deiner Application. Stell dir ein Szenario vor, in dem du eine Node Application zusammen mit einer MySQL Database laufen lässt. Unter dem services-Abschnitt definierst du zwei Einträge. Den ersten nennst du web und gibst das Node Image sowie die lokalen Ports an, die du exposen willst. Den zweiten nennst du database und gibst das MySQL Image sowie die benötigten Environment Variables an, wie zum Beispiel das Root-Passwort. Hier ist die wichtigste Erkenntnis. Du musst diese Container nicht manuell verlinken. Standardmäßig erstellt Docker Compose automatisch ein einziges internes Network für deine Application. Es bindet alle definierten Services an dieses Network an und weist jedem Container einen Hostname zu, der seinem Service-Namen entspricht. Dein Node Application Code kann sich einfach mit der Database verbinden, indem er den Hostname database ansteuert, und das interne DNS resolved ihn zur korrekten Container IP. Du kannst Custom Networks manuell im networks-Abschnitt der YAML-Datei definieren, aber für die meisten Standard Development Setups macht das Default-Verhalten genau das, was du brauchst. Der letzte strukturelle Teil ist der volumes-Abschnitt. Databases brauchen persistenten Storage. Wenn der MySQL Container herunterfährt, willst du nicht, dass deine Daten gelöscht werden. Ganz unten in deiner YAML-Datei deklarierst du ein Named Volume. Dann mappst du innerhalb deiner Database Service Definition einen bestimmten Pfad im Container auf dieses Named Volume. Docker Compose managt die Erstellung und den Lifecycle dieses Storages für dich. Sobald deine Datei geschrieben ist, managst du den gesamten Stack mit zwei Commands. Du tippst docker compose up. Compose liest die YAML-Datei, erstellt das interne Network, setzt die Volumes auf und startet die MySQL und Node Container. Wenn du in deinem Terminal weiterarbeiten willst, fügst du das detach Flag hinzu, um alles im Hintergrund laufen zu lassen. Wenn du mit der Arbeit fertig bist, stoppst und entfernst du nicht jeden Container einzeln. Du tippst docker compose down. Compose beendet die Node App graceful, stoppt die Database und entfernt die Container und das Default Network, wodurch dein System komplett sauber bleibt. Es lässt deine Named Volumes intakt, was bedeutet, dass deine Database Records auf dich warten, wenn du den Stack das nächste Mal hochfährst. Docker Compose shiftet dein Mindset vom Managen einzelner isolierter Container hin zum Managen kompletter Application Environments. Dein Infrastructure Setup wird zu einem einzigen Stück Code, das du in die Version Control committen und sofort mit deinem Team teilen kannst. Das war's für diese Folge. Danke fürs Zuhören und keep building!
11

Docker in der CI/CD-Pipeline

3m 39s

Eliminiere unzuverlässige Tests mit containerisierten Build-Umgebungen. Diese Episode behandelt die Verwendung von Docker in Continuous Integration-Pipelines, um perfekt reproduzierbare automatisierte Tests zu garantieren.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 11 von 18. Du pushst deinen Code, die Pipeline läuft, und die Tests schlagen fehl. Du führst sie lokal aus, und sie laufen einwandfrei. Dein CI-Server hat eine etwas ältere Dependency-Version als dein Laptop. Dieser Drift ist die Hauptursache für notorisch flaky Tests, aber das Containerisieren deiner Build-Umgebung macht jeden Run perfekt vorhersehbar. Heute behandeln wir Docker in der CI/CD-Pipeline. Früher bedeutete Continuous Integration, statische Build-Server zu warten. Mit der Zeit verbinden sich Entwickler mit diesen Virtual Machines, um Packages zu installieren, Runtimes zu updaten und Systemkonfigurationen anzupassen. Diese Server verwandeln sich in Pet-VMs. Sie sammeln versteckten State und übrig gebliebene Cache-Files an. Wenn eine Pipeline fehlschlägt, verschwendest du Zeit damit, herauszufinden, ob der Code tatsächlich kaputt ist oder ob der Server einfach nur ein Software-Update braucht. Docker als Build-Umgebung zu nutzen, umgeht dieses Problem komplett. Anstatt deine Test-Skripte direkt auf dem Host-Betriebssystem eines CI-Workers auszuführen, startet der Worker einen Container. Der CI-Runner pullt ein spezifisches Docker-Image, startet den Container, mountet deinen Source Code und führt deine Build-Steps innerhalb dieser isolierten Umgebung aus. Hier ist der entscheidende Punkt: Wenn der Job beendet ist, wird der Container zerstört. Der nächste Pipeline-Run bekommt eine komplett frische, identische Umgebung. Es gibt keine Konflikte durch Hintergrundprozesse aus vorherigen Runs. Die Umgebung ist stateless und komplett durch das Image definiert. Denk mal an den Prozess, eine Programming Runtime upzugraden. Angenommen, du musst dein Projekt von Node 18 auf Node 20 umziehen. In einem traditionellen Setup muss sich jemand auf dem Build-Server einloggen, die Software systemweit updaten und hoffen, dass es keine anderen Projekte breakt, die denselben Worker nutzen. Mit Docker als deiner Build-Umgebung ist dieser ganze Prozess nur eine String-Änderung. Du updatest das Base-Image-Tag in deiner Konfiguration von Node 18 auf Node 20. Der CI-Runner pullt das neue Image. Dein Build läuft sofort in der aktualisierten Umgebung. Wenn ein Test fehlschlägt, revertest du das Tag und versuchst es später nochmal. Du managst die Infrastruktur direkt zusammen mit deinem Code. Das Ganze hat noch eine weitere Ebene. Wenn du Docker nutzt, um deine Applikation zu bauen, braucht deine CI-Pipeline die Möglichkeit, Images zu builden und zu pushen. Wenn dein CI-Job schon in einem Container läuft, wie führst du dann Docker-Build-Commands aus? Dafür brauchst du ein Pattern namens Docker-in-Docker. Docker-in-Docker bedeutet, einen isolierten Docker-Daemon innerhalb deines CI-Containers laufen zu lassen. Der äußere Container stellt die kontrollierte Umgebung für deine Pipeline-Steps bereit, während der innere Daemon deine Application-Builds verarbeitet. Dadurch kann dein CI-Job Base-Images pullen, deinen Application-Container bauen und das finale Artifact in eine Registry pushen, und das alles, ohne die Host-Maschine zuzumüllen, auf der der CI-Worker läuft. Deine CI-Umgebung in einen Container zu verlagern, verschiebt die Kontrolle über das Build-System zum Entwickler. Genau dasselbe Image, das deinen Code auf einem Remote-Server buildet, kann auf deiner lokalen Maschine ausgeführt werden. Das garantiert, dass du, wenn ein Test in der CI fehlschlägt, genau diesen Fehler lokal reproduzieren kannst. Das war's für diese Folge. Danke fürs Zuhören, und keep building!
12

Multi-Platform Images

3m 59s

Löse die Diskrepanz zwischen Apple Silicon und Cloud-Servern. Erfahre, wie Docker Buildx es dir ermöglicht, Anwendungen gleichzeitig für ARM- und AMD64-Architekturen zu cross-kompilieren und zu paketieren.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 12 von 18. It works on my machine bekommt eine ganz neue Bedeutung, wenn dein lokaler Rechner einen ARM-Prozessor nutzt, deine Production-Cloud aber auf Intel läuft. Du testest deinen Container lokal, pushst ihn in eine Registry, pullst ihn auf dem Server, und er stürzt sofort mit einem Execution Format Error ab. Das Problem ist ein Hardware-Architecture-Mismatch. Um das zu fixen, nutzt du Multi-Platform Images. Ein Container-Image ist im Grunde ein Bundle aus Binaries und Dateisystemen. Wenn du ein Image auf einem Apple Silicon Mac baust, werden die resultierenden Binaries für die ARM64-Architektur kompiliert. Wenn du dieses Image auf einem Standard-Cloud-Linux-Server mit einem AMD64-Prozessor deployst, versteht die Host-CPU die Instructions im Container buchstäblich nicht. Früher musstest du separate Build-Pipelines für verschiedene Hardware-Targets pflegen. Docker Buildx macht das überflüssig. Docker Buildx ist ein Command-Line-Plugin, das das Standard-Docker-Build-System erweitert. Es nutzt eine Backend-Engine namens BuildKit, um Builds parallel auszuführen und komplexe Tasks zu übernehmen, wie das Targeten mehrerer Plattformen in einem einzigen Durchgang. Wenn du mit Buildx ein Multi-Platform Image baust, packst du nicht zwei separate Dateisysteme in einen einzigen riesigen Container. Stattdessen erstellt Buildx eine Image Manifest List. Stell dir dieses Manifest wie eine Routing-Tabelle vor. Es enthält eine Liste von Pointern auf verschiedene architekturspezifische Images, die in deiner Registry gespeichert sind. Wenn eine Maschine dein Image pullt, liest ihr Docker Daemon dieses Manifest, identifiziert seine eigene Host-CPU-Architektur und lädt automatisch nur die Image Layers herunter, die zu seiner Hardware passen. Um eine Backend-API für beide Architekturen gleichzeitig zu cross-kompilieren und zu packagen, nutzt du den Befehl docker buildx build. Du fügst ein Platform-Flag hinzu und übergibst ihm eine kommagetrennte Liste deiner Targets. Zum Beispiel tippst du das Flag ein, gefolgt von linux slash amd64 comma linux slash arm64. Du hängst dein Standard-Image-Tag an und fügst dann ein Push-Flag hinzu. Hier ist der entscheidende Punkt. Wenn du für mehrere Plattformen gleichzeitig buildest, kannst du das finale Multi-Platform Image nicht einfach wieder in deinen lokalen Docker Engine Cache laden. Der lokale Daemon ist nicht dafür ausgelegt, eine Manifest List mit Pointern auf mehrere Architekturen zu halten. Du musst Buildx anweisen, die Ergebnisse direkt in deine Container Registry zu pushen. Die Registry dient als Storage-System, das die Manifest List und die einzelnen Architektur-Images korrekt organisiert. Um den Build für einen Prozessor, den du gar nicht hast, physisch auszuführen, verlässt sich Buildx auf einen Emulator namens QEMU. Docker Desktop konfiguriert das automatisch. Wenn deine ARM-Maschine einen Step erreicht, der eine AMD64-Instruction erfordert, übersetzt der Emulator diese on the fly. Das erfordert null Änderungen an deinem Dockerfile. Wenn du schnellere Build-Zeiten brauchst, kannst du auch Cross-Compilation-Tools direkt in einem Multi-Stage Build verwenden. Das überspringt die Emulation, erfordert aber, dass du bestimmte Compiler-Flags in deinem Code setzt. Die wahre Stärke eines Multi-Platform Manifests liegt darin, dass es den Consumer vollständig von den zugrunde liegenden Hardware-Details isoliert. Ein Developer auf einem Mac und ein Production-Cluster mit Intel pullen exakt dasselbe Image-Tag, und die Registry liefert jedem automatisch das richtige Binary – ganz ohne zusätzliche Konfiguration. Danke, dass du ein paar Minuten mit mir verbracht hast. Bis zum nächsten Mal, mach's gut.
13

Das Docker MCP Toolkit

3m 49s

Verbinde deine KI-Agenten sicher mit lokalen Tools. Diese Episode stellt das Docker Model Context Protocol (MCP) Toolkit vor und erklärt, wie man containerisierte MCP-Server mithilfe von Katalogen und Profilen verwaltet.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 13 von 18. Einem AI Agent direkten Zugriff auf deine lokale Datenbank oder dein Filesystem zu geben, ist unglaublich mächtig. Aber untrusted Integration Scripts direkt auf deiner Host Machine zu installieren, um das zu ermöglichen, ist eine absolute Sicherheitskatastrophe. Das Docker MCP Toolkit fixt das, indem es diese Integrations in isolierte Container auslagert. Das Model Context Protocol, oder MCP, ist ein offener Standard, der es AI Clients, wie der Claude Desktop App oder dem Cursor Editor, ermöglicht, sich mit externen Datenquellen und Tools zu verbinden. Um deiner AI eine neue Capability zu geben, führst du eine kleine Applikation namens MCP Server aus. Bisher hieß das, Third-Party Python oder Node Scripts herunterzuladen und sie direkt auf deinem Betriebssystem auszuführen. Das sorgt für massive Operational Friction durch Dependency Conflicts, und was noch wichtiger ist: Es gibt untrusted Code uneingeschränkten Zugriff auf deine Machine. Das Docker MCP Toolkit löst das, indem es diese Server in Standard Docker Container wrappt. Der erste Teil dieses Systems ist der Catalog. Ein Catalog ist eine Registry von verifizierten, containerisierten MCP Servern. Anstatt random Repositories aus dem Internet zu pullen, pullst du standardisierte Docker Images. Diese Images sind pre-packaged, um die benötigten Tools auszuführen, ohne dass du lokale Language Runtimes auf deiner Host Machine brauchst. Sobald du Zugriff auf diese Server hast, brauchst du einen Weg, sie zu organisieren. Das machst du mit Profiles. Ein Profile ist ein Configuration Grouping, das genau definiert, welche Tools für ein bestimmtes Projekt gebraucht werden. Zum Beispiel könntest du ein Profile namens web-dev erstellen. In dieser Config legst du fest, dass dieses Profile den GitHub Server zum Lesen von Code Repositories und den Playwright Server für Browser Automation braucht. Du setzt deine API Keys und Environment Variables für beide Tools ein einziges Mal innerhalb der Profile Config. Jetzt hast du isolierte Tools und ein definiertes Profile. Wie verbindet sich die AI damit? Hier wird es interessant. Die Connection wird vom MCP Gateway gemanagt. Das Gateway fungiert als zentraler Router, der auf deinem Host läuft. Du konfigurierst deinen AI Client nicht so, dass er einzelne Container launcht. Stattdessen richtest du Claude oder Cursor auf das MCP Gateway und forderst das web-dev Profile an. Wenn der Client sich verbindet, liest das Gateway das Profile, startet automatisch die angeforderten GitHub und Playwright Container im Hintergrund und stellt die Connection her. Das Gateway vermittelt die Kommunikation zwischen dem AI Client und den Containern über das Standardprotokoll. Der AI Client glaubt, er redet mit lokalen Tools, aber die gesamte Execution passiert sicher innerhalb von Docker. Du konfigurierst die Tools nur einmal im Profile, und du kannst genau dieses Setup über beliebig viele verschiedene AI Applications hinweg sharen. Wenn eines dieser Tools sich falsch verhält oder kompromittiert wird, ist es in einem Container gefangen und komplett blind für den Rest deines Systems. Der wahre Wert des MCP Toolkits ist, dass es die Config deiner AI Tools von den Clients trennt, die sie nutzen. Das liefert starke Isolation Guarantees, ohne die Intelligenz deiner Workflows zu opfern. Danke fürs Zuhören. Macht's gut, Leute.
14

Dynamic MCP Auto-Discovery

4m 18s

Erkunde Dynamic MCP, ein experimentelles Feature, das es KI-Clients ermöglicht, den Docker MCP Catalog zu durchsuchen und während einer Konversation dynamisch neue Tool-Server ohne manuelle Einrichtung zu installieren.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 14 von 18. Du bist mitten in einer Unterhaltung mit einem AI Coding Agent und bittest ihn, eine Datenbank abzufragen. Normalerweise, wenn du vergessen hast, das Database Tool vorher zu konfigurieren, wirft der Agent einen Fehler und bittet dich einzugreifen. Das Problem ist, dass die manuelle Tool-Konfiguration deinen Workflow unterbricht. Was aber, wenn der Agent merkt, dass ihm eine Capability fehlt, einen Katalog durchsucht und den nötigen Server komplett on the fly installiert? Genau das erreicht Dynamic MCP Auto-Discovery. Normalerweise bedeutet das Bereitstellen von Tools für ein Large Language Model, dass du sie statisch in einer Config-Datei definierst, bevor du die Session startest. Wenn dein Agent vielleicht ein GitHub-Repository lesen, eine Slack-Nachricht posten und eine Datenbank abfragen muss, musst du all diese Model Context Protocol Server im Voraus laden. Dieser Ansatz müllt das Context Window mit Tools zu, die vielleicht nie benutzt werden, und verlangt von dir, die Bedürfnisse des Agenten perfekt vorherzusagen. Dynamic MCP ändert dieses Paradigma. Es erlaubt dem Agenten, Tools genau dann zu finden und zu attachen, wenn der Task sie erfordert – ganz ohne menschliches Eingreifen. Wenn du das dynamische Feature aktivierst, exposed das Docker MCP Gateway ein Set von Management Tools direkt für den AI Agent. Das Gateway gibt dem Agenten im Grunde die Fähigkeit, seine eigene Toolchain zu managen. Die beiden wichtigsten Tools, die das Gateway für diesen Prozess bereitstellt, sind mcp-find und mcp-add. Der Agent interagiert mit diesen genau so, wie er mit jedem Standard Function Call interagiert. Wir können uns diese Logik anhand eines konkreten Szenarios ansehen. Angenommen, du bittest deinen Agenten, User Metrics zu analysieren, die in einer SQL-Datenbank gespeichert sind. Der Agent evaluiert den Request, checkt sein aktuelles Toolkit und stellt fest, dass er keine Database Querying Tools geladen hat. Anstatt einen Error zu werfen, ruft der Agent das mcp-find Tool auf und übergibt einen relevanten Search String wie postgres. Das Gateway fängt diesen Call ab und fragt den konfigurierten Docker MCP Katalog nach verfügbaren Servern ab, die auf diesen String matchen. Es gibt die Metadaten und Descriptions der matchenden Server an den Agenten zurück. Der Agent liest die Description, bestätigt, dass der Postgres-Server das Problem lösen wird, und geht zum nächsten Schritt über. Der Agent ruft dann das mcp-add Tool auf und übergibt den Identifier des Postgres-Servers, den er gerade gefunden hat. Hier wird es interessant. Das Gateway fängt den mcp-add Request ab, pullt das nötige Image, fährt den MCP-Server in einem Docker-Container hoch und bindet die neuen Tools dynamisch an die aktive Connection. Der Agent hat plötzlich Zugriff auf die Database Tools, verbindet sich mit deiner Datenbank, führt die Query aus, um die du ursprünglich gebeten hast, und gibt das Result zurück. Der gesamte Prozess passiert im Hintergrund, sodass deine Conversation komplett ununterbrochen bleibt. Es gibt noch ein drittes Tool in dieser Management Suite für experimentelle Code Execution, aber das behandelt ein komplett anderes Problem Set, also legen wir unseren Fokus heute strikt auf Discovery. Hier ist die wichtigste Erkenntnis zu diesem Prozess. Wenn der Agent mcp-add nutzt, um einen neuen Server zu laden, ist diese Erweiterung strikt auf die aktuelle Session gescoped. Das Gateway überschreibt deine globalen Config-Dateien nicht, und die neu hinzugefügten Tools persistieren nicht über Restarts hinweg. Wenn du die Session schließt, wird das temporäre Tool Binding zerstört. Das stellt sicher, dass dein Baseline Environment clean und sicher bleibt, während es dem Agenten trotzdem maximale Flexibilität gibt, um komplexe, mehrstufige Probleme dynamisch zu lösen. Indem Catalog Search und Installation als Standard Function Calls exposed werden, nimmt Dynamic MCP dir die Last der Upfront Configuration ab und erlaubt dem Agenten, sein eigenes Environment on demand zu bauen. Das war's für diese Folge. Danke fürs Zuhören, und keep building!
15

Docker Sandboxes für KI

4m 15s

Verstehe die Architektur von Docker Sandboxes. Erfahre, warum autonome KI-Coding-Agenten isolierte MicroVMs mit dedizierten Docker-Daemons anstelle von Standard-Container-Namespaces benötigen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 15 von 18. Ein autonomer AI Coding Agent ist genau die Art von Prozess, den du nicht mit Root-Zugriff auf deinem Laptop laufen lassen willst. Du bittest ihn, einen Bug zu fixen, und plötzlich lädt er beliebige Packages herunter, verändert Systemdateien oder versucht, deine lokale Infrastruktur neu zu bauen. Du brauchst einen Ort, an dem der Agent wie ein Administrator agieren kann, ohne tatsächlich einer zu sein. Genau dieses Problem sollen Docker Sandboxes für AI lösen. Traditionell isoliert Docker Prozesse mithilfe von Linux Namespaces und Control Groups. Diese Container teilen sich den Kernel des Host-Betriebssystems. Für einen vorhersehbaren Web Service funktioniert dieses Modell perfekt. Aber ein AI-Agent ist von Natur aus unberechenbar. Er generiert ungeprüften Code, führt ihn aus und muss oft on the fly neue System Packages installieren, um seine eigenen Lösungen zu testen. Den Host Kernel mit einem unberechenbaren Agenten zu teilen, ist ein zu großes Sicherheitsrisiko. Um das zu lösen, verzichten Docker Sandboxes auf Standard-Container-Namespaces und setzen stattdessen auf isolierte MicroVMs. Wenn du eine Sandbox für einen Agenten startest, bootet eine dedizierte, schlanke Virtual Machine. Der Agent bekommt seinen eigenen, separaten Kernel. Er kann deine Host-Prozesse nicht sehen. Er kann standardmäßig nicht auf deinen Host Network Stack zugreifen. Und am wichtigsten: Es eliminiert das Risiko von traditionellen Container Escape Vulnerabilities komplett. Der Agent ist strikt auf eine hardwarevirtualisierte Box beschränkt. Das ist enorm wichtig, wenn du bedenkst, was AI-Agenten eigentlich tun. Stell dir vor, dein Agent hat die Aufgabe, eine komplexe Web Application zu schreiben, ein Dockerfile dafür zu erstellen und den Build zu testen. Um das zu schaffen, muss der Agent Docker-Befehle ausführen. Wenn du den Docker Socket deines Host-Systems einfach in einen Standard-Container mappen würdest, könnte der Agent theoretisch privilegierte Container direkt auf deiner Host-Maschine starten. Docker Sandboxes verhindern das, indem sie einen komplett isolierten Docker Daemon direkt in der MicroVM laufen lassen. Der Agent kann den ganzen Tag lang Images builden, externe Dependencies pullen und Nested Containers ausführen. Weil er mit dem isolierten Daemon in der MicroVM spricht, bekommt deine Host-System-Docker-Umgebung davon überhaupt nichts mit und bleibt völlig sauber. Sobald der Task beendet ist und die Sandbox zerstört wird, verschwinden der interne Daemon und all seine heruntergeladenen Images sofort. Hier wird es interessant. Wenn die MicroVM komplett isoliert ist, wie bekommst du den fertigen Code dann eigentlich wieder heraus? Die Architektur löst das durch Workspace Mounting. Das ist ein sicherer Filesystem-Passthrough-Mechanismus. Wenn du die Sandbox initialisierst, definierst du ein bestimmtes Verzeichnis auf deinem Host, das als Workspace dient. Genau dieses eine Verzeichnis wird sicher in die MicroVM gemountet. Während der Agent Code schreibt, Tests ausführt oder Assets generiert, speichert er sie in diesem Workspace-Verzeichnis. Der Passthrough synchronisiert genau diese Dateien in Echtzeit zurück in dein Host Filesystem. Der Agent liefert den angeforderten Output, ohne jemals Zugriff auf den Rest deiner Festplatte zu haben. Er kann innerhalb der MicroVM nach Belieben Dinge kaputt machen, aber deine lokalen Dateien bleiben unberührt. Die zentrale Erkenntnis ist, dass es bei der Isolation in diesem Kontext nicht mehr nur darum geht, den Host vor bösartiger externer Software zu schützen. Es geht darum, die unberechenbaren, hochprivilegierten Systemoperationen sicher zu ermöglichen, die ein autonomer Agent ausführen muss, um überhaupt nützlich zu sein. Wenn dir diese Folgen gefallen und du die Show unterstützen möchtest, kannst du auf Patreon nach DevStoriesEU suchen. Das war's für diese Folge. Bis zum nächsten Mal!
16

KI-Agenten-Teams aufbauen

4m 02s

Verlasse dich bei komplexen Aufgaben nicht mehr auf ein einziges KI-Modell. Diese Episode führt das Docker Agent Framework ein und zeigt, wie man spezialisierte, in YAML definierte Agenten-Teams zusammenstellt.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 16 von 18. Du übergibst einem einzelnen AI-Modell einen massiven Application Error. Es versucht, die gesamte Architektur, die Logs und die Target-Syntax gleichzeitig im Kopf zu behalten. Auf halbem Weg verliert es den Überblick und halluziniert einen Fix für eine völlig andere Datei. Ein generisches Modell, das versucht alles zu machen, führt zu einem Context Overload. Um komplexe Probleme zuverlässig zu lösen, brauchst du AI Agent Teams. Mit dem Docker Agent Framework kannst du spezialisierte Teams von AI Agents über eine einfache YAML-Konfigurationsdatei definieren. Anstatt einen monolithischen System Prompt zu schreiben, unterteilst du den Workflow in einzelne Rollen. Du strukturierst das als Hierarchie. Es gibt einen Root Agent, der den Workflow orchestriert, und mehrere Sub-Agents, die spezifische Tasks ausführen. Das isoliert den Context. Jeder Sub-Agent bekommt nur die Informationen, die er für seinen spezifischen Job braucht. Stell dir einen Debugging-Workflow vor. Du brauchst ein Team mit zwei verschiedenen Rollen. Erstens einen Bug Investigator, der Stack Traces analysiert. Zweitens einen Fixer, der den kaputten Code tatsächlich neu schreibt. Du definierst diese gesamte Teamzusammensetzung in einer Datei namens docker dash agent dot yml. Du fängst an, indem du den Root Agent ganz oben in der Datei konfigurierst. Du gibst ihm einen Namen, wählst ein zugrundeliegendes Language Model aus und übergibst System Instructions. Der Root Agent fungiert als Manager. Seine Hauptaufgabe ist es nicht, das Problem direkt zu lösen, sondern Arbeit zu delegieren. Du weist den Root Agent an, basierend auf den Inputs, die er bekommt, zwischen dem Investigator und dem Fixer zu koordinieren. Als Nächstes definierst du die Sub-Agents in derselben YAML-Datei. Du deklarierst den Bug Investigator Agent. Du weist ihm ein Modell zu, das besonders gut im Reasoning und im Lesen von Logs ist. Du gibst ihm strikte Instructions, nur Stack Traces zu lesen, die fehlschlagende Funktion zu identifizieren und eine kurze Erklärung auszugeben, warum sie fehlgeschlagen ist. Dann deklarierst du den Code Fixer Agent. Du weist ihm vielleicht ein Modell zu, das speziell für Code Generation optimiert ist. Seine Instructions sagen ihm strikt, dass er eine fehlschlagende Funktion nehmen und eine korrigierte Version ausgeben soll. Keine Log-Analyse, einfach Code rein und Code raus. Wenn du dieses Team ausführst, interagiert der User nur mit dem Root Agent. Du übergibst dem Root Agent einen massiven Dump von Application Logs. Der Root Agent evaluiert den Request und liest die Beschreibungen seiner verfügbaren Sub-Agents. Er stellt fest, dass der Bug Investigator der richtige Agent für den ersten Schritt ist. Der Root Agent reicht den Log Dump an den Investigator weiter. Der Investigator verarbeitet das Rauschen, findet eine Null Pointer Exception in einer bestimmten Funktion und gibt genau dieses spezifische Detail zurück. Der Root Agent nimmt diese isolierte Information und übergibt sie an den Code Fixer Agent. Der Code Fixer schreibt den Patch und gibt ihn an den Root Manager zurück, der dir dann das finale, saubere Ergebnis zurückgibt. Hier ist der entscheidende Punkt. Der Code Fixer sieht niemals den massiven Stack Trace. Er sieht nur die exakte Funktion, die er fixen muss. Du schützt das Context Window des Coding Models, indem du das Rauschen im Voraus herausfilterst. Indem du einzelnen Sub-Agents in der YAML-Datei enge, spezifische Instructions zuweist, verhinderst du, dass die Modelle vom Task abdriften. Der Root Agent übernimmt die Sequence, und die Sub-Agents übernehmen die Execution. Agents hierarchisch zu strukturieren zwingt dich dazu, AI wie eine Microservice-Architektur zu behandeln und strikte Grenzen dafür festzulegen, worum sich ein einzelnes Modell kümmern darf. Das war's für diese Folge. Danke fürs Zuhören und keep building!
17

Agent Toolsets und Workflows

4m 01s

Mache deine KI-Agenten wirklich nützlich, indem du ihnen die richtigen Einschränkungen gibst. Lerne, wie du Dateisystem-Toolsets konfigurierst und strukturierte Entwicklungs-Workflows in Docker Agent erzwingst.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 17 von 18. Ein AI Agent mit dem fortschrittlichsten Language Model ist für die Entwicklung praktisch nutzlos, wenn er deinen Source Code nicht lesen oder deine Test Suite nicht ausführen kann. Ohne externe Capabilities rät er lediglich die Syntax. Agent Toolsets und Workflows lösen dieses Problem, indem sie die Lücke zwischen einem einfachen Textgenerator und einem arbeitenden Software Engineer schließen. Standardmäßig läuft ein Docker Agent in einem isolierten Container. Er hat keine Ahnung, welche Files in deinem Project Directory existieren. Um das zu ändern, konfigurierst du das Toolsets Array in deiner Agent YAML File. Toolsets sind vorkonfigurierte Capabilities, die dem Agenten direkten Access auf seine Host Environment geben. Für einen Development Agent injectest du typischerweise zwei primäre Toolsets: Filesystem Access und Shell Access. Das Filesystem Toolset erlaubt dem Agenten, deinen Directory Tree zu lesen, Source Files zu öffnen und Code zurück auf die Disk zu schreiben. Das Shell Toolset erlaubt dem Agenten, Terminal Commands auszuführen. Ohne das Toolsets Array ist dein Agent in einer Box gefangen. Mit ihm hat dein Agent Hände und Augen. Einem Agenten Hände und Augen zu geben, ist jedoch ein Rezept für Chaos, wenn ihm die Disziplin fehlt. Ein unstrukturierter Agent ändert vielleicht ein File, nimmt an, dass es funktioniert hat, und meldet Success, ohne jemals auf Syntax Errors zu prüfen. Du steuerst dieses Verhalten über den Instructions Block in der YAML File. Dieser Block ist kein Ort für vage Vorschläge. Hier definierst du einen strikten operativen Workflow. Der zuverlässigste Weg, diese Instructions zu strukturieren, ist, die Agent Tasks in vier obligatorische Phasen zu unterteilen: Analyze, Examine, Modify und Validate. Du schreibst diese direkt in den Instructions Block und sagst dem Agenten, dass er eine Phase abschließen muss, bevor er zur nächsten übergeht. Zuerst kommt Analyze. Der Agent liest den User Prompt, um das gewünschte Feature oder den Bugfix zu verstehen. Als Nächstes kommt Examine. Hier instruierst du den Agenten, sein Filesystem Toolset zu nutzen, um deine Codebase zu durchsuchen, die relevanten Files zu finden und ihren Inhalt zu lesen, um die aktuelle Logik zu verstehen. Als Drittes kommt Modify. Der Agent schreibt den aktualisierten Code auf die Disk. Das ist der Teil, auf den es ankommt. Die vierte Phase ist Validate. Hier zwingst du den Agenten, seine Arbeit mit dem Shell Toolset zu beweisen. Stell dir einen erfahrenen Go Developer Agenten vor. Im Validate-Abschnitt deiner Instructions legst du explizit fest, dass der Agent den Command go test dot slash dot dot dot ausführen muss, gefolgt von golangci dash lint run. Weil der Agent Shell Access hat, führt er genau diese Commands aus. Wenn der Go Compiler einen Syntax Error wirft oder ein Test fehlschlägt, gibt das Toolset diesen Terminal Output direkt an den Agenten zurück. Weil deine Instructions besagen, dass der Task nicht abgeschlossen ist, bis die Validation durchgeht, ist der Agent gezwungen, den Error zu lesen, zurück in die Modify-Phase zu loopen, den Code zu fixen und die Tests erneut auszuführen. Er wird diesen Cycle wiederholen, bis der Linter zufrieden ist und die Tests durchgehen. Access auf das Filesystem und die Shell zu geben, macht deinen Agenten fähig, Software zu schreiben. Aber seine Instructions so zu strukturieren, dass sie eine explizite Test Execution verlangen, macht deinen Agenten zuverlässig. Du bindest seine Tools an einen strikten Validation Loop, sodass du nie wieder broken Code reviewen musst. Das war's für diese Folge. Danke fürs Zuhören und keep building!
18

KI-Modelle in Compose

3m 29s

Behandle deine lokalen LLMs genau wie jede andere Anwendungsabhängigkeit. Lerne, wie du KI-Modelle direkt in deiner Docker Compose YAML-Datei deklarierst, konfigurierst und bindest.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. Docker Masterclass, Folge 18 von 18. Deine Application hängt von einem lokalen Large Language Model ab. Wahrscheinlich startest du eine externe Inference Engine, konfigurierst das Netzwerk manuell und injectest die Endpoint-URLs von Hand. Das funktioniert zwar, aber es zerstört die isolierte Reproduzierbarkeit deiner Umgebung. Dein AI-Modell ist einfach nur eine weitere Dependency und gehört in dein Config-File direkt neben deine Datenbank. Genau das erreichst du mit dem Top-Level models-Element in Docker Compose. Ab Compose Version 2.38 sind models ein natives Konzept. Bisher bedeutete das Ausführen eines lokalen Modells, dass du komplexe Service-Definitions für eine Inference Engine schreiben, Ports manuell exposen und Network Bridges konfigurieren musstest, damit dein Application-Container damit kommunizieren konnte. Der neue models-Block eliminiert diese Reibung, indem er das AI-Modell als eigenständigen Teil der Infrastruktur behandelt. Du fügst einen models-Block ganz oben in deinem File hinzu, auf derselben Einrückungsebene wie services und volumes. Darin benennst du dein Modell. Lass uns ai/smollm2 für eine einfache Chat-Application verwenden. Unter diesem Namen deklarierst du den eigentlichen Model Identifier, den du pullen willst. Hier definierst du auch Hardware Constraints und Engine-Parameter. Du kannst die Context Size festlegen, um die Memory-Nutzung zu begrenzen. Wenn die zugrundeliegende Engine spezifische Launch-Parameter benötigt, definierst du sie über Runtime Flags. Die Model-Config ist isoliert und übersichtlich. Als Nächstes bindest du deine Application an das Modell. Innerhalb deines services-Blocks suchst du den Service deiner Chat-App und fügst ein models-Array hinzu. Über die Short Syntax listest du einfach ai/smollm2 auf. Du musst keine Dependencies manuell konfigurieren oder Custom Networking Aliases einrichten. Hier ist der entscheidende Punkt. Wenn du diese Short Binding Syntax verwendest, übernimmt Compose die Orchestrierung. Es provisioniert im Hintergrund die richtige Inference Engine, um dein angegebenes Modell zu serven. Und das Wichtigste: Es generiert automatisch Standard Environment Variables und injectet sie direkt in deinen Chat-Application-Container. Dein Code wacht mit bereits befüllten Variablen wie OPENAI_BASE_URL auf, die perfekt auf den internen Endpoint des Modells zeigen. Du führst einen einzigen docker compose up-Befehl aus. Compose pullt das smollm2-Modell, konfiguriert die Engine, startet deinen Chat-Service und verkabelt die Connection. Keine manuellen API-Keys, kein Rätselraten bei internen IP-Adressen. Alles routet out of the box korrekt. Ich ermutige dich, die offizielle Documentation zu erkunden und selbst mal so ein File zu schreiben. Da das unsere Masterclass-Serie abschließt, schau gerne auf devstories dot eu vorbei, um Themen für das vorzuschlagen, was wir als Nächstes behandeln. Indem du AI-Modelle zu nativen Elementen in deiner Config erhebst, wird deine Infrastruktur vollständig deklarativ. Das stellt sicher, dass immer genau die Model-Version bootet, die dein Code erwartet. Das war’s für heute. Danke fürs Zuhören – geh und bau etwas Cooles.