Zum Inhalt

Pod Management 2

Ziel

In diesem Projekt geht es um fortgeschrittene Techniken zur Erstellung von Pods. Sie werden:

  • StatefulSets, (Cron-)Jobs und DaemonSets erstellen
  • Unterschiedliche Deployment-Strategien anwenden

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.
  • StatefulSets, DaemonSets und Jobs werden auch in der offiziellen Kubernetes-Dokumentation erklärt.

Aufgabe 1: StatefulSet

Aufgabe 1.1: StatefulSets skalieren

Erstellen Sie eine Datei statefulset-scaling.yaml mit dem folgenden Inhalt:

---
apiVersion: v1
kind: Service
metadata:
  name: db-headless
  labels:
    app: blog
    component: db
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None
  selector:
    app: blog
    component: db
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
  labels:
    app: blog
    component: db
spec:
  serviceName: db
  replicas: 1
  minReadySeconds: 10
  selector:
    matchLabels:
      app: blog
      component: db
  template:
    metadata:
      labels:
        app: blog
        component: db
    spec:
      containers:
      - name: mysql
        image: mysql:5
        env:
        - name: MYSQL_RANDOM_ROOT_PASSWORD
          value: "yes"
        - name: MYSQL_DATABASE
          value: wordpress
        - name: MYSQL_USER
          value: wordpress
        - name: MYSQL_PASSWORD
          value: "notthesecret"
        ports:
        - name: mysql
          containerPort: 3306
  • Deployen Sie das StatefulSet
  • Überprüfen Sie, ob das StatefulSet erfolgreich erstellt wurde
  • Lassen Sie sich das StatefulSet und den Pod anzeigen mit
kubectl get all
  • Lassen Sie dieses Terminal offen und beobachten Sie es bei den weiteren Schritten
watch kubectl get all
  • Skalieren Sie das StatefulSet auf 4 Pods
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl scale statefulset db --replicas=4
  • Löschen Sie einen oder mehrere Pods und beobachten Sie, wie Kubernetes die Pods wiederherstellt
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl delete pod db-3
kubectl delete pod db-1
  • Skalieren Sie das StatefulSet auf 2 Pods
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl scale statefulset db --replicas=2

Aufgabe 1.2: StatefulSets updaten

  • Skalieren Sie das StatefulSet aus der vorherigen Aufgabe wieder auf 4 Pods indem Sie die yaml-Datei bearbeiten und das Update durchführen
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f statefulset-scaling.yaml
  • Ändern Sie das Image des Containers auf mysql:8.3 und führen Sie ein Update des StatefulSets durch
  • Beachten Sie dabei, dass das Update der Pods sequentiell erfolgt

Aufgabe 1.3: DNS in StatefulSets

  • Starten Sie einen interaktiven Busybox-Pod
  • Führen Sie nslookup auf den Service db-headless aus
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

kubectl run -it --rm busybox --image=busybox --restart=Never -- sh
nslookup db-headless

  • Sie sollten eine Ausgabe ähnlich der folgenden erhalten:
Name:   db-headless.default.svc.cluster.local
Address: 10.42.129.48
Name:   db-headless.default.svc.cluster.local
Address: 10.42.129.219
Name:   db-headless.default.svc.cluster.local
Address: 10.42.128.250
Name:   db-headless.default.svc.cluster.local
Address: 10.42.129.126

Aufgabe 2: DaemonSets

  • Die offizielle Dokumentation zu DaemonSets finden Sie hier
  • DaemonSets sind eine spezielle Art von Controller, die Pods auf jedem Node im Cluster starten

Aufgabe 2.1: Skalierung und Scheduling von DaemonSets

  • Ein typisches Anwendungsbeispiel für DaemonSets ist das Starten eines Monitoring-Agents auf jedem Node im Cluster
  • Erstellen Sie eine Datei daemonset.yaml und fügen Sie das DaemonSet-Manifest hinzu:
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  labels:
    app: monitoring
    component: node-exporter
    exercise: daemonsets
spec:
  selector:
    matchLabels:
      app: monitoring
      component: node-exporter
  template:
    metadata:
      labels:
        app: monitoring
        component: node-exporter
    spec:
      containers:
      - name: node-exporter
        image: prom/node-exporter
        ports:
        - containerPort: 9100
  • Deployen Sie das DaemonSet
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f daemonset.yaml
  • Überprüfen Sie, ob das DaemonSet erfolgreich erstellt wurde
  • Lassen Sie sich das DaemonSet und die Pods anzeigen mit kubectl get all -o wide

Durch das Flag -o wide erhalten Sie zusätzliche Informationen zu den Pods, wie z.B. den Node, auf dem sie laufen. Damit können Sie überprüfen, ob das DaemonSet auf jedem Node im Cluster Pods erstellt hat.

  • Löschen Sie das DaemonSet
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl delete daemonset node-exporter

Aufgabe 3: Jobs (Optional)

Aufgabe 3.1: Einfacher Job

Erstellen Sie eine Datei job.yaml und fügen Sie das folgende Job-Manifest hinzu:

---
apiVersion: batch/v1
kind: Job
metadata:
  name: echo-hello
  labels:
    exercise: jobs
spec:
  template:
    spec:
      containers:
      - name: echo-hello
        image: alpine
        command: ["echo", "Hello"]
      restartPolicy: Never
  • Deployen Sie den Job
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f job.yaml
  • Untersuchen Sie den Job mit kubectl get jobs und kubectl describe job echo-hello
  • Untersuchen Sie den Pod, der vom Job erstellt wurde, mit kubectl get pods und kubectl describe pod echo-hello-<hash>
  • Untersuchen Sie die Logs des Pods mit kubectl logs echo-hello
  • Löschen Sie den Job
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl delete job echo-hello

Aufgabe 3.2: Parallelisierung von Jobs

Erstellen Sie eine Datei job-parallel.yaml und fügen Sie das folgende Job-Manifest hinzu:

---
apiVersion: batch/v1
kind: Job
metadata:
  name: echo-hello-parallel
  labels:
    exercise: jobs
spec:
  template:
    spec:
      containers:
      - name: echo-hello
        image: alpine
        command: ["echo", "Hello"]
      restartPolicy: Never
  • Erweitern Sie das Job-Manifest um parallelism: 2 und completions: 6
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
apiVersion: batch/v1
kind: Job
metadata:
  name: echo-hello-parallel
  labels:
    exercise: jobs
spec:
  parallelism: 2
  completions: 6
  template:
    spec:
      containers:
      - name: echo-hello
        image: alpine
        command: ["echo", "Hello"]
      restartPolicy: Never
  • Deployen Sie den Job
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f job-parallel.yaml
  • Beobachten Sie die vom Job erstellten Pods mit watch kubectl get pods
  • Untersuchen Sie den Job mit kubectl get jobs und kubectl describe job echo-hello-parallel
  • Untersuchen Sie die vom Job erstellten Pods mit kubectl get pods
  • Löschen Sie den Job
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl delete job echo-hello-parallel

Aufgabe 3.3: Umgang mit fehlgeschlagenen Jobs

  • Erstellen Sie eine Datei job-failing.yaml und fügen Sie das folgende Job-Manifest hinzu:
---
apiVersion: batch/v1
kind: Job
metadata:
  name: failing-job
  labels:
    exercise: jobs
spec:
  backoffLimit: 3
  template:
    spec:
      containers:
      - name: failing
        image: alpine
        command: ["sh", "-c", "echo failing && sleep 5 && exit 1"]
      restartPolicy: Never
  • Deployen Sie den Job
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f job-failing.yaml
  • Untersuchen Sie den Job mit kubectl get jobs und kubectl describe job failing-job
  • Beobachten Sie die vom Job erstellten Pods mit watch kubectl get pods
  • Sie sollten sehen, dass die Pods erstellt werden und nach 5 Sekunden fehlschlagen
  • Dies wird nur 3 Mal passieren, da dies das Backoff-Limit ist, das wir mit .spec.backoffLimit festgelegt haben
  • Fehlgeschlagene Pods, die mit dem Job verbunden sind, werden vom Job-Controller mit einer exponentiellen Backoff-Verzögerung (10s, 20s, 40s ...) erstellt, die auf sechs Minuten begrenzt ist
  • Löschen Sie den Job
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl delete job failing-job
  • Ändern Sie die restart policy des Jobs auf OnFailure und deployen Sie den Job erneut
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
apiVersion: batch/v1
kind: Job
metadata:
  name: failing-job
spec:
  backoffLimit: 3
  template:
    spec:
      containers:
      - name: failing
        image: alpine
        command: ["sh", "-c", "echo failing && sleep 5 && exit 1"]
      restartPolicy: OnFailure
  • Beobachten Sie die vom Job erstellten Pods mit watch kubectl get pods
  • Lassen Sie sich Details zum Job ausgeben
  • Wie unterscheidet sich das Verhalten von dem vorherigen Job?
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Sie können sehen, dass der Container nach einem Fehler neu gestartet wird
  • Der Container wird 3 Mal neu gestartet, da dies das Backoff-Limit ist, das wir mit .spec.backoffLimit festgelegt haben
  • Nach dem dritten Fehler wird der Job als fehlgeschlagen markiert und der Pod beendet
  • Löschen Sie den Job
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl delete job failing-job

Aufgabe 4: CronJobs (Optional)

Erstellen Sie eine Datei cronjob.yaml und fügen Sie das folgende CronJob-Manifest hinzu:

---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello-every-minute
  labels:
    exercise: jobs
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: alpine
            command: ["echo", "Hello"]
          restartPolicy: OnFailure
  • Deployen Sie den CronJob
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f cronjob.yaml
  • Untersuchen Sie den CronJob mit kubectl get cronjobs und kubectl describe cronjob hello-every-minute
  • Nach einer Minute wird der Controller einen Job und einen Pod erstellen
  • Untersuchen Sie den Job mit kubectl get jobs und kubectl describe job hello-every-minute-<hash>
  • Untersuchen Sie den Pod, der vom Job erstellt wurde, mit kubectl get pods
  • Löschen Sie den CronJob
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl delete cronjob hello-every-minute

Aufgabe 5: Deployment-Strategien (Optional)

  • Die offizielle Dokumentation zur rollingUpdate-Strategie finden Sie hier

Aufgabe 5.1: Erstellen und Untersuchen eines Deployments mit RollingUpdate-Strategie

  • Erstellen Sie eine Datei rolling.yaml und fügen Sie das folgende Deployment-Manifest hinzu:
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rolling-update
  labels:
    exercise: deployment-strategies
spec:
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
  replicas: 10
  selector:
    matchLabels:
      app: rolling
  template:
    metadata:
      labels:
        app: rolling
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
  • Deployen Sie das Deployment
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f rolling.yaml
  • Überprüfen Sie, ob das Deployment erfolgreich erstellt wurde
  • Lassen Sie sich das Deployment und die ReplicaSets anzeigen mit kubectl get all
  • Verändern Sie das Deployment, indem Sie das imagePullPolicy auf Always setzen
  • Beobachten Sie die Änderungen, die an den ReplicaSets vorgenommen werden

Aufgabe 5.2: Erstellen und Untersuchen eines Deployments mit Recreate-Strategie

  • Erstellen Sie eine Datei recreate.yaml und fügen Sie das folgende Deployment-Manifest hinzu:
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: recreate
  labels:
    exercise: deployment-strategies
spec:
  strategy:
    type: Recreate
  replicas: 10
  selector:
    matchLabels:
      app: recreate
  template:
    metadata:
      labels:
        app: recreate
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
  • Deployen Sie das Deployment
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
kubectl apply -f recreate.yaml
  • Überprüfen Sie, ob das Deployment erfolgreich erstellt wurde
  • Lassen Sie sich das Deployment und die ReplicaSets anzeigen mit kubectl get all
  • Verändern Sie das Deployment, indem Sie das imagePullPolicy auf Always setzen
  • Beobachten Sie die Änderungen, die an den ReplicaSets vorgenommen werden

Cleanup

  • Löschen Sie alle erstellten Ressourcen