347

Cloud & DevOps · Container für Entwickler

Dienst mit Container anwenden

Du lernst, deine eigene Anwendung samt Datenbank in Container zu verpacken, sodass sie auf jedem Rechner und in der Cloud gleich läuft.

Fortgeschritten Fortgeschritten ca. 20 Std. SelbststudiumApplikationsentwicklung: 2. Lehrjahr · Berufsfachschule
#Docker#Container#Dockerfile#Docker Compose#Images#Registry#Multi-Stage-Build#DevOps

Überblick

Worum geht es?

'Bei mir läuft es' ist im Team kein Argument. Mit Containern beschreibst du die komplette Laufzeitumgebung deiner Anwendung in einem Dockerfile und baust daraus ein Image, das überall identisch startet. Du verbindest mehrere Container mit Docker Compose, hältst Daten mit Volumes dauerhaft und steuerst die Konfiguration über Umgebungsvariablen. Am Ende veröffentlichst du dein Image in einer Registry, damit Kolleginnen, Testsysteme oder die Cloud es direkt nutzen können.

Wofür brauchst du das?

In vielen Entwicklungsteams in der Schweiz startet die lokale Umgebung mit einem einzigen 'docker compose up', und Deployments in Azure, AWS oder Kubernetes laufen über Container-Images. Wer seine App sauber containerisieren kann, ist ab dem ersten Tag im Projekt produktiv und versteht, was die CI-Pipeline eigentlich baut. Das Wissen brauchst du direkt in 210 (Public Cloud), 324 (DevOps) und 321 (Verteilte Systeme).

Das solltest du schon können

  • Eine kleine Anwendung (z.B. in Node, Java oder Python) selbst schreiben und lokal starten (Modul 319)
  • Eine relationale Datenbank anlegen und von einer Anwendung aus darauf zugreifen (Modul 164)
  • Grundlegende Befehle in der Kommandozeile (cd, ls, Umgebungsvariablen setzen) beherrschen

Typische Tools & Technologien

Docker / Docker DesktopDocker ComposePodmanGitHub Container RegistryAzure Container RegistryNode.js / Spring Boot / .NETPostgreSQLVS Code Dev Containers

Lernziele

Was musst du können?

