Wer ersetzt einen Container, wenn sein Rechner ausfällt?

Eine Anwendung läuft zunächst auf einem Rechner. Später braucht sie mehrere Instanzen, regelmäßige Updates und einen Ersatz, wenn ein Prozess oder Rechner ausfällt. Kubernetes ist eine Plattform zur Container-Orchestrierung: Sie koordiniert die Ausführung von Anwendungen auf einem Cluster, also einer Gruppe von Rechnern. Du beschreibst den gewünschten Zustand; mehrere Komponenten arbeiten laufend daran, den tatsächlichen Zustand daran anzugleichen.

Docker Compose beschreibt einen Verbund von Services und eignet sich etwa für lokale Entwicklung und überschaubaren Betrieb auf einem Host. Kubernetes bringt eine Cluster-API, Scheduling und Regelkreise mit. Es ist kein anderer Name für Compose und auch kein automatischer nächster Pflichtschritt für jede Anwendung. Für eine einzelne kleine Website kann der Betriebsaufwand einer Clusterplattform den Nutzen übersteigen.

Ein einfaches Beispiel für den Desired State, den Sollzustand, lautet: „Zwei Instanzen dieses Webservers sollen laufen.“ Du schreibst nicht selbst eine Endlosschleife zum Neustarten. Kubernetes vergleicht beobachteten Zustand und Vorgabe und veranlasst passende Änderungen. Dieser Abgleich heißt Reconciliation. Er benötigt Zeit und verfügbare Ressourcen; die Vorgabe ist keine Garantie, dass jederzeit zwei gesunde Instanzen existieren.

Control Plane steuert, Nodes führen Anwendungen aus.

Die Control Plane verwaltet den Clusterzustand. Ihr API Server nimmt API-Anfragen entgegen, authentifiziert und autorisiert sie und führt sie durch die konfigurierte Zulassungsprüfung. etcd ist der konsistente Schlüssel-Wert-Speicher für Clusterdaten. Es ist keine allgemeine Datenbank für deine Anwendung und benötigt besonders geschützten Zugriff und geeignete Sicherungen.

Der Controller Manager betreibt Regelkreise für verschiedene Ressourcen. Der Scheduler sucht für noch nicht zugewiesene Pods einen passenden Node. Dabei berücksichtigt er unter anderem Ressourcenanforderungen und Platzierungsregeln. Er startet nicht selbst den Container. Auf dem Zielnode überwacht das kubelet die dort vorgesehenen Pods und beauftragt über die Container Runtime Interface, kurz CRI, eine Runtime wie containerd oder CRI-O. Die Runtime lädt Images und führt Container aus. Docker Engine ist dafür keine zwingende Voraussetzung; der frühere eingebaute dockershim wurde entfernt.

Ein Worker Node ist eine Maschine für Workloads. Die Control Plane kann aus mehreren Maschinen bestehen; kleine Lerncluster fassen Rollen auch auf einem Rechner zusammen. Eine Netzwerkimplementierung, häufig über Container Network Interface (CNI), stellt Pod-Verbindungen und gegebenenfalls Netzwerkrichtlinien bereit. Services brauchen eine passende Weiterleitung, beispielsweise kube-proxy oder eine alternative Datenebene. Cluster-DNS ergänzt die Namensauflösung. Diese Funktionen entstehen nicht allein durch das Schreiben eines Deployment-Manifests.

01 / Steuerung und TrafficDie Control Plane mit API Server, etcd, Scheduler und Controllern steuert die Nodes. Auf einem Node führen kubelet und Runtime die Pods aus. Der separate Datenpfad führt vom Eingang über den Service zu bereiten Pods auf diesen Nodes. Die vertikale Reihenfolge zeigt Aufgaben, nicht eine Verkabelung durch den API Server.01 / Steuerung und TrafficControl Plane · SteuerungAPI Server + etcdScheduler + ControllerWorker Nodeskubelet + Container RuntimeNetzwerkimplementierungPods auf diesen Nodesein oder mehrere Containergemeinsamer NetzwerkraumDatenpfad · separatEingang → Service → PodsService wählt bereite ZieleAPI-Steuerung ≠ Webdatenpfad
Die Control Plane mit API Server, etcd, Scheduler und Controllern steuert die Nodes. Auf einem Node führen kubelet und Runtime die Pods aus. Der separate Datenpfad führt vom Eingang über den Service zu bereiten Pods auf diesen Nodes. Die vertikale Reihenfolge zeigt Aufgaben, nicht eine Verkabelung durch den API Server.

