Modulseite

Lektion 1 von 9

Vom Handbetrieb zum Container-Dienst

Du verstehst, warum Container den Betrieb von Serverdiensten vereinfachen, trennst Programm, Konfiguration und Daten und installierst Docker Engine sauber aus dem offiziellen Repository.

ca. 40 Min.0/3 Checks gelöst

Worum es geht

Bei der Bergsicht Informatik GmbH in Chur läuft das interne Wiki seit Jahren auf einer alten VM. Jemand hat damals PHP, einen Webserver und die Wiki-Software von Hand installiert, ein paar Konfigurationsdateien angepasst und dann nie mehr etwas angefasst. Seit zwei Jahren hat niemand das System aktualisiert. Der Grund ist nicht Faulheit, sondern Angst: Niemand weiss genau, welche Dateien verändert wurden und ob das Wiki ein Update überlebt.

Lucas Berufsbildnerin stellt ihm eine einfache Frage: «Wenn diese VM morgen kaputt ist, wie lange brauchst du, bis das Wiki wieder läuft?» Luca weiss es nicht. Und genau das ist das Problem.

In diesem Kurs baust du mit Luca eine Plattform, auf der diese Frage eine klare Antwort hat. Jeder Dienst ist in einer Datei beschrieben, Programm und Daten sind sauber getrennt, ein Update ist eine geänderte Versionsnummer, und ein getestetes Backup bringt alles in definierter Zeit zurück. Das Werkzeug dafür heisst Container. Du schaust dabei aus Sicht des Betriebs auf Container: Du baust keine eigenen Images (das ist Thema von Modul 347), sondern betreibst fertige Dienste sicher, wartbar und überwacht.

Das Betriebsmodell: Programm, Konfiguration und Daten trennen

Stell dir einen Mietwagen vor. Wenn er eine Panne hat, bekommst du von der Vermietung ein gleiches Modell. Das Auto selbst ist austauschbar. Wichtig sind nur zwei Dinge: dein Gepäck im Kofferraum und deine Einstellungen (Sitz, Spiegel, Radiosender), die du dir notiert hast. Wer das Gepäck rechtzeitig umlädt, ist nach zehn Minuten wieder unterwegs.

Ein Container-Dienst funktioniert genauso. Er besteht aus drei Schichten, die du strikt auseinanderhältst:

SchichtBeispielWo sie liegtWas bei Verlust passiert
Programm (Image)mariadb:11.4in einer Registry im Interneteinfach neu herunterladen
Konfigurationcompose.yaml, .env/opt/stacks/wiki/ auf dem Hostaus Git oder dem Backup holen
Daten (Volume)Datenbank, hochgeladene BilderDocker-Volume auf dem Hostnur aus dem Backup zu retten

Bei der alten Wiki-VM sind alle drei Schichten vermischt: Programmdateien, angepasste Konfiguration und Daten liegen kreuz und quer im Dateisystem. Darum traut sich niemand an ein Update.

Im Betrieb spricht man auch von Einzelstück und Serienteil. Die alte VM ist ein Einzelstück: über Jahre von Hand gepflegt, nicht reproduzierbar. Ein Container ist ein Serienteil: Du kannst ihn jederzeit löschen und aus Image und Konfiguration identisch neu erzeugen. Er hat keinen Wert an sich. Wertvoll sind nur die Daten und die Beschreibung.

Das Zielbild für die Bergsicht Informatik

Bevor Luca einen Befehl eintippt, zeichnet er auf, wohin die Reise geht. Dieses Zielbild baust du Lektion für Lektion auf:

  • Container-Host (Lektionen 1 und 2): eine Ubuntu-VM mit Docker Engine, abgesichert mit SSH-Schlüsseln und Firewall.
  • Stacks (Lektionen 3 und 4): Wiki und Datenbank als Compose-Stack, die Datenbank nur im internen Netzwerk.
  • Reverse Proxy (Lektion 5): Traefik nimmt alle Anfragen entgegen und sorgt für HTTPS.
  • Backup (Lektion 6): Dumps und Volumes gehen verschlüsselt an zwei Orte.
  • Betrieb (Lektionen 7 und 8): Updates mit Rückweg, Ressourcenlimits, Logs und Alarme.
  • Ausblick (Lektion 9): Wie Kubernetes dieselben Ideen auf mehrere Server verteilt.

Docker Engine: was du eigentlich installierst