Das sind die Fähigkeiten, die am Ende des Moduls sitzen sollten. Jedes Ziel mit einem Beispiel aus dem Lehrbetrieb.

  1. 1

    Den Unterschied zwischen Image, Container und virtueller Maschine erklären

    Kompetenz A

    Ein Image ist eine unveränderliche Vorlage, ein Container eine laufende Instanz davon. Container teilen sich den Kernel des Hosts und starten deshalb in Sekunden, während eine VM ein ganzes Betriebssystem mitbringt.

    Situation

    Dein Berufsbildner fragt, warum das Team für die Testumgebung von VMs auf Container umsteigen soll.

    Deine Aufgabe

    Erkläre den Unterschied anhand des eigenen Projekts in drei Sätzen und mit einer Skizze.

    Gutes Ergebnis

    Eine Skizze mit Host, Docker Engine und drei Containern im Vergleich zu drei VMs mit je eigenem Gastbetriebssystem. Fazit: Ein Container startet in 2 Sekunden statt 2 Minuten und braucht 150 MB statt 2 GB RAM.

    ImageContainerLayerContainer-RuntimeKernel-Sharing
  2. 2

    Ein Dockerfile für eine eigene Webanwendung schreiben

    Kompetenz B

    Du wählst ein passendes Basis-Image, kopierst nur das Nötige hinein, installierst Abhängigkeiten und definierst den Startbefehl. Die Reihenfolge der Anweisungen wählst du so, dass der Build-Cache greift und Rebuilds schnell bleiben.

    Situation

    Eine Express-API für die interne Raumreservation läuft bisher nur mit 'npm start' auf deinem Laptop.

    Deine Aufgabe

    Erstelle ein Dockerfile, das die API auf Port 3000 startet.

    Gutes Ergebnis

    Basis 'node:22-alpine', zuerst package.json und package-lock.json kopieren und 'npm ci --omit=dev', danach den Quellcode, 'EXPOSE 3000', Start als Benutzer 'node'. Eine .dockerignore schliesst node_modules und .env aus. Der Rebuild nach einer Codeänderung dauert 4 statt 60 Sekunden.

    FROM / COPY / RUN / CMDBuild-Cache.dockerignoreBasis-ImageNon-root-User
  3. 3

    Images mit Multi-Stage-Builds klein und sicher halten

    Kompetenz C

    Compiler, Testwerkzeuge und Quellcode gehören nicht ins fertige Image. Mit mehreren Build-Stufen trennst du Bauen und Ausführen und erhältst kleinere Images mit weniger Angriffsfläche.

    Situation

    Das Image einer Spring-Boot-Anwendung ist 780 MB gross, weil Maven und das JDK mitgeliefert werden.

    Deine Aufgabe

    Baue das Dockerfile auf einen Multi-Stage-Build um.

    Gutes Ergebnis

    Stufe 1 mit 'maven:3-eclipse-temurin-21' baut das JAR, Stufe 2 mit 'eclipse-temurin:21-jre-alpine' kopiert nur das JAR. Das Image schrumpft von 820 auf 210 MB, und ein Scan mit Trivy zeigt deutlich weniger bekannte Schwachstellen.

    Multi-Stage-BuildBuild- vs. Runtime-ImageImage-GrösseSchwachstellen-Scan
  4. 4

    App und Datenbank mit Docker Compose gemeinsam starten

    Kompetenz D

    Du beschreibst alle Dienste deiner Anwendung in einer compose.yaml: Web-App, Datenbank, eventuell ein Admin-Tool. Die Container finden sich über ihren Dienstnamen, und ein einziger Befehl startet die ganze Umgebung.

    Situation

    Neue Lernende brauchen jedes Mal einen halben Tag, um PostgreSQL und die App lokal einzurichten.

    Deine Aufgabe

    Erstelle eine compose.yaml mit App, PostgreSQL und pgAdmin.

    Gutes Ergebnis

    Drei Dienste, die App verbindet sich über den Hostnamen 'db', die Datenbank hat einen Healthcheck, und die App startet erst, wenn die DB bereit ist. Onboarding: Repo klonen, 'docker compose up', fertig in 3 Minuten.

    compose.yamlServicedepends_on / HealthcheckDocker-NetzwerkPort-Mapping
  5. 5

    Daten mit Volumes sichern und Konfiguration über Umgebungsvariablen steuern

    Kompetenz E

    Container sind wegwerfbar, Daten nicht. Du legst Datenbankdaten in Volumes ab und trennst Konfiguration und Passwörter vom Image, sodass dasselbe Image in Test und Produktion läuft.

    Situation

    Nach 'docker compose down' sind alle Testreservationen weg, und das DB-Passwort steht im Dockerfile.

    Deine Aufgabe

    Mach die Daten persistent und entferne das Passwort aus dem Image.

    Gutes Ergebnis

    Ein benanntes Volume 'pgdata' für /var/lib/postgresql/data (Image postgres:17; ab postgres:18 wird /var/lib/postgresql eingebunden). Passwort und Verbindungsdaten kommen aus einer .env-Datei, die in .gitignore steht. Eine .env.example im Repo zeigt, welche Variablen nötig sind.

    Named VolumeBind MountUmgebungsvariable.env-DateiSecrets
  6. 6

    Ein Image versionieren und in einer Registry veröffentlichen

    Kompetenz F

    Damit andere dein Image nutzen können, taggst du es mit einer sinnvollen Version und pushst es in eine Registry. Idealerweise baut eine CI-Pipeline das Image automatisch bei jedem Merge.

    Situation

    Die Testumgebung des Lehrbetriebs soll immer die neueste Version der Raumreservation ziehen können.

    Deine Aufgabe

    Veröffentliche das Image in der GitHub Container Registry, automatisiert per GitHub Actions.

    Gutes Ergebnis

    Ein Workflow baut bei jedem Push auf main das Image und taggt es mit der Commit-ID und 'latest'. Releases bekommen zusätzlich einen Tag wie '1.4.0'. Die Testumgebung zieht 'ghcr.io/lehrbetrieb/raumreservation:1.4.0'.

    RegistryImage-TagSemantic Versioningdocker push / pullCI-Build