Das Diagramm trennt Steuerung und Datenverkehr. Der API Server transportiert gewöhnliche Browseranfragen nicht stellvertretend durch die Webanwendung. Die konkrete Netzwerkimplementierung kann sich unterscheiden. Hintergründe zu DNS, Routing und Netzsegmentierung helfen, diese Aufgaben einzuordnen.

Ein Deployment verwaltet Pods über ReplicaSets.

Ein Pod ist die kleinste von Kubernetes geplante ausführbare Einheit. Er enthält einen oder mehrere eng zusammengehörende Container. Die Container eines Pods teilen sich einen Netzwerkkontext, können sich über localhost erreichen und können ausdrücklich eingebundene Volumes gemeinsam verwenden. Ein Pod ist deshalb nicht dasselbe wie ein einzelner Container. Zwei Container in getrennten Pods haben dagegen nicht automatisch denselben lokalen Netzwerkraum.

Ein einzelner von Hand angelegter Pod hat noch keinen Controller, der nach seiner Löschung eine neue Instanz erzeugt. Für einen gewöhnlichen zustandslosen Webdienst verwendet man ein Deployment. Es verwaltet normalerweise ReplicaSets, welche die geforderte Zahl passender Pods aufrechterhalten. Das Deployment koordiniert auch den Wechsel zwischen ReplicaSets bei einer neuen Podvorlage.

Ein Label ist ein Schlüssel-Wert-Merkmal, etwa app: bitsicht-web. Ein Selector wählt anhand solcher Merkmale Ressourcen aus. Beim Deployment müssen spec.selector.matchLabels und die Labels seiner Podvorlage zueinander passen. Der Service wählt anschließend dieselben Pods unabhängig vom Namen des Deployments aus. Gleich aussehende Ressourcennamen stellen diese Verbindung nicht automatisch her.

02 / Sollzustand wird BetriebEin Manifest wird an den API Server übermittelt und als gewünschter Zustand gespeichert. Controller erzeugen beziehungsweise verwalten ReplicaSets und Pods. Der Scheduler weist neue Pods geeigneten Nodes zu; das kubelet startet dort über die Runtime die Container. Beobachtete Abweichungen lösen den erneuten Abgleich aus.02 / Sollzustand wird BetriebManifestDeployment: zwei ReplikenAPI Server + Speicherungprüft und speichert VorgabeController-RegelkreisDeployment → ReplicaSetReplicaSet → PodsSchedulerweist neue Pods Nodes zukubelet + RuntimeContainer auf Node startenZustand zurückmeldenAbweichung → erneuter Abgleich
Ein Manifest wird an den API Server übermittelt und als gewünschter Zustand gespeichert. Controller erzeugen beziehungsweise verwalten ReplicaSets und Pods. Der Scheduler weist neue Pods geeigneten Nodes zu; das kubelet startet dort über die Runtime die Container. Beobachtete Abweichungen lösen den erneuten Abgleich aus.

Der Regelkreis beobachtet etwa, dass ein Pod fehlt. Ein Controller erzeugt daraufhin einen Ersatz-Pod; der Scheduler weist ihn einem geeigneten Node zu. Das kubelet lässt dort dessen Container starten. Sind keine passenden Ressourcen verfügbar, kann der Pod im Zustand Pending bleiben. Ein ausgefallener Node wird erst erkannt und verarbeitet; Ersatz ist weder sofortig noch unabhängig von Speicher- und Netzbedingungen möglich.

Ein Service bleibt erreichbar, während Pods wechseln.

