8 Kubernetes Request Lifecycle

Dieses Kapitel beschreibt den vollständigen Ablauf einer CRUD-Operation in Kubernetes - von der Client-Anfrage bis zur Container-Ausführung. Am Beispiel einer Pod-Erstellung wird der Weg durch alle beteiligten Komponenten verfolgt.

8.1 Big Picture – Request Flow Sequenz

Das Sequenzdiagramm zeigt die chronologische Interaktion aller Komponenten während eines Pod-Creation-Requests. Gut zu erkennen ist hier das alle Komponenten via API Server miteinander kommunizieren.

8.2 Übersicht des Request-Flows

Phase Komponente Aktion
1. Authentication API Server Client-Identität validieren
2. Authorization API Server RBAC-Permissions prüfen
3. Admission API Server Admission Controllers ausführen
4. Validation API Server Resource-Spec validieren
5. Persistence API Server → etcd Objekt in etcd speichern
6. Watch/Reconciliation Controller Manager Gewünschten Zustand durchsetzen
7. Scheduling Scheduler Pod einem Node zuweisen
8. Node Assignment API Server → etcd Node-Assignment persistieren
9. Kubelet Pull Kubelet → API Server Assigned Pods abrufen
10. Runtime Execution Kubelet → Container Runtime Container starten
11. Status Reporting Kubelet → API Server Container/Pod-Status melden

Diagramm der Kommunikationsflüsse zwischen allen beteiligten Komponenten.

8.3 Detaillierter Ablauf

8.3.1 Phase 1: Client Request

kubectl create -f pod.yaml
# oder
helm install myapp ./chart

Request-Struktur:

8.3.2 Phase 2: API Server - Authentication & API Aggregation

Der API Server führt die Authentifizierung durch und routet Requests über die API Aggregation Layer:

API Aggregation Layer:

Authentifizierungstyp Verfahren Verwendung
Client Certificates X.509 Certificate im TLS-Handshake kubectl mit kubeconfig
Bearer Tokens HTTP Header Authorization: Bearer <token> Service Accounts, OIDC
Basic Auth HTTP Header Authorization: Basic <base64> Legacy (nicht empfohlen)
Bootstrap Tokens Spezielle Tokens für Node-Registrierung kubeadm
TLS Bootstrapping CSR-basierte Zertifikatserneuerung Kubelet Auto-Renewal

TLS Bootstrapping Ablauf:

  1. Kubelet startet mit Bootstrap-Token
  2. Erstellt Certificate Signing Request (CSR)
  3. CSR wird automatisch approved (oder manuell)
  4. Kubelet erhält signiertes Client-Zertifikat
  5. Automatic Certificate Rotation vor Ablauf

8.3.3 Phase 3: API Server - Authorization

Nach erfolgreicher Authentifizierung prüft der API Server die Berechtigung des Clients für die angeforderte Operation.

RBAC-Evaluation:

  1. Subject: Wer führt die Aktion aus? (User, Group, ServiceAccount)
  2. Verb: Was wird getan? (create, get, list, update, delete)
  3. Resource: Auf was wird zugegriffen? (pods, services, deployments)
  4. Namespace: In welchem Namespace? (default, kube-system, custom)

RBAC-Objekte:

# Beispiel: ClusterRole für Pod-Erstellung
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-creator
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create", "get", "list"]

RBAC-Fehlerbeispiel:

# HTTP 403 Response bei unzureichenden Permissions
status:
  code: 403
  message: "pods is forbidden: User 'dev' cannot create resource 'pods' in API group '' in the namespace 'default'"
  reason: "Forbidden"
  details:
    group: ""
    kind: "pods"
    name: "mypod"

8.3.4 Phase 4: API Server - Admission Control

Mit den validierten Berechtigungen durchläuft die Anfrage nun die Admission Controller Pipeline zur finalen Modifikation und Validierung.

Admission Controller Pipeline:

Diagramm der Admission Controller Pipeline mit Mutating und Validating Webhooks.

1. Mutating Admission Controllers: Modifizieren die Request

2. Dynamic Admission (Webhooks):

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionWebhook
metadata:
  name: pod-policy-webhook