Selbsteinschätzung

Wo stehst du?

Die Kompetenzmatrix zerlegt das Modul in Themenstränge und drei Stufen. Für den Kompetenznachweis solltest du überall mindestens Stufe 2 erreichen. Dein Stand bleibt in diesem Browser gespeichert und färbt Lernweg und Übungen ein.

Tippe auf eine Aussage, um deinen Stand zu setzen: offen unsicher sitzt
A

Container verstehen

Ziel 1

Grundlagen

Fortgeschritten

Erweitert

B

Dockerfile schreiben

Ziel 2

Grundlagen

Fortgeschritten

Erweitert

C

Images optimieren und absichern

Ziel 3

Grundlagen

Fortgeschritten

Erweitert

D

Mehrere Container mit Compose

Ziel 4

Grundlagen

Fortgeschritten

Erweitert

E

Daten und Konfiguration

Ziel 5

Grundlagen

Fortgeschritten

Erweitert

F

Registry und Automatisierung

Ziel 6

Grundlagen

Fortgeschritten

Erweitert

Praxisfall

Die Rampenbuchung im Container

Elias ist im 2. Lehrjahr als Informatiker Applikationsentwicklung bei der Transbox Logistik AG in Härkingen, einem Logistikunternehmen mit 400 Mitarbeitenden. Das interne Entwicklungsteam betreut eine Webanwendung, mit der Speditionen Zeitfenster an den Laderampen buchen. Jede Entwicklerin richtet die Anwendung anders ein, und auf dem Testserver läuft eine Version, die niemand genau kennt, deshalb soll Elias die Anwendung containerisieren.

  1. Kapitel 1

    Warum nicht einfach eine VM?

    Elias startet zuerst ein fertiges PostgreSQL-Image und staunt, dass die Datenbank nach drei Sekunden läuft statt nach einer halben Stunde Installation. Im Teammeeting erklärt er den Unterschied zwischen Image und Container und warum sich Container den Kernel des Hosts teilen. Für die Rampenbuchung schlägt er Container vor, das alte ERP bleibt auf seiner VM.

    Ziel 1

  2. Kapitel 2

    820 MB sind zu viel

    Elias schreibt ein Dockerfile für die Spring-Boot-Anwendung auf Basis eines JDK-Images. Das Image ist 820 MB gross, weil Maven und der ganze Quellcode mitkommen. Mit einem Multi-Stage-Build, der nur das fertige JAR in ein schlankes JRE-Image kopiert, sinkt die Grösse auf 210 MB. Ein Scan mit Trivy zeigt zwei kritische Lücken im alten Basis-Image, die mit einer neueren Version verschwinden.

    Ziel 2Ziel 3

  3. Kapitel 3

    Ein Befehl für alles

    Damit neue Lernende nicht mehr einen halben Tag für die Einrichtung brauchen, schreibt Elias eine compose.yaml mit App, PostgreSQL und Adminer. Beim ersten Start stürzt die App ab, weil sie schneller bereit ist als die Datenbank. Elias ergänzt einen Health Check für PostgreSQL und lässt die App erst starten, wenn dieser grün ist.

    Ziel 4

  4. Kapitel 4

    Wo sind meine Buchungen?

    Nach einem docker compose down sind alle Testbuchungen verschwunden. Elias legt ein benanntes Volume für die Datenbank an und zeigt, dass die Daten jetzt einen Neustart überleben. Das Datenbankpasswort stand bisher direkt in der compose.yaml, deshalb verschiebt er es in eine .env-Datei, die in der .gitignore steht, und legt eine Vorlage .env.example ins Repository.

    Ziel 5

  5. Kapitel 5

    Die Testumgebung zieht automatisch nach

    Zum Schluss baut Elias einen GitHub-Actions-Workflow, der bei jedem Git-Tag ein Image baut und mit der Versionsnummer, etwa 1.4.0, in die GitHub Container Registry pusht. Der Testserver zieht immer eine bestimmte Version statt latest. Als Version 1.4.1 einen Fehler bei der Zeitzonenberechnung hat, stellt Elias die Testumgebung in einer Minute auf 1.4.0 zurück.

    Ziel 6

Lernweg

Wie lernst du das?

  1. 1

    Docker installieren und fremde Images nutzen

    ca. 2 Std.

    Du startest zuerst fertige Container, um ein Gefühl für Images, Ports und Logs zu bekommen.

    • Docker Desktop (unter Windows mit WSL 2) oder Podman installieren
    • nginx und PostgreSQL als Container starten, Ports freigeben, Logs mit 'docker logs' lesen
    • Mit 'docker exec' in einen laufenden Container wechseln und herumschauen

    Trainiert Kompetenz A1A2

    Lernziel1

  2. 2

    Eigene App containerisieren

    ca. 4 Std.

    Du schreibst dein erstes Dockerfile für ein eigenes Projekt und lernst, wie der Build-Cache funktioniert.

    • Ein Dockerfile für eine kleine API aus dem Unterricht schreiben
    • Mit 'docker history' die Layer anschauen und die Reihenfolge der Anweisungen optimieren
    • Eine .dockerignore anlegen und die Build-Zeit vorher und nachher vergleichen

    Trainiert Kompetenz B1B2

    Lernziel2

  3. 3

    Images schlank und sicher machen

    ca. 3 Std.

    Du baust dein Dockerfile auf mehrere Stufen um und prüfst das Ergebnis auf Grösse und Schwachstellen.

    • Ein Multi-Stage-Dockerfile für eine kompilierte App (Java, .NET oder Go) erstellen
    • Bildgrösse mit 'docker images' vergleichen
    • Das Image mit Docker Scout oder Trivy scannen und kritische Funde beheben

    Trainiert Kompetenz C1C2

    Lernziel3

  4. 4

    Mehrere Container orchestrieren

    ca. 4 Std.

    Du verbindest App und Datenbank mit Docker Compose und machst die Daten dauerhaft.

    • Eine compose.yaml mit App, Datenbank und Admin-Oberfläche schreiben
    • Ein Volume einrichten und testen, dass Daten 'docker compose down' überleben
    • Alle Passwörter in eine .env auslagern und eine .env.example committen

    Trainiert Kompetenz D1D2E1E2

    Lernziel45

  5. 5

    Veröffentlichen und automatisieren

    ca. 3 Std.

    Du bringst dein Image in eine Registry und lässt es von einer Pipeline bauen. Mit dem GitHub Student Developer Pack ist das kostenlos.

    • Ein Image manuell taggen und in die GitHub Container Registry pushen
    • Einen GitHub-Actions-Workflow erstellen, der bei jedem Push baut und pusht
    • Das Image auf einem zweiten Rechner oder in einer Codespaces-Umgebung starten

    Trainiert Kompetenz F1F2

    Lernziel6

  6. 6

    Mini-Projekt: Vom Repo zum laufenden Stack

    ca. 4 Std.

    Du kombinierst alles in einem kleinen Projekt, wie es im Kompetenznachweis vorkommen kann.

    • Eine Anwendung mit Datenbank vollständig containerisieren
    • Eine README schreiben, mit der jemand Fremdes den Stack in unter 5 Minuten startet
    • Die Lösung einem Kollegen oder einer Tutorin vorführen und Fragen beantworten

    Trainiert Kompetenz B3D3E3A3

    Lernziel2451

Üben

Übungen aus der Praxis

Schulprojekt-Website im Container

Einstieg Einstieg

Deine Klasse hat eine statische Website für den Berufswahltag gebaut. Sie soll auf jedem Laptop gleich laufen.

Weist nach A1B1

  1. Ein Dockerfile auf Basis von nginx:alpine schreiben, das die HTML-Dateien ausliefert
  2. Image bauen und auf Port 8080 starten
  3. Eine Änderung am HTML machen und neu bauen
Tipp anzeigen

Schau in der Dokumentation des nginx-Images nach, in welchem Ordner die Dateien liegen müssen.

Lösungsskizze anzeigen