Pods sind austauschbar und bekommen bei einer Neuerstellung häufig andere IP-Adressen. Ein Service bietet eine beständige Zugangsbeschreibung zu einer Gruppe von Pods. Bei einem gewöhnlichen Service mit Selector führen EndpointSlices die passenden Endpunkte und deren Bereitschaft. Der Verkehr wird durch die Datenebene zu geeigneten Endpunkten geleitet. Ein Service startet keine Pods und prüft nicht selbst die Fachfunktion deiner Anwendung.

Welche Zugangsebene wird eingerichtet?
TypZugang und Voraussetzungen
ClusterIPGewöhnlich eine interne virtuelle Service-IP und DNS-Name. Standardtyp; kein automatisch öffentlicher Zugang.
NodePortEin zugeteilter Port auf Nodeadressen leitet zum Service. Erreichbarkeit hängt von Routing, Firewall und Clusterkonfiguration ab.
LoadBalancerFordert einen Lastverteiler über eine passende Implementierung an. Eine Cloudintegration oder lokale Lösung muss ihn bereitstellen; externe IP und Kosten entstehen nicht überall gleich.

Ingress beschreibt HTTP-/HTTPS-Routing, beispielsweise nach Hostname und URL-Pfad. Es benötigt einen Ingress Controller. Die Ingress-API ist funktional eingefroren, bleibt aber als stabile API verfügbar. Die Gateway API trennt Infrastruktur- und Routingrollen genauer und wird für weitergehende Funktionen entwickelt. Auch sie braucht passende API-Erweiterungen und eine geeignete Implementierung. Keine dieser Ressourcen ist von allein ein lauffähiger Router oder ein ausgestelltes TLS-Zertifikat.

Im selben Namespace kann ein Pod den Service häufig kurz als bitsicht-web ansprechen. Namespaceübergreifend wird der Name entsprechend qualifiziert; die Cluster-DNS-Domain ist konfigurierbar. Service-DNS und öffentliche Internet-DNS-Zonen sind getrennte Ebenen. Eine erfolgreiche DNS-Antwort beweist noch keine erreichbare Anwendung.

Konfiguration und Speicher haben eigene Lebenszyklen.

Ein Namespace gliedert viele API-Ressourcen nach Namen und Zuständigkeit. Er hilft etwa, Labor und andere Anwendungen zu unterscheiden. Er ist keine vollständige Sicherheitsgrenze: Rollen, Netzwerkrichtlinien, Quoten und weitere Regeln müssen dafür passend eingerichtet werden. Clusterweite Ressourcen wie Nodes gehören keinem Namespace an.

Eine ConfigMap speichert gewöhnliche Konfiguration als Schlüssel-Wert-Daten. Ein Secret ist für sensible Daten vorgesehen und kann gezielt als Datei oder Umgebungsvariable bereitgestellt werden. Base64 in einem YAML-Feld ist nur eine Kodierung und lässt sich ohne Schlüssel zurückwandeln. Secrets werden nicht durch diese Kodierung verschlüsselt. Verschlüsselung im Speicher, RBAC-Zugriff, Schutz der API, Rotation und sichere Übergabe müssen eingerichtet sein. Ein Secret gehört ebenso wenig ins öffentliche Git-Repository wie ein Klartextpasswort.

Ein PersistentVolume (PV) beschreibt bereitgestellten Speicher im Cluster. Ein PersistentVolumeClaim (PVC) ist die Speicheranforderung eines Workloads. Eine StorageClass kann die dynamische Bereitstellung über einen passenden Treiber auslösen. Größe, Zugriffsmodus, Nodebindung und Rückgewinnungsrichtlinie bestimmen, was tatsächlich möglich ist. Ein lokales Volume wird nicht durch die API automatisch auf einen anderen Rechner kopiert.

emptyDir entsteht für einen Pod und kann Containerneustarts innerhalb dieses Pods überleben. Mit dem Ende des Pods geht sein Inhalt verloren. Im folgenden Beispiel dient es nur temporären Dateien. Persistente Anwendungsdaten würden eine gesonderte Speicherplanung benötigen. Weder PVC noch Snapshot ersetzt eine unabhängige, wiederherstellbare Datensicherung. Die Einführung in Linux-Serveradministration ordnet Backup und Beobachtung ein.

Ein Webserver mit zwei Instanzen und internem Service.

Die zwei Dateien verwenden die stabilen APIs apps/v1 für Deployment und v1 für Service. Sie gehören in ein eigenes Laborverzeichnis. Das vom NGINX-Projekt gepflegte Unprivileged-Image bedient statische Inhalte auf Port 8080 ohne Root. Sein Tag ist beweglich; für einen festgehaltenen Teststand ist der geprüfte Digest zu dokumentieren. Es gibt keine Secrets, keinen Host-Mount und keinen externen Service.

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: bitsicht-web
spec:
  replicas: 2
  # Selector und Pod-Labels müssen zusammenpassen.
  selector:
    matchLabels:
      app: bitsicht-web
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  template:
    metadata:
      labels:
        app: bitsicht-web
    spec:
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 101
        runAsGroup: 101
        fsGroup: 101
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: web
          image: nginxinc/nginx-unprivileged:stable-alpine
          ports:
            - name: http
              containerPort: 8080
          # Laborwerte, keine gemessene Kapazitätsempfehlung.
          resources:
            requests:
              cpu: 100m
              memory: 32Mi
            limits:
              cpu: 500m
              memory: 128Mi
          readinessProbe:
            httpGet:
              path: /
              port: http
            initialDelaySeconds: 2
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /
              port: http
            initialDelaySeconds: 10
            periodSeconds: 10
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: [ALL]
          volumeMounts:
            - name: temporary
              mountPath: /tmp
      # Temporär; keine persistenten Anwendungsdaten.
      volumes:
        - name: temporary
          emptyDir: {}

apiVersion und kind bestimmen API und Ressourcentyp; metadata.name benennt das Objekt. replicas: 2 fordert zwei Pods. Der Selector und die Labels in template.metadata passen exakt zusammen. template.spec beschreibt die Podvorlage, containers deren Container. Der benannte containerPort beschreibt den von der Anwendung verwendeten Port und gibt ihm den Namen http; er veröffentlicht keinen Port auf einem Host.

RollingUpdate erlaubt mit maxSurge: 1 vorübergehend einen zusätzlichen Pod und mit maxUnavailable: 0 keinen geplanten Ausfall einer verfügbaren Replik während des Updates. Das setzt Platz für den Zusatz-Pod und eine geeignete Bereitschaftsprüfung voraus. Es verhindert keine unvorhergesehenen Ausfälle und garantiert keine unterbrechungsfreien bestehenden Verbindungen.

requests nennt die Ressourcen, die der Scheduler für die Platzierung einplant: 100m entspricht 0,1 CPU, 32Mi 32 Mebibyte Arbeitsspeicher. limits begrenzt hier auf 0,5 CPU und 128 MiB. CPU kann bei Erreichen des Limits gedrosselt werden; eine Speicherüberschreitung kann zur Beendigung mit OOMKilled führen. Diese Laborwerte sind Beispielkonfiguration, keine gemessene Kapazitätsempfehlung. Mehr Repliken benötigen entsprechend mehr Ressourcen.

Die Readiness Probe prüft, ob der Pod Anfragen erhalten soll. Bei fehlender Bereitschaft wird er im gewöhnlichen Service-Routing nicht als bereites Ziel verwendet. Die Liveness Probe prüft dagegen, ob ein Container neu gestartet werden soll. Beide senden hier HTTP-Anfragen auf / an den benannten Port. initialDelaySeconds verzögert die erste Prüfung, periodSeconds bestimmt den Abstand. Eine Startup Probe wäre für langsam startende Anwendungen sinnvoll und würde die anderen Prüfungen bis zum erfolgreichen Start zurückhalten. Eine Abhängigkeit wie eine Datenbank sollte nicht unbedacht zum Liveness-Kriterium werden: Sonst entstehen Neustartschleifen bei einem externen Fehler.