webhooks:
- name: mutate.example.com
  admissionReviewVersions: ["v1", "v1beta1"]
  clientConfig:
    service:
      name: webhook-service
      namespace: webhook-system
      path: "/mutate"
  rules:
  - operations: ["CREATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]

3. Validating Admission Controllers:

Webhook-Ablauf:

  1. API Server sendet AdmissionReview an externes System
  2. Webhook analysiert Request und antwortet mit AdmissionResponse
  3. Bei Mutating Webhooks: Patches werden angewendet
  4. Bei Validating Webhooks: Allowed/Denied Entscheidung

8.3.5 Phase 5: API Server - Validation & Persistence

Nach erfolgreicher Admission Control validiert der API Server die finale Resource-Specification und persistiert das Objekt in etcd.

Schema-Validierung:

Detaillierter Ablauf der API Server Validierung und etcd-Persistierung.

Optimistic Concurrency Control (OCC):

apiVersion: v1
kind: Pod
metadata:
  name: mypod
  resourceVersion: "12345"  # etcd revision number
spec:
  containers: [...]

OCC-Ablauf:

  1. Create: Neue Ressource erhält initiale resourceVersion
  2. Read: Client liest Objekt mit aktueller resourceVersion
  3. Update: Client sendet Änderung mit bekannter resourceVersion
  4. Conflict Detection: API Server vergleicht mit aktueller Version in etcd
  5. Success/Failure: Update erfolgt nur bei übereinstimmender Version

etcd-Persistierung:

  1. Key Structure: /registry/{group}/{version}/{kind}/{namespace}/{name}

    /registry/pods/default/mypod
    /registry/deployments/kube-system/coredns
  2. Atomic Operations: Compare-And-Swap für Konsistenz

  3. Watch-Events: Änderungen an alle Watch-Clients propagieren

    {
      "type": "ADDED",
      "object": {...},
      "resourceVersion": "12346"
    }

8.3.6 Phase 6: Controller Manager - Reconciliation

Nach erfolgreicher Persistierung in etcd reagieren nun die Controller über ihre Watch-Mechanismen - eine eventbasierte Reaktion auf Watch-Streams vom API Server.

Watch-Mechanismus:

// Controller abonniert Watch-Events für spezifische Ressourcen
watchInterface, err := clientset.CoreV1().Pods(namespace).Watch(context.TODO(), metav1.ListOptions{})
for event := range watchInterface.ResultChan() {
    switch event.Type {
    case watch.Added:
        controller.handlePodAdded(event.Object.(*v1.Pod))
    case watch.Modified:
        controller.handlePodModified(event.Object.(*v1.Pod))
    case watch.Deleted:
        controller.handlePodDeleted(event.Object.(*v1.Pod))
    }
}

Controller Loop:

for {
    desired := getDesiredState()
    current := getCurrentState()
    if desired != current {
        reconcile(desired, current)
    }
    sleep(reconciliationInterval)
}

Diagramm der Controller Watch-Streams und Reconciliation Loops.

ReplicaSet Controller Beispiel:

  1. Gewünschte Pod-Anzahl aus ReplicaSet-Spec lesen
  2. Aktuelle Pod-Anzahl über API Server abfragen
  3. Fehlende Pods erstellen oder überschüssige löschen
  4. Pod-Templates mit Owner-References versehen

8.3.7 Phase 7: Scheduler - Pod Placement

Parallel zu den Controller-Aktionen reagiert der Scheduler eventbasiert auf Watch-Streams für ungeschedulte Pods (Phase Pending ohne nodeName).

Scheduler Watch-Pattern:

// Scheduler überwacht Pods ohne Node-Assignment
watchInterface := clientset.CoreV1().Pods("").Watch(context.TODO(), metav1.ListOptions{
    FieldSelector: "spec.nodeName=",  // Pods ohne nodeName
})

Scheduling-Algorithmus:

Detaillierter Ablauf des Scheduling-Algorithmus mit Filtering und Scoring.

  1. Filtering Phase - Ungeeignete Nodes ausschließen:

  2. Scoring Phase - Verbleibende Nodes bewerten:

  3. Binding - Besten Node auswählen und Pod zuweisen:

# Pod-Update mit Node-Assignment
spec:
  nodeName: worker-node-1
  schedulerName: default-scheduler
status:
  phase: Pending

8.3.8 Phase 8: Node Assignment

Mit der Scheduler-Entscheidung wird das Node-Assignment über den API Server in etcd persistiert, wodurch der zugewiesene Kubelet über seine Watch-Streams aktiviert wird.

Node-Assignment-Persistierung:

spec:
  nodeName: worker-node-1  # Scheduler-Entscheidung
status:
  phase: Pending
  conditions:
  - type: PodScheduled
    status: "True"
    reason: "Scheduled"

8.3.9 Phase 9: Kubelet - Work Pull & Execution

Der Kubelet auf dem zugewiesenen Node erkennt über seinen kontinuierlichen Pull-Mechanismus die neue Pod-Zuweisung und startet die Container-Orchestrierung.

Pull-Modell vs. Push-Modell:

Kubelet Control Loop:

  1. Sync Loop (jede Sekunde):

    assignedPods := apiserver.GetPodsAssignedToNode(nodeName)
    runningPods := kubelet.GetRunningPods()
    kubelet.SyncPods(assignedPods, runningPods)
  2. Pod Lifecycle Event Generator (PLEG):

Der Pod Lifecycle Event Generator (PLEG) erkennt Zustandsänderungen durch Container-Events und stellt sicher, dass der Kubelet umgehend auf Container-State-Transitions reagiert.

// PLEG überwacht Container-Runtime für State-Änderungen
for event := range runtime.GetContainerEvents() {
    switch event.Type {
    case ContainerStarted:
        kubelet.HandleContainerStarted(event.PodUID, event.ContainerID)
    case ContainerDied:
        kubelet.HandleContainerDied(event.PodUID, event.ContainerID)
    }
}
  1. cAdvisor Integration:

    // Sammelt Container-Metriken und Resource-Usage
    containerStats := cAdvisor.GetContainerStats(containerID)
    kubelet.UpdatePodStatus(podUID, containerStats)

Pod Sync Ablauf:

8.3.10 Phase 10: Container Runtime - Container Lifecycle

Nach der Kubelet-Vorbereitung übernimmt die Container Runtime die eigentliche Container-Orchestrierung mit dem Pod Sandbox Lifecycle.

Container Runtime Implementierungen:

Zustandsdiagramm: PodPending → PodRunning → PodSucceeded/Failed → Terminated

Pod Sandbox Lifecycle:

1. Pod Sandbox Creation (Pause Container):

# Pause Container wird zuerst gestartet
crictl runp pod-sandbox-config.json
# Output: sandbox-id (z.B. abc123...)

Pause Container Zweck:

2. Container Runtime Interface (CRI):

Image Pull:

crictl pull docker.io/nginx:latest

Container Creation im Pod Sandbox:

{
  "pod_sandbox_id": "abc123...",
  "config": {
    "image": {
      "image": "docker.io/nginx:latest"
    },
    "command": ["/docker-entrypoint.sh"],
    "args": ["nginx", "-g", "daemon off;"],
    "envs": [{"key": "PATH", "value": "/usr/local/sbin:/usr/local/bin"}],
    "mounts": [{"container_path": "/var/log", "host_path": "/var/log/pods/..."}],
    "linux": {
      "resources": {
        "cpu_quota": 100000,
        "memory_limit_in_bytes": 268435456
      },
      "security_context": {
        "run_as_user": {"value": 1000}
      }
    }
  }
}

3. Container Start Sequence:

8.3.11 Phase 11: Status Reporting

Mit laufenden Containern beginnt das kontinuierliche Status-Reporting des Kubelet an den API Server, wodurch der Request-Lifecycle in einen dauerhaften Monitoring-Zyklus übergeht.

Kubelet → API Server Status Updates:

status:
  phase: Running
  conditions:
  - type: Ready
    status: "True"
  - type: ContainersReady
    status: "True"
  containerStatuses:
  - name: nginx
    state:
      running:
        startedAt: "2024-01-01T10:00:00Z"
    ready: true
    restartCount: 0
    image: "docker.io/nginx:latest"

Kompletter Pod-Status-Lifecycle von Pending bis Running/Succeeded/Failed.

8.4 Performance-Charakteristika

Operation Typische Latenz Limiting Factor
API Request → etcd Write 10-50ms etcd Write Latency
Controller Reconciliation 100ms-5s Controller Sync Interval
Scheduler Decision 50-200ms Node Count, Constraints
Kubelet Pod Sync 1-10s Image Pull Time
Container Startup 100ms-30s Application Init Time

8.5 Fehlerbehandlung

Retry-Mechanismen:

Spezifische Fehlerszenarien:

8.5.1 Fehler-Matrix

Status Grund Ursache Maßnahme
OOMKilled Memory-Limit überschritten Container verbraucht mehr RAM als erlaubt Memory-Limits erhöhen, Application optimieren
CrashLoopBackOff Wiederholte Container-Exits Application-Fehler, Config-Probleme Logs prüfen, Dependencies validieren
ImagePullBackOff Image nicht verfügbar Registry-Auth, Netzwerk, falscher Tag Credentials prüfen, Image-Tag validieren
Pending Unschedulable Keine passenden Nodes Ressourcen hinzufügen, Constraints lockern
FailedMount Volume-Probleme PV nicht verfügbar, Permission-Fehler Storage-Klasse prüfen, Node-Permissions

8.5.2 OOMKilled (Out of Memory)

status:
  containerStatuses:
  - name: app
    state:
      terminated:
        reason: "OOMKilled"
        exitCode: 137
    restartCount: 3

Ablauf:

  1. Container überschreitet Memory-Limit
  2. Linux OOM-Killer terminiert Prozess mit SIGKILL
  3. Kubelet detektiert via PLEG den Container-Exit
  4. Restart Policy wird angewendet (Always, OnFailure, Never)
  5. Exponential Backoff bei wiederholten OOM-Kills

8.5.3 CrashLoopBackOff

status:
  containerStatuses:
  - name: app
    state:
      waiting:
        reason: "CrashLoopBackOff"
        message: "back-off 5m0s restarting failed container"
    restartCount: 10

Backoff-Strategie:

Restart Delays: 10s, 20s, 40s, 80s, 160s, 300s (max)

Ursachen:

8.5.4 ImagePullBackOff

status:
  containerStatuses:
  - name: app
    state:
      waiting:
        reason: "ImagePullBackOff"
        message: "Back-off pulling image 'invalid-registry/app:latest'"

Retry-Logic:

8.5.5 Pod Pending States

status:
  conditions:
  - type: PodScheduled
    status: "False"
    reason: "Unschedulable"
    message: "0/3 nodes are available: insufficient cpu"

Häufige Scheduling-Failures:

Monitoring-Points: