Zum Inhalt

Pod Status

Ziel

In diesem Projekt geht es um fortgeschrittene Techniken rund um Pods. Sie werden:

  • Pod Status verstehen
  • mit Image Pull Secrets arbeiten
  • Pod-Probes definieren

Hilfsmittel

  • Versuchen Sie, die unten stehenden Aufgaben mit Hilfe der Folien und des Cheatsheets eigenständig zu lösen.
  • Sollten Sie dabei Probleme haben, finden Sie bei jeder Aufgabe einen ausklappbaren Block, in dem der Lösungsweg beschrieben wird.

Aufgabe 1: Pod Status verstehen

Aufgabe 1.1: Pods mit einem erfolgreich abgeschlossenen Container

  • Erstellen Sie eine YAML-Datei completed.yaml mit folgendem Inhalt:
---
apiVersion: v1
kind: Pod
metadata:
  name: completed
  labels:
    exercise: pod-status
spec:
  containers:
  - name: completed
    image: alpine
    command:
    - "true"
  restartPolicy: Never
  • Deployen Sie den Pod
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f completed.yaml
  • Untersuchen Sie den Pod-Status (.status.phase) und die Pod-Status Conditions (.status.conditions) mit kubectl get pod
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pod completed -o json | jq .status.phase
kubectl get pod completed -o json | jq .status.conditions

Der Pod hat vier verschiedene Zustände durchlaufen, die sind:

  • PodScheduled bedeutet, dass der Pod einem Node zugewiesen wurde.
  • Initialized bedeutet, dass alle initContainers erfolgreich abgeschlossen wurden.

Da wir keine initContainer haben, ist die Bedingung erfüllt.

  • ContainersReady bedeutet, dass alle Container im Pod bereit sind.
  • Ready bedeutet, dass der Pod Anfragen bearbeiten kann und allen passenden Services hinzugefügt werden sollten. Wie durch PodCompleted angezeigt, hat unser Pod den Ready-Zustand bereits verlassen, weil der Containerprozess beendet wurde und die RestartPolicy einen Neustart verhinderte.

Leider ist die Reihenfolge der Bedingungen, wie sie in kubectl get pod erscheinen, nicht immer korrekt.

Aufgabe 1.2: Pods mit fehlerhaftem Container mit Neustarts

  • Erstellen Sie eine YAML-Datei crashloopbackoff.yaml mit folgendem Inhalt:
---
apiVersion: v1
kind: Pod
metadata:
  name: crashloopbackoff
  labels:
    exercise: pod-status
spec:
  containers:
  - name: crashloopbackoff
    image: alpine
    command:
    - "false"
  restartPolicy: Always
  • Deployen Sie den Pod
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f crashloopbackoff.yaml
  • Untersuchen Sie den Pod-Status (.status.phase) und die Pod-Status Conditions (.status.conditions) mit kubectl get pod
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pod crashloopbackoff -o json | jq .status.phase
kubectl get pod crashloopbackoff -o json | jq .status.conditions

Der Pod hat folgende Zustände durchlaufen:

  • PodScheduled: Der Pod wurde erfolgreich geplant
  • Initialized: Der Pod hat den Zustand Initialized erreicht, da es keine initContainers gibt
  • ContainersReady: Der Pod ist nicht bereit, da der Containerprozess sofort beendet wird und damit auch der Container beendet wird
  • Ready: Der Pod ist nicht bereit, da die RestartPolicy und der beendete Containerprozess eine Endlosschleife verursachen

  • Lassen Sie sich den ContainerStatus (.status.containerStatuses) mit kubectl get pod ausgeben

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pod crashloopbackoff -o json | jq .status.containerStatuses

Der Container befindet sich in einem "CrashLoopBackOff"-Zustand, weil der Container mit einem Non-Zero-Exit-Code beendet wurde und die restartPolicy den Pod dazu zwingt, den Container neu zu starten, bis er in einem "Ready"-Zustand ist. Wir können auch sehen, ob Kubernetes den Container bereits mehrmals neu gestartet hat. Standardmäßig wird alle 5 Minuten ein Neustart ausgelöst.

Aufgabe 1.3: Pods mit einem fehlerhaften Container ohne Neustarts

  • Erstellen Sie eine YAML-Datei error.yaml mit folgendem Inhalt:
---
apiVersion: v1
kind: Pod
metadata:
  name: error
  labels:
    exercise: pod-status
spec:
  containers:
  - name: error
    image: alpine
    command:
    - "false"
  restartPolicy: Never
  • Deployen Sie den Pod
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f error.yaml
  • Untersuchen Sie den Pod-Status (.status.phase) und die Pod-Status Conditions (.status.conditions) mit kubectl get pod
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pod error -o json | jq .status.phase

Failed bedeutet, dass alle Container im Pod beendet wurden und mindestens ein Container mit einem Fehler beendet wurde. Das bedeutet, dass der Container entweder mit einem Non-Zero-Status beendet wurde oder vom System beendet wurde. In unserem Fall wurde der Containerbefehl false mit einem Non-Zero-Status beendet.

Der Pod hat folgende Zustände durchlaufen:

  • PodScheduled: Der Pod wurde erfolgreich geplant
  • Initialized: Der Pod hat den Zustand Initialized erreicht, da es keine initContainers gibt
  • ContainersReady: Der Pod ist nicht bereit, da der Containerprozess sofort beendet wird und damit auch der Container beendet wird
  • Ready: Der Pod ist nicht bereit, da der Containerprozess mit einem Non-Zero-Exit-Code beendet wurde

  • Lassen Sie sich den ContainerStatus (.status.containerStatuses) mit kubectl get pod ausgeben

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pod error -o json | jq .status.containerStatuses

Der Container befindet sich in einem terminated-Zustand, da der Prozess mit ExitCode 1 beendet wurde.

Aufgabe 1.4: Pods mit nicht existierendem Container-Image

  • Erstellen Sie eine YAML-Datei imagepullbackoff.yaml mit folgendem Inhalt:
---
apiVersion: v1
kind: Pod
metadata:
  name: imagepullbackoff
  labels:
    exercise: pod-status
spec:
  containers:
  - name: imagepullbackoff
    image: alpaine
  restartPolicy: Always
  • Deployen Sie den Pod
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f imagepullbackoff.yaml
  • Untersuchen Sie den Pod-Status (.status.phase) und die Pod-Status Conditions (.status.conditions) mit kubectl get pod
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pod imagepullbackoff -o json | jq .status.phase
kubectl get pod imagepullbackoff -o json | jq .status.conditions

Der Pod hat folgende Zustände durchlaufen:

  • Pending bedeutet, dass der Pod akzeptiert wurde, aber mindestens einer der Container nicht eingerichtet und bereit zum Ausführen ist. Dies beinhaltet die Zeit, die ein Pod darauf wartet, geplant zu werden, sowie die Zeit, die zum Herunterladen von Container-Images über das Netzwerk benötigt wird.

In unserem Fall schlägt das Herunterladen von Container-Images über das Netzwerk fehl.

Die Pod-Status Conditions sind die gleichen wie in Aufgabe 2, außer dass der Loopback-Grund "imagepullbackoff" anstelle von "crashloopbackoff" ist.

  • Lassen Sie sich den ContainerStatus (.status.containerStatuses) mit kubectl get pod ausgeben
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl get pod imagepullbackoff -o json | jq .status.containerStatuses

Der Container befindet sich in einem "waiting"-Zustand, weil das Container-Image nicht gefunden wurde, aber Kubernetes wird versuchen, das Image erneut herunter zu laden.

  • Führen Sie kubectl describe aus, um die Pod-Events zu untersuchen

Der Pod wurde geplant und Kubernetes hat versucht, das Image "alpaine" herunterzuladen. Das schlägt jedoch fehl, da das Repository nicht existiert. Der Status ErrImagePull bedeutet, dass das Herunterladen des Images fehlgeschlagen ist, was als nicht-permanenter Fehler interpretiert wird. Deshalb ändert sich der Pod-Status in "ImagePullBackOff", was bedeutet, dass Kubernetes versucht, das Image erneut herunterzuladen.

Aufgabe 2: Image Pull Secrets nutzen

Aufgabe 2.1: Pull Secret erstellen

  • Verwenden Sie kubectl create secret docker-registry um ein Pull Secret mit dem Namen registry.gitlab.com und den folgenden Einstellungen zu erstellen:
    • docker-server: registry.gitlab.com
    • docker-username: ${COREWIRE_TRAINING_REGISTRY_USER}
    • docker-password: ${COREWIRE_TRAINING_REGISTRY_TOKEN}
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl create secret docker-registry registry.gitlab.com \
--docker-server=registry.gitlab.com \
--docker-username=${COREWIRE_TRAINING_REGISTRY_USER} \
--docker-password=${COREWIRE_TRAINING_REGISTRY_TOKEN}
  • Untersuchen Sie das Secret mit
kubectl get secrets registry.gitlab.com -o yaml

Aufgabe 2.2: Pod erstellen

  • Erstellen Sie eine Datei pull-secret.yaml mit der Beschreibung eines Pods, der:
    • das imagePullSecrets registry.gitlab.com verwendet
    • das Container-Image registry.gitlab.com/corewire/hands-on/k8s/images/docker-demoapp:1.0.0 verwendet
    • den Port 5000 freigibt
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: v1
kind: Pod
metadata:
  name: pull-secret
spec:
  imagePullSecrets:
  - name: registry.gitlab.com
  containers:
  - name: demoapp
    image: registry.gitlab.com/corewire/hands-on/k8s/images/docker-demoapp:1.0.0
    ports:
    - name: web
      containerPort: 5000
  • Deployen Sie den Pod
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f pull-secret.yaml
  • Überprüfen Sie den Pod mit kubectl get pod und stellen Sie sicher, dass er sich im Zustand "Running" befindet
  • Lassen Sie sich den Pod mit kubectl get pod pull-secret -o yaml anzeigen und überprüfen Sie, ob das ImagePullSecret korrekt konfiguriert ist

Aufgabe 2.3: Zum Pod verbinden

  • Verbinden Sie sich mit dem Pod durch Port-Forwarding.
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl port-forward pods/pull-secret 8082:5000
  • Überprüfen Sie, ob die Demoapp erreichbar ist.

Aufgabe 3: Probes (Optional)

Aufgabe 3.1: Web Server Liveness Probe

Sie erhalten ein Basismanifest für ein Webserver-Deployment. Ihre Aufgabe ist es, eine Liveness-Probe hinzuzufügen, um den Webserver-Container neu zu starten, wenn er nicht mehr reagiert.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-server
  template:
    metadata:
      labels:
        app: web-server
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
  • Fügen Sie der Container-Spezifikation eine HTTP-Liveness-Probe hinzu, um den Root-Pfad / auf Port 80 zu überprüfen
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
  labels:
    exercise: probes
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-server
  template:
    metadata:
      labels:
        app: web-server
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
        livenessProbe:
          httpGet:
            path: /
            port: 80
  • Wenden Sie das aktualisierte Manifest an
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f web-server.yaml
  • Beobachten Sie das Deployment mit den Befehlen kubectl get pods und kubectl describe pod

Aufgabe 3.2: Datenbank-Readiness-Probe

Passen Sie das Basismanifest für ein MySQL-Datenbank-Deployment an, indem Sie eine Readiness-Probe hinzufügen. Diese Probe sollte sicherstellen, dass die Datenbank bereit ist, Verbindungen zu akzeptieren, bevor sie als bereit markiert wird.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-db
  labels:
    exercise: probes
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql-db
  template:
    metadata:
      labels:
        app: mysql-db
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password"
        ports:
        - containerPort: 3306
  • Fügen Sie der Container-Spezifikation eine Readiness-Probe hinzu, um die Datenbankbereitschaft mit dem Befehl mysqladmin ping zu überprüfen
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-db
  labels:
    exercise: probes
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql-db
  template:
    metadata:
      labels:
        app: mysql-db
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password"
        ports:
        - containerPort: 3306
        readinessProbe:
          exec:
            command:
            - mysqladmin
            - ping
  • Wenden Sie das aktualisierte Manifest an
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f mysql-db.yaml
  • Beobachten Sie das Deployment mit den Befehlen kubectl get pods und kubectl describe pod

Aufgabe 3.3: Exec Liveness Probe zur Selbstheilung

Das folgende Manifest startet eine benutzerdefinierte Anwendung basierend auf Alpine Linux. Es enthält eine exec Liveness-Probe, die das Vorhandensein einer bestimmten Datei überprüft. Wenn die Datei nicht vorhanden ist, sollte die Probe fehlschlagen und darauf hinweisen, dass die Anwendung in einem schlechten Zustand ist.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: custom-app
  labels:
    exercise: probes
spec:
  replicas: 1
  selector:
    matchLabels:
      app: custom-app
  template:
    metadata:
      labels:
        app: custom-app
    spec:
      containers:
      - name: alpine-app
        image: alpine:latest
        command: ["/bin/sh", "-c"]
        args: ["touch /tmp/alive; sleep 15; rm -f /tmp/alive; sleep 600"]
        livenessProbe:
          exec:
            command:
            - cat
            - /tmp/alive
          initialDelaySeconds: 5
          periodSeconds: 5
          failureThreshold: 3
  • Wenden Sie das Manifest an
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f custom-app.yaml
  • Überwachen Sie das Verhalten der Liveness-Probe mit dem Befehl kubectl get events -w
  • Untersuchen Sie den Status des Pods mit kubectl describe pod
  • Sie können auch mit den Eigenschaften initialDelaySeconds, periodSeconds und failureThreshold spielen, um das Verhalten der Liveness-Probe besser zu verstehen