automountServiceAccountToken: false verhindert den automatischen API-Token-Mount, den dieser Webserver nicht braucht. Der Pod läuft ausdrücklich mit UID/GID 101 und ohne Root; fsGroup ermöglicht den passenden Gruppenzugriff auf das temporäre Volume. RuntimeDefault fordert das Standard-Seccomp-Profil der Runtime an. Der Container erhält keine zusätzlichen Capabilities und darf seine Rechte nicht erhöhen. Sein Root-Dateisystem bleibt schreibgeschützt; emptyDir unter /tmp bietet den vom Unprivileged-Image benötigten temporären Schreibbereich. Das sind einzelne Schutzmaßnahmen, keine vollständige Sicherheitsabnahme.

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: bitsicht-web
spec:
  # Nur interner Zugang, kein externer Lastverteiler.
  type: ClusterIP
  selector:
    app: bitsicht-web
  ports:
    - name: http
      port: 80
      targetPort: http
      protocol: TCP

Der Service wählt mit app: bitsicht-web die Pods des Deployments. port: 80 ist der Serviceport, targetPort: http verweist auf den benannten Containerport 8080. protocol: TCP nennt das Transportprotokoll. ClusterIP hält den Zugang im Cluster. Für das lokale Betrachten lässt sich nach einem ausdrücklich eingerichteten Labor ein zeitlich begrenzter Port-Forward verwenden; ein öffentlicher LoadBalancer ist dafür unnötig.

Erst Kontext und Namespace, dann Zustand untersuchen.

kubectl ist der API-Client. Er verwendet die gewählte Verbindung aus seiner kubeconfig. Ein Labor darf ausschließlich einen vorher verifizierten eigenen Testcluster verwenden. Die folgenden Inspektionsbeispiele nehmen einen dort bereits eingerichteten Namespace bitsicht-lab an. Sie installieren keinen Cluster und legen keinen Namespace an.

kubectl config current-context
kubectl get namespaces
kubectl -n bitsicht-lab get deployments,replicasets,pods,services
kubectl -n bitsicht-lab describe deployment bitsicht-web
kubectl -n bitsicht-lab get endpointslices -l kubernetes.io/service-name=bitsicht-web
kubectl -n bitsicht-lab logs deployment/bitsicht-web --tail=50
kubectl -n bitsicht-lab get events --sort-by=.metadata.creationTimestamp
kubectl -n bitsicht-lab rollout status deployment/bitsicht-web

-n wählt den Namespace. get liest eine Übersicht; describe zeigt Details und zugehörige Ereignisse. -l filtert nach einem Label. logs liest Prozessausgaben und --tail begrenzt die Zeilenzahl. Der Deployment-Kurzaufruf zeigt nicht automatisch die Logs sämtlicher Repliken; für einen konkreten Fehler wählst du den betroffenen Pod. --previous kann den vorherigen beendeten Containerlauf sichtbar machen. get events sortiert hier nach Erstellungszeit; Events sind flüchtige Diagnosehinweise. rollout status beobachtet den Fortschritt einer Aktualisierung.

Simulierte Beispielbeobachtung: Zwei Pods stehen auf Running, aber READY zeigt jeweils 0/1. Das beweist laufende Container, jedoch keine erfolgreiche Readiness Probe. Prüfe Poddetails, Probeport, Pfad und Logs. Sind die Service-Endpoints nicht bereit, hilft das bloße Ändern der DNS-Konfiguration nicht.

Eine Schema- und Beziehungsprüfung lässt sich zunächst offline vornehmen. Ein offizielles OpenAPI-Schema prüft Felder und Typen; zusätzliche Prüfungen müssen Selector, Labels und Portreferenzen vergleichen. kubectl apply --dry-run=client -f … ist nicht automatisch vollständig offline, weil der Client für API-Erkennung oder Validierung einen Server kontaktieren kann. Eine serverseitige Trockenprüfung setzt einen ausdrücklich ausgewählten Testcluster voraus und durchläuft dessen API- und Zulassungsregeln, ohne die Ressource dauerhaft zu speichern.

Nach einer gesondert bewussten Bereitstellung in deinem eigenen Labor verbindet kubectl -n bitsicht-lab port-forward --address 127.0.0.1 service/bitsicht-web 8081:80 einen lokalen Loopbackport vorübergehend mit einem ausgewählten Pod hinter dem Service. Strg+C beendet die Weiterleitung. Sie ist ein Diagnoseweg und testet nicht den vollständigen externen Netzwerkpfad oder die Lastverteilung auf alle Repliken. In dieser Artikelproduktion wurden weder Manifeste an einen Cluster übermittelt noch Container gestartet; funktionierende Probes und Image-Laufzeit werden hier nicht als ausgeführt behauptet.

