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.
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:
| Schicht | Beispiel | Wo sie liegt | Was bei Verlust passiert |
|---|---|---|---|
| Programm (Image) | mariadb:11.4 | in einer Registry im Internet | einfach neu herunterladen |
| Konfiguration | compose.yaml, .env | /opt/stacks/wiki/ auf dem Host | aus Git oder dem Backup holen |
| Daten (Volume) | Datenbank, hochgeladene Bilder | Docker-Volume auf dem Host | nur 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.
| Teil | Aufgabe | Analogie |
|---|---|---|
docker (CLI) | Befehle entgegennehmen und an den Daemon schicken | Fernbedienung |
dockerd (Daemon) | Images, Container, Netzwerke und Volumes verwalten | Fernseher |
containerd und runc | Container tatsächlich starten und isolieren | Bildröhre und Elektronik |
| Compose-Plugin | Mehrere Container aus einer compose.yaml steuern | Szenen-Taste «Kinoabend» |
/var/run/docker.sock | Schnittstelle, über die CLI und Daemon reden | Infrarot-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.
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:
| Registry | Adresse | Beispiel |
|---|---|---|
| Docker Hub | docker.io (Standard) | mariadb:11.4, louislam/uptime-kuma:1.23.16 |
| GitHub Container Registry | ghcr.io | ghcr.io/requarks/wiki:2.5 |
| LinuxServer.io | lscr.io | lscr.io/linuxserver/bookstack:version-v25.05.1 |
| Quay | quay.io | Images 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.
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ührendenv) 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 mitlatestalphabetisch sortiert.
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.
for pkg in docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc; do
sudo apt-get remove -y "$pkg"
doneSchritt 2: Signaturschlüssel von Docker holen. Damit prüft apt, dass die Pakete wirklich von Docker stammen.
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.ascSchritt 3: Repository eintragen. Ubuntu 24.04 verwendet für Paketquellen das Format mit .sources-Dateien.
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.
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginSchritt 5: Dienst prüfen. Der Daemon soll laufen und beim Booten automatisch starten.
systemctl is-active docker # Ausgabe: active
systemctl is-enabled docker # Ausgabe: enabledSchritt 6: Mit einem Testcontainer prüfen.
sudo docker run --rm hello-worldDie 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.
docker version --format '{{.Server.Version}}' # z.B. 28.x
docker compose version # Docker Compose version v2.xLuca 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:
sudo docker run -d --name test-web -p 8080:80 nginx:1.27
curl -s http://localhost:8080 | head -n 4Die Willkommensseite von nginx erscheint. Luca lässt den Container vorerst laufen. Merk ihn dir: In Lektion 2 zeigt er eine unangenehme Überraschung.
Luca installiert Docker Engine auf einer frischen Ubuntu-Server-VM aus dem offiziellen Repository. Bring die Schritte in die richtige Reihenfolge.
- 1
Mit sudo docker run --rm hello-world die Installation testen
- 2
Konkurrierende Pakete wie docker.io und podman-docker entfernen
- 3
Signaturschlüssel von Docker nach /etc/apt/keyrings herunterladen
- 4
Das Docker-Repository als Paketquelle eintragen
- 5
apt-get update ausführen und docker-ce mit Compose-Plugin installieren
Typische Fehler
- Pakete aus mehreren Quellen mischen. Wer
docker.ioaus Ubuntu unddocker-cevon 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. Nutzesudooder die geregelte Gruppenlösung aus Lektion 2. latestim Betrieb. Was heute funktioniert, ist nach dem nächstenpullvielleicht eine andere Hauptversion. Immer eine konkrete Version eintragen.- Images von unbekannten Accounts. Ein Image von
irgendwer123/wikikann alles enthalten. Bevorzuge offizielle Images und die Images der Projekte selbst. - Testcontainer vergessen.
docker ps -azeigt 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),containerdund 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.iooderlscr.io. Ohne Tag nimmt Dockerlatest, 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.