Aufgabe 3.4: Redis TCP Liveness Probe

  • Passen Sie folgendes Basismanifest für ein Redis-Deployment an. Ihre Aufgabe ist es, eine TCP-Liveness-Probe hinzuzufügen, um sicherzustellen, dass der Redis-Server reagiert.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-server
  labels:
    app: redis
    exercise: probes
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:alpine
        ports:
        - containerPort: 6379
  • Fügen Sie der Container-Spezifikation eine TCP-Liveness-Probe hinzu, um Port 6379 zu überprüfen
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-server
  labels:
    app: redis
    exercise: probes
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:alpine
        ports:
        - containerPort: 6379
    livenessProbe:
      tcpSocket:
        port: 6379
      initialDelaySeconds: 15
      periodSeconds: 20
  • Wenden Sie das aktualisierte Manifest an
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f redis-deployment.yaml
  • Beobachten Sie das Deployment mit den Befehlen kubectl get pods und kubectl describe pod

Aufgabe 3.5: Startup Probes

Das Kubelet verwendet Startup-Probes, um zu wissen, wann eine Container-Anwendung gestartet ist. Wenn eine solche Probe konfiguriert ist, starten Liveness- und Readiness-Probes erst, wenn die Startup-Probe erfolgreich ist. Das stellt sicher, dass diese Probes nicht mit dem Anwendungsstart interferieren. Dies kann verwendet werden, um Liveness-Checks auf langsam startenden Containern zu übernehmen, um zu verhindern, dass sie vom Kubelet neugestartet werden, bevor sie vollständig gestartet sind.

  • Sie erhalten ein Basismanifest für ein Deployment, das eine Anwendung startet, die 15 Sekunden benötigt, um vollständig zu starten
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: slow-startup-app
  labels:
    exercise: probes
spec:
  replicas: 1
  selector:
    matchLabels:
      app: slow-startup-app
  template:
    metadata:
      labels:
        app: slow-startup-app
    spec:
      containers:
      - name: alpine-app
        image: alpine:latest
        command: ["/bin/sh", "-c"]
        args: ["sleep 15; touch /tmp/alive; sleep infinity"]
        livenessProbe:
          exec:
            command:
            - cat
            - /tmp/alive
          initialDelaySeconds: 1
          periodSeconds: 5
          failureThreshold: 2
        readinessProbe:
          exec:
            command:
            - cat
            - /tmp/alive
          initialDelaySeconds: 1
          periodSeconds: 2
          failureThreshold: 5
  • Wenden Sie das gegebenen Manifest an
  • Beobachten Sie das Verhalten des Containers mit den Befehlen kubectl get events -w und kubectl describe pod

Sie sollten sehen, dass der Container neu gestartet wird, wenn die Liveness- und Readiness-Probes fehlschlagen, bevor die Startup-Probe erfolgreich ist.

  • Fügen Sie der Container-Spezifikation eine Startup-Probe hinzu, um das Vorhandensein der Datei /tmp/alive zu überprüfen. Konfigurieren Sie die Probe mit:
    • initialDelaySeconds: 10
    • periodSeconds: 5
    • failureThreshold: 30
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: slow-startup-app
  labels:
    exercise: probes
spec:
  replicas: 1
  selector:
    matchLabels:
      app: slow-startup-app
  template:
    metadata:
      labels:
        app: slow-startup-app
    spec:
      containers:
      - name: alpine-app
        image: alpine:latest
        command: ["/bin/sh", "-c"]
        args: ["sleep 15; touch /tmp/alive; sleep infinity"]
        livenessProbe:
          exec:
            command:
            - cat
            - /tmp/alive
          initialDelaySeconds: 1
          periodSeconds: 5
          failureThreshold: 2
        readinessProbe:
          exec:
            command:
            - cat
            - /tmp/alive
          initialDelaySeconds: 1
          periodSeconds: 2
          failureThreshold: 5
        startupProbe:
          exec:
            command:
            - cat
            - /tmp/alive
          initialDelaySeconds: 10
          periodSeconds: 5
          failureThreshold: 30
  • Wenden Sie das aktualisierte Manifest an
  • Beobachten Sie das Verhalten des Containers mit den Befehlen kubectl get events -w und kubectl describe pod

Cleanup

  • Löschen Sie alle Objekte die Sie erstellt haben mit kubectl delete