Skalieren und Aktualisieren lösen nur einen Teil des Betriebs.

Eine Änderung von replicas in der gewünschten Konfiguration fordert mehr oder weniger Pods. Eine Änderung von template, etwa ein geprüftes neues Image, erzeugt einen Rollout. Ein gewöhnlicher Deployment-Rollout eignet sich für austauschbare Instanzen; zustandsbehaftete Dienste brauchen zusätzliche Überlegungen zu Identität, Speicher und Datenkonsistenz. Ein Rollback des Deployments macht eine bereits erfolgte Datenbankmigration nicht rückgängig.

Der Scheduler berücksichtigt Requests, Nodebedingungen und Regeln wie Affinity und Taints/Tolerations. Zwei Repliken können ohne weitere Platzierungsregeln auf demselben Node landen. Eine einzelne Maschine, ein gemeinsamer Datenträger oder eine einzelne Control Plane bleiben mögliche Ausfallpunkte. Kubernetes garantiert deshalb nicht auf jeder Infrastruktur Hochverfügbarkeit. Auch Verteilung auf mehrere Nodes ersetzt keine ausreichend unabhängigen Ausfallbereiche und keine Datenwiederherstellung.

Zum sicheren Betrieb gehören API-Zugriff mit geringsten nötigen RBAC-Rechten, geschützte kubeconfig-Dateien, geprüfte Images, Pod-Sicherheitsregeln, zeitnahe Updates und kontrollierter Netzwerkverkehr. NetworkPolicies wirken nur mit einer Implementierung, die sie durchsetzt. Ein Namespace allein sperrt Netzwerkzugriffe nicht. Überwache verfügbare Repliken, Ressourcen und Anwendungsantworten; sichere Clusterkonfiguration und Anwendungsdaten nach ihren unterschiedlichen Anforderungen.

Bei KI-Diensten kommen GPU-Verfügbarkeit, passende Treiber und Device Plugins, große Modellartefakte sowie lange Startzeiten hinzu. Kubernetes kann die Bereitstellung koordinieren, erhöht aber nicht von selbst die Rechenleistung eines Modells. Für den Aufbau des Lernpfads bleiben Linux-Grundlagen, Rechte und SSH und der Serverbetrieb die nötige Basis.

Erkenne, welcher Teil des Systems zuständig ist.

Aufgabe 1: Beide Pods laufen. Der Service hat keine passenden Endpunkte. Was vergleichst du zuerst?

Vergleiche den Selector des Services mit den tatsächlichen Pod-Labels und prüfe anschließend die Readiness sowie die EndpointSlices. Im Beispiel muss überall app: bitsicht-web passen. Der Name des Deployments genügt nicht. Stimmen die Labels, aber die Pods sind nicht bereit, untersuchst du Probes und Anwendung. Eine neue Replica-Zahl repariert weder einen falschen Selector noch einen falschen Probeport.

Aufgabe 2: Zwei Repliken, ein Node und ein „emptyDir“: Ist die Anwendung gegen einen Rechnerausfall und Datenverlust geschützt?

Nein. Beide Repliken können auf dem einzigen Rechner ausfallen. Der Cluster kann ohne verfügbaren Ersatznode keine neuen Instanzen platzieren. emptyDir ist außerdem an den Pod gebunden und wird mit dessen Lebensende verworfen. Für wichtige Daten brauchst du passenden persistenten Speicher und Backups; für Verfügbarkeit unabhängige Ressourcen und eine passende Platzierungs- und Ausfallplanung. Die Replikazahl allein erfüllt diese Anforderungen nicht.

Quellen und fachlicher Stand.

Fachlich aktualisiert am . Die Beispiele verwenden stabile Kubernetes-APIs, keine Beta-Deployment-API. Die API-Entfernungen wurden gegen den offiziellen Migrationsleitfaden abgeglichen. Welche Features und Zulassungsregeln dein Cluster tatsächlich unterstützt, hängt von dessen Version und Einrichtung ab.