«Docker» ist nicht ein einzelnes Programm, sondern ein Zusammenspiel mehrerer Teile. Eine gute Analogie ist ein Fernseher mit Fernbedienung: Du drückst Knöpfe auf der Fernbedienung, aber die Arbeit macht das Gerät.

TeilAufgabeAnalogie
docker (CLI)Befehle entgegennehmen und an den Daemon schickenFernbedienung
dockerd (Daemon)Images, Container, Netzwerke und Volumes verwaltenFernseher
containerd und runcContainer tatsächlich starten und isolierenBildröhre und Elektronik
Compose-PluginMehrere Container aus einer compose.yaml steuernSzenen-Taste «Kinoabend»
/var/run/docker.sockSchnittstelle, über die CLI und Daemon redenInfrarot-Kanal

Der Daemon läuft als Systemdienst mit Root-Rechten. Wer über den Socket mit ihm sprechen darf, kann alles auf dem Host. Das ist der Grund, warum du in Lektion 2 genau regelst, wer Docker bedienen darf.

Check 1 · ZuordnenEinstieg

Ordne jedem Teil von Docker seine Aufgabe zu.

Images aus Registries

Images holst du aus einer Registry, einem Server, der Images speichert und verteilt. Die wichtigsten für den Betrieb:

RegistryAdresseBeispiel
Docker Hubdocker.io (Standard)mariadb:11.4, louislam/uptime-kuma:1.23.16
GitHub Container Registryghcr.ioghcr.io/requarks/wiki:2.5
LinuxServer.iolscr.iolscr.io/linuxserver/bookstack:version-v25.05.1
Quayquay.ioImages verschiedener Open-Source-Projekte

Eine Image-Referenz hat die Form registry/namensraum/name:tag. Fehlt die Registry, nimmt Docker docker.io. Fehlt der Tag, nimmt Docker latest. Ein Name ohne Namensraum wie mariadb ist ein Docker Official Image, gepflegt von Docker zusammen mit dem jeweiligen Projekt.

Bevor du ein Image in Betrieb nimmst, prüfst du vier Dinge: Wer pflegt es (offizielles Projekt, bekannter Anbieter oder unbekannter Account)? Wann wurde es zuletzt aktualisiert? Gibt es eine Dokumentation mit Ports, Variablen und Volumes? Und welche Tags gibt es, um eine Version fest zu wählen?

Im folgenden Code-Labor baust du ein kleines Prüfwerkzeug, das in einer Liste von Images alle latest-Fallen findet, auch die versteckten ohne Tag.

Check 2 · Code-LaborFortgeschritten

Code-Labor: Die latest-Fallen finden

Im Betrieb soll kein Dienst unbemerkt auf latest laufen. Schreibe drei Funktionen:

  • tag_von(image) liefert den Tag einer Image-Referenz. Ohne Tag gilt "latest". Enthält die Referenz ein @ (Digest), liefere "digest". Achtung: Eine Registry kann einen Port haben (registry.bergsicht.ch:5000/intern/wiki). Der Tag steht deshalb nur im Teil nach dem letzten /.
  • einstufen(image) liefert "digest", "latest", "schwebend" oder "fix". Schwebend ist ein Tag, der (nach einem optionalen führenden v) aus einer oder zwei reinen Zahlen besteht, z.B. 16, 11.4, v3, v3.3. Alles andere ist fix, z.B. 1.23.16, 16.4-alpine, version-v25.05.1.
  • latest_dienste(stack) bekommt ein Dict Dienstname zu Image und liefert die Dienste mit latest alphabetisch sortiert.
Code-Labor · Python
Strg + Enter

Schritt für Schritt: Docker Engine auf Ubuntu Server 24.04 installieren

Luca hat eine frische VM mit Ubuntu Server 24.04, 4 vCPU und 8 GB RAM. Er installiert Docker aus dem offiziellen Repository von Docker, nicht aus den Ubuntu-Paketen (docker.io). Die Distributionspakete sind oft älter und anders aufgeteilt, und das Compose-Plugin fehlt oder heisst anders.

Schritt 1: Konkurrierende Pakete entfernen. Falls jemand schon etwas installiert hat, entfernt Luca es. Volumes und Images bleiben dabei erhalten.

Bash
for pkg in docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc; do
  sudo apt-get remove -y "$pkg"
done

Schritt 2: Signaturschlüssel von Docker holen. Damit prüft apt, dass die Pakete wirklich von Docker stammen.

Bash
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

Schritt 3: Repository eintragen. Ubuntu 24.04 verwendet für Paketquellen das Format mit .sources-Dateien.

Bash
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

$VERSION_CODENAME ergibt bei Ubuntu 24.04 noble.

Schritt 4: Pakete installieren.

Bash
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Schritt 5: Dienst prüfen. Der Daemon soll laufen und beim Booten automatisch starten.

Bash
systemctl is-active docker     # Ausgabe: active
systemctl is-enabled docker    # Ausgabe: enabled

Schritt 6: Mit einem Testcontainer prüfen.

Bash
sudo docker run --rm hello-world

Die Ausgabe beginnt mit Hello from Docker! und erklärt, was gerade passiert ist: Der Client hat den Daemon kontaktiert, der Daemon hat das Image von Docker Hub geladen, einen Container gestartet und dessen Ausgabe zurückgeschickt. --rm löscht den Container danach wieder.

Schritt 7: Versionen für die Dokumentation notieren.

Bash
docker version --format '{{.Server.Version}}'   # z.B. 28.x
docker compose version                          # Docker Compose version v2.x

Luca hält beide Versionen im Betriebshandbuch fest. Bei einem Fehler später ist das die erste Frage, die jemand stellt.

Schritt 8: Ein Webserver als Probe. Zum Schluss will Luca sehen, ob ein Dienst von aussen erreichbar ist:

Bash
sudo docker run -d --name test-web -p 8080:80 nginx:1.27
curl -s http://localhost:8080 | head -n 4

Die Willkommensseite von nginx erscheint. Luca lässt den Container vorerst laufen. Merk ihn dir: In Lektion 2 zeigt er eine unangenehme Überraschung.

Check 3 · ReihenfolgeEinstieg

Luca installiert Docker Engine auf einer frischen Ubuntu-Server-VM aus dem offiziellen Repository. Bring die Schritte in die richtige Reihenfolge.

  1. 1

    Mit sudo docker run --rm hello-world die Installation testen

  2. 2

    Konkurrierende Pakete wie docker.io und podman-docker entfernen

  3. 3

    Signaturschlüssel von Docker nach /etc/apt/keyrings herunterladen

  4. 4

    Das Docker-Repository als Paketquelle eintragen

  5. 5

    apt-get update ausführen und docker-ce mit Compose-Plugin installieren

Typische Fehler

  • Pakete aus mehreren Quellen mischen. Wer docker.io aus Ubuntu und docker-ce von Docker gleichzeitig installiert oder Docker als Snap nachschiebt, hat zwei Daemons oder kaputte Abhängigkeiten. Entscheide dich für das offizielle Repository und entferne den Rest.
  • Den Socket für alle öffnen. Bei «permission denied while trying to connect to the Docker daemon socket» hilft nicht chmod 666 /var/run/docker.sock. Damit bekommt jeder Benutzer auf dem Host faktisch Root-Rechte. Nutze sudo oder die geregelte Gruppenlösung aus Lektion 2.
  • latest im Betrieb. Was heute funktioniert, ist nach dem nächsten pull vielleicht eine andere Hauptversion. Immer eine konkrete Version eintragen.
  • Images von unbekannten Accounts. Ein Image von irgendwer123/wiki kann alles enthalten. Bevorzuge offizielle Images und die Images der Projekte selbst.
  • Testcontainer vergessen. docker ps -a zeigt auch gestoppte Container. Aufräumen gehört zur Installation dazu.

Zusammenfassung

  • Ein Container-Dienst besteht aus Programm (Image), Konfiguration (compose.yaml, .env) und Daten (Volumes). Nur die Daten sind ohne Backup verloren.
  • Container sind Serienteile: jederzeit löschbar und identisch neu erzeugbar.
  • Docker besteht aus CLI, Daemon (dockerd), containerd und dem Compose-Plugin. Der Daemon läuft als root, wer den Socket bedienen darf, hat Root-Rechte.
  • Images kommen aus Registries wie Docker Hub, ghcr.io oder lscr.io. Ohne Tag nimmt Docker latest, im Betrieb pinnst du Versionen.
  • Docker installierst du aus dem offiziellen Repository mit geprüftem Signaturschlüssel und testest mit hello-world.

Mit deiner eigenen KI vertiefen

Kopiere einen Prompt in Claude, ChatGPT oder Claude Code. Er macht die KI zur Lernbegleitung statt zum Lösungsautomaten.

Das Betriebsmodell von Containern verstehen Chat-KI

Wenn dir noch unklar ist, warum Container den Betrieb vereinfachen und was Image, Container, Volume und Registry genau sind. Die KI erklärt und prüft danach dein Verständnis.