FROM nginx:alpine, COPY des Website-Ordners nach /usr/share/nginx/html, Start mit Port-Mapping 8080:80. Optional ein Bind Mount für die Entwicklung, damit Änderungen ohne Rebuild sichtbar sind.

Todo-API mit PostgreSQL

Fortgeschritten Fortgeschritten

Ein Team im Lehrbetrieb entwickelt eine kleine Todo-API. Jede Person hat bisher eine andere PostgreSQL-Version installiert, und Tests schlagen unterschiedlich fehl.

Weist nach B2D2E2

  1. Ein Dockerfile für die API schreiben
  2. Eine compose.yaml mit API und PostgreSQL 16 erstellen
  3. Ein Volume für die Datenbank anlegen und den Neustart testen
  4. Alle Zugangsdaten über eine .env-Datei steuern
Tipp anzeigen

Die API startet oft schneller als die Datenbank. Ein Healthcheck mit 'pg_isready' löst das.

Lösungsskizze anzeigen

Zwei Services, die API nutzt 'db' als Hostnamen. depends_on mit condition service_healthy. Ein benanntes Volume für die Daten, eine .env für POSTGRES_PASSWORD und die DB-URL, eine .env.example im Repo.

Automatisch gebautes, schlankes Produktions-Image

Anspruchsvoll Anspruchsvoll

Die Spring-Boot- oder .NET-Anwendung des Lehrbetriebs soll künftig nur noch als Container ausgeliefert werden. Vorgaben: Image unter 250 MB, kein Root-User, keine kritischen Schwachstellen, automatischer Build bei jedem Merge.

Weist nach C3F3F2

  1. Ein Multi-Stage-Dockerfile erstellen
  2. Die Anwendung als Non-root-User laufen lassen und einen Healthcheck ergänzen
  3. Einen CI-Workflow schreiben, der baut, scannt und in die Registry pusht
  4. Eine Tagging-Strategie festlegen und in der README dokumentieren
Tipp anzeigen

Lass den Schwachstellen-Scan die Pipeline nur bei 'critical' abbrechen, sonst kommst du nie zu einem grünen Build.

Lösungsskizze anzeigen

Build-Stufe mit SDK, Runtime-Stufe mit JRE- oder ASP.NET-Runtime-Image auf Alpine- oder Distroless-Basis. USER-Anweisung mit eigenem Benutzer. Workflow mit docker/build-push-action, Trivy-Scan mit severity CRITICAL und exit-code 1, Tags aus Commit-SHA und Git-Tag.

Selbstcheck

Kannst du das beantworten?

Was ist der Unterschied zwischen einem Image und einem Container?

Das Image ist die unveränderliche Vorlage. Ein Container ist eine laufende (oder gestoppte) Instanz davon mit eigener beschreibbarer Schicht.

Warum kopiert man package.json vor dem restlichen Quellcode ins Image?

Damit der Layer mit 'npm ci' im Cache bleibt, solange sich die Abhängigkeiten nicht ändern. Codeänderungen lösen dann keinen kompletten Neuaufbau aus.

Was passiert mit Daten im Container, wenn du ihn löschst?

Sie sind weg, ausser sie liegen in einem Volume oder Bind Mount.

Wie erreicht die App in Docker Compose die Datenbank?

Über den Dienstnamen als Hostnamen, z.B. 'db:5432'. Compose legt dafür ein gemeinsames Netzwerk mit DNS an.

Warum ist 'latest' als einziger Tag in der Produktion problematisch?

Man weiss nicht, welche Version genau läuft, und kann nicht gezielt auf eine frühere Version zurück.

Was bringt ein Multi-Stage-Build?

Das finale Image enthält nur die Laufzeit und das fertige Artefakt, nicht Compiler und Quellcode. Es ist kleiner und hat weniger Schwachstellen.

Wo gehören Passwörter nicht hin?

Nicht ins Dockerfile, nicht ins Image und nicht ins Git-Repository. Sie werden zur Laufzeit als Variable oder Secret übergeben.

Prüfung

Stolpersteine & Prüfungstipps

