Zum Hauptinhalt springen

Docker und Container

Der Satz, den es abschaffen soll

„Bei mir läuft es doch."

Diesen Satz hat jede Entwicklerin schon gesagt und jeder Entwickler schon gehört. Die Software läuft auf dem einen Rechner und auf dem anderen nicht — und niemand weiß auf Anhieb, warum.

Die Gründe sind fast immer dieselben:

Andere VersionBei dir Java 26, auf dem Server Java 21
Fehlendes ZubehörBei dir läuft eine PostgreSQL, auf dem Testrechner nicht
Andere EinstellungEine Umgebungsvariable, die nur bei dir gesetzt ist
Andere ReihenfolgeDie Datenbank war schon da, als die Anwendung startete — beim Kollegen nicht

Jeder einzelne Punkt ist behebbar. Zusammen kosten sie in jedem Projekt Tage.

Die Idee von Docker: Nicht nur das Programm ausliefern, sondern das Programm samt seiner Umgebung. Was einmal läuft, läuft überall gleich.

Was ein Container ist

Ein Container ist ein Prozess, der so abgeschottet läuft, als hätte er den Rechner für sich allein. Er bringt alles mit, was er braucht: seine Programmbibliotheken, seine Konfiguration, seine Dateien. Was er nicht mitbringt, ist ein eigenes Betriebssystem.

Genau darin unterscheidet er sich von einer virtuellen Maschine.

Virtuelle MaschinenAnwendung ABibliothekenAnwendung BBibliothekenGast-BetriebssystemGast-BetriebssystemHypervisorWirts-BetriebssystemHardwarejede Anwendung schleppt ein ganzes Betriebssystem mitContainerAnwendung ABibliothekenAnwendung BBibliothekenContainer-Laufzeit (Docker)Wirts-Betriebssystemein Kern für alle ContainerHardwarealle teilen sich einen Betriebssystemkern

Daraus folgt der praktische Unterschied:

Virtuelle MaschineContainer
StartzeitMinute(n) — das Betriebssystem fährt hochSekunden — nur ein Prozess startet
GrößeGigabyteMegabyte
Wie viele parallel?eine HandvollDutzende
Isolationsehr stark (eigener Kern)stark, aber gemeinsamer Kern
Die häufigste Fehlvorstellung

„Ein Container ist eine kleine virtuelle Maschine."

Nein. In einem Container läuft kein Betriebssystem. Es läuft ein Prozess, den der Kern des Wirtssystems so abschottet, dass er die anderen nicht sieht.

Der Beweis liegt direkt vor dir: Öffne die Prozessliste deines Rechners, während ein Container läuft. Der Datenbankprozess steht dort — als gewöhnlicher Prozess. Es gibt keine zweite Maschine, in der er sich versteckt.

Die praktische Folge: Auf einem Linux-Kern laufen nur Linux-Container. Dass es unter Windows trotzdem funktioniert, liegt daran, dass Docker Desktop im Hintergrund eine schlanke Linux-VM betreibt — eine für alle Container, nicht eine pro Container.

Die drei Begriffe, die man ständig verwechselt

Registryz.B. Docker Hubdas Regal mit denfertigen VorlagenpullImagedie Vorlageunveränderlich,liegt auf der PlatterunContainer 1Container 2laufende ProzesseAus einer Vorlage entstehen beliebig viele laufende Container.
Die Brücke zu dem, was du schon kennst

Image verhält sich zu Container wie Klasse zu Objekt.

Die Klasse Article beschreibt, was ein Artikel ist — sie liegt einmal im Projekt und ändert sich nicht, während das Programm läuft. Mit new Article() entstehen daraus beliebig viele Objekte, jedes mit eigenem Zustand.

Genauso: Das Image postgres:17.6 beschreibt eine PostgreSQL-Installation. Mit docker run entstehen daraus beliebig viele Container, jeder mit eigenen Daten.

Und wie beim Objekt gilt: Was du im Container änderst, ändert das Image nicht. Löschst du den Container, ist die Änderung weg — es sei denn, du hast sie in ein Volume geschrieben (siehe unten).

Was ein Anwendungsentwickler wissen muss

Du wirst in der Ausbildung selten Images bauen. Du wirst aber ständig welche benutzen — für Datenbanken, Message-Broker, Testumgebungen. Dafür reicht ein überschaubarer Vorrat an Wissen.