Typische Stolpersteine

  • Passwörter mit ENV im Dockerfile setzen. Sie sind danach für alle sichtbar, die das Image haben.
  • 'COPY . .' ohne .dockerignore, sodass node_modules, .git und .env im Image landen.
  • Im Container 'localhost' für die Datenbank verwenden. localhost ist dort der Container selbst.
  • Datenbank ohne benanntes Volume betreiben: Nach 'docker compose down' und 'up' entsteht ein neues anonymes Volume, und die Daten sind scheinbar weg. Zudem löscht 'docker compose down -v' auch benannte Volumes.
  • Ein riesiges Basis-Image wie 'ubuntu' wählen, obwohl ein offizielles Laufzeit-Image existiert.
  • Die App als root laufen lassen, weil es ohne Anpassung funktioniert.

Tipps für den Kompetenznachweis

  • Kenne die wichtigsten Befehle auswendig: build, run, ps, logs, exec, compose up/down. Im Prüfungsstress hilft das enorm.
  • Teste nach jeder Änderung am Dockerfile sofort mit einem Build, statt zehn Änderungen auf einmal zu machen.
  • Kommentiere in compose.yaml kurz, warum ein Port oder Volume nötig ist.
  • Wenn ein Container sofort stoppt, schau zuerst in 'docker logs'. Dort steht fast immer die Ursache.

Glossar

Begriffe kurz erklärt

Image
Unveränderliche Vorlage aus mehreren Schichten, aus der Container gestartet werden.
Container
Laufende, isolierte Instanz eines Images mit eigenem Dateisystem, Netzwerk und Prozessen.
Dockerfile
Textdatei mit Bauanweisungen für ein Image.
Layer
Eine Schicht im Image, die durch eine Anweisung im Dockerfile entsteht und gecacht werden kann.
Volume
Von Docker verwalteter Speicherbereich, der unabhängig vom Container bestehen bleibt.
Docker Compose
Werkzeug, das mehrere Container mit Netzwerken und Volumes aus einer YAML-Datei startet.
Registry
Server, der Images speichert und verteilt, z.B. Docker Hub oder GitHub Container Registry.
Multi-Stage-Build
Dockerfile mit mehreren FROM-Stufen, bei dem nur die letzte Stufe im finalen Image landet.

Mit KI-Tutor

Jeder Kurs hat einen persönlichen KI-Tutor

  • Erklärt in deinem Tempo
  • Debuggt mit dir
  • Fachgespräch wie im QV
  • Unbegrenzt neue Übungen

Denkanstösse statt fertiger Lösungen. In der Gratis-Lektion zum Ausprobieren.

KI-Tutor · Modul 164Nur Tipps

Mein JOIN liefert plötzlich doppelte Zeilen. Was mache ich falsch?
Gute Frage! Schau dir die Spalte an, über die du verbindest: Ist sie in beiden Tabellen eindeutig? Was passiert mit einer Kundin, die zwei Bestellungen hat?
Ah, dann kommt sie zweimal vor …
Genau. Willst du die Bestellungen zählen oder nur die Kundinnen sehen? Je nachdem hilft dir GROUP BY oder DISTINCT.

Tutavio

So helfen wir dir bei Modul 347

  • Wir containerisieren gemeinsam dein aktuelles Schul- oder Betriebsprojekt und besprechen jede Zeile im Dockerfile.
  • Wenn dein Container sofort abstürzt oder die App die Datenbank nicht findet, debuggen wir mit dir per Bildschirmfreigabe Logs und Netzwerk.
  • Wir prüfen dein Image auf Grösse, Root-User und Secrets und zeigen dir konkrete Verbesserungen.
  • Wir richten mit dir eine GitHub-Actions-Pipeline ein, die dein Image automatisch baut und in die Registry pusht.

Unverbindlich anfragen. Wir melden uns innert 24 Stunden.

Tutor:in für Modul 347 finden

Passende Module

Diese Seite ist eine eigene Lernhilfe von Tutavio und keine offizielle Modulbeschreibung. Nummer, Titel und Einordnung stammen aus den öffentlichen Bildungsplänen. Die verbindliche Modulidentifikation findest du im Modulbaukasten von ICT-Berufsbildung Schweiz.

Gratis-LektionNachhilfe