1. Der Tag ist Teil des Namens

postgres:17.6
└──┬───┘ └─┬─┘
│ └── Tag: die Version
└────────── Name des Images
latest ist keine Version

postgres:latest bedeutet nicht „die neueste", sondern „das Image, das zuletzt mit diesem Tag versehen wurde". Es zeigt heute auf Version 17 und in einem Jahr auf 18 — ohne dass sich in deinem Projekt eine Zeile ändert.

Dann läuft es bei dir noch und beim Kollegen nicht mehr. Genau der Satz, den Docker abschaffen sollte.

Immer eine feste Version angeben.

2. Ports werden durchgereicht

Ein Container ist abgeschottet — auch im Netzwerk. Damit du von außen hineinkommst, musst du einen Port veröffentlichen:

ports:
- "5432:5432"
# ^^^^ ^^^^
# │ └── Port IM Container
# └─────── Port auf DEINEM Rechner

Die linke Zahl kannst du frei wählen, die rechte ist durch das Programm im Container vorgegeben. Ist der Port auf deinem Rechner schon belegt — weil dort bereits eine PostgreSQL läuft —, meldet Docker port is already allocated. Dann änderst du die linke Zahl, etwa auf 5433:5432, und trägst dieselbe Zahl in deiner Anwendungskonfiguration ein.

3. Container sind vergesslich — Volumes nicht

Alles, was ein Container in sein eigenes Dateisystem schreibt, verschwindet mit ihm. Für eine Datenbank wäre das fatal.

Ein Volume ist ein Stück Speicher, das außerhalb des Containers liegt und hineingereicht wird:

volumes:
- webshop-data:/var/lib/postgresql/data
# ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
# │ └── Ort IM Container
# └────────────── Name des Volumes
BefehlWas mit den Daten passiert
docker compose stopContainer hält an, Daten bleiben
docker compose downContainer wird gelöscht, Volume bleibt
docker compose down -vContainer und Volume werden gelöscht — die Daten sind weg
-v ist keine Kleinigkeit

Das -v in docker compose down -v löscht die Datenbank. Nicht die Tabellen — den ganzen Inhalt.

Im Unterricht ist das oft genau das, was du willst: sauber von vorn anfangen. Im Betrieb ist es der Befehl, nach dem man das Backup braucht.

4. Die Befehle, die du wirklich brauchst

docker compose up -d # startet alles aus der docker-compose.yml, im Hintergrund
docker compose ps # was läuft gerade?
docker compose logs -f # was sagt der Container? (-f = mitlaufen lassen)
docker compose stop # anhalten, Daten bleiben
docker compose down # anhalten und Container löschen

Das -d steht für detached: Der Container läuft weiter, auch wenn du das Terminal schließt. Ohne -d blockiert der Container dein Terminal und stirbt mit ihm.

Wenn etwas nicht geht, lies die Logs

docker compose logs ist das erste Mittel bei jedem Problem. Eine Datenbank, die nicht startet, sagt dort, warum — meist in der letzten oder vorletzten Zeile.

Der zweite Blick gilt docker compose ps: Steht dort Up (healthy), läuft der Container und antwortet. Steht dort Exit 1, ist er gestartet und sofort wieder gestorben.

5. Die Datei, die alles zusammenhält

Ein einzelner Container lässt sich mit docker run starten. Sobald mehrere zusammenspielen — Anwendung, Datenbank, vielleicht ein Cache —, schreibt man sie in eine docker-compose.yml. Diese Datei gehört ins Projekt und in die Versionsverwaltung: Sie ist die Beschreibung der Umgebung, und damit Teil des Quelltextes.

Genau so eine Datei benutzt du im Webshop-Tutorial:

docker-compose.yml
services:
webshop-db:
image: postgres:17.6
container_name: webshop-db
environment:
POSTGRES_DB: webshop
POSTGRES_USER: webshop
POSTGRES_PASSWORD: geheim
ports:
- "5432:5432"
volumes:
- webshop-data:/var/lib/postgresql/data

volumes:
webshop-data:
AbschnittBedeutung
servicesDie Container, die zusammen eine Umgebung bilden
imageWelche Vorlage — mit Version
environmentEinstellungen, die beim Start hineingereicht werden
portsWas von außen erreichbar sein soll
volumesWo die Daten liegen, die den Container überleben

Dass Zugangsdaten hier im Klartext stehen, ist für eine Übungsumgebung in Ordnung. Im Betrieb kommen sie aus Umgebungsvariablen oder einem Geheimnisspeicher — nie aus einer Datei im Repository.

Wie ein Image entsteht

Auch wenn du selten eines baust: Du solltest ein Dockerfile lesen können. Es ist eine Bauanleitung, Zeile für Zeile.

Dockerfile
FROM eclipse-temurin:26-jre
WORKDIR /app
COPY target/webshop-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
AnweisungBedeutung
FROMAuf welchem Image wird aufgebaut — hier eine Java-Laufzeitumgebung
WORKDIRIn welchem Verzeichnis wird gearbeitet
COPYWas aus dem Projekt kommt mit hinein
EXPOSEWelchen Port das Programm im Container benutzt (Dokumentation)
ENTRYPOINTWas beim Start ausgeführt wird

Jede Anweisung erzeugt eine Schicht. Ändert sich eine Zeile, werden nur sie und die darunter neu gebaut — deshalb steht das, was sich selten ändert, oben.

Dass eine Spring-Boot-Anwendung ihren Webserver eingebaut mitbringt (siehe Tutorial 01), passt genau dazu: Eine einzige .jar-Datei, ein java -jar, fertig. Genau deshalb lassen sich Spring-Boot-Anwendungen so gut in Container packen.

Wozu das Ganze — jenseits des Klassenraums

AnwendungsfallWas Docker beiträgt
EntwicklungsumgebungJede neue Kollegin ist in Minuten arbeitsfähig: Repository klonen, docker compose up, fertig
TestenJeder Testlauf startet mit einer frischen, immer gleichen Datenbank
AusliefernWas getestet wurde, wird ausgeliefert — dasselbe Image, nicht ein neu gebautes
BetriebMehrere Anwendungen auf einem Server, ohne dass sich ihre Bibliotheken in die Quere kommen
SkalierenVon einem Container auf zehn, ohne dass jemand etwas installiert

Der letzte Punkt ist der Grund, warum Docker und Microservices fast immer zusammen genannt werden: Wer viele kleine Dienste betreibt, braucht eine Verpackung, die sich schnell und einheitlich vervielfältigen lässt.

Und was ist Kubernetes?

Docker startet Container auf einem Rechner. Sobald ein System auf vielen Rechnern läuft, braucht es jemanden, der entscheidet, welcher Container wo läuft, ihn neu startet, wenn er abstürzt, und den Verkehr verteilt.

Das ist die Aufgabe eines Orchestrators, und der verbreitetste heißt Kubernetes. Für die Ausbildung reicht es zu wissen, dass es ihn gibt und wozu — bedienen wirst du ihn frühestens im Betrieb.

Filme

Zum Ansehen statt Lesen — beide auf Deutsch:

FilmWofür
Was ist Docker? (the native web)Der Einstieg: Warum es Container gibt und was sie von VMs unterscheidet
DOCKER Crashkurs — in 20 Minuten (Coding Crashkurse)Die Praxis: Images, Volumes, Compose zum Mitmachen

Wer tiefer einsteigen will: Docker lernen — Eine Einführung in 100 Minuten vom selben Kanal wie der erste Film.

Das Wichtigste in Kürze

  • Ein Container ist ein abgeschotteter Prozess, keine virtuelle Maschine — er teilt sich den Betriebssystemkern mit allen anderen.
  • Image ist die Vorlage, Container die laufende Instanz — wie Klasse und Objekt.
  • Immer eine feste Version angeben, nie latest.
  • ports reicht einen Port nach außen: links dein Rechner, rechts der Container.
  • Daten überleben nur in einem Volume. down -v löscht es.
  • Die docker-compose.yml beschreibt die Umgebung und gehört ins Repository.
  • Bei Problemen: erst docker compose ps, dann docker compose logs.

Weiterlesen

  • Microservices — warum Container und viele kleine Dienste zusammengehören
  • Maven und Abhängigkeiten — dieselbe Grundfrage auf der Ebene der Bibliotheken: Wer sorgt dafür, dass überall dasselbe läuft?
  • Webshop-Tutorial — dort startest du deine erste Datenbank im Container