Die Aufgaben in diesem Abschnitt beziehen sich auf das erste Folienkapitel “Container Grundlagen”.
Starten Sie einen Docker-Willkommens-Container mit dem folgenden Befehl:
docker run -p 8080:80 docker/welcome-to-docker
Um zu bestätigen, dass der Container läuft besuchen Sie http://localhost:8080. Der Container kann nun gestoppt werden, indem der laufende Befehl mit CTRL + C abgebrochen wird.
Die Aufgaben in diesem Abschnitt beziehen sich auf das zweite Folienkapitel “Docker”.
Prüfen Sie ob eine Verbindung zu ihrem Virtual Private Server (VPS) hergestellt werden kann. Die Server-Adresse und das dazugehörige Passwort wurde ihnen zusammen mit dem Aufgabenmaterial zugeschickt.
ssh student@<server-domain>
Optional: Laden Sie ihren Public Key auf den Server um in Zukunft schneller darauf zugreifen zu können:
# Fall noch kein public key vorhanden ist
ssh-keygen
ssh-copy-id student@<server-domain>
Installieren Sie auf dem Server Docker mit dem Convenience Script.
https://docs.docker.com/engine/install/ubuntu/#install-using-the-convenience-script
Machen Sie Docker auch für Ihren lokalen Nutzer student verfügbar. Indem Sie ihn zu der docker Gruppe hinzufügen:
sudo groupadd docker
sudo usermod -aG docker $USER
# Ausloggen und wieder einloggen um die Gruppe zu erhalten
exit
ssh student@<server-domain>
Testen Sie die installierte Docker-Version mit:
docker version
Erstellen Sie einen Docker Kontext, der es erlaubt die Docker Befehle direkt von Ihrer lokalen Maschine auszuführen, ohne dabei extra den SSH Befehl aufrufen zu müssen:
docker context create student --docker "host=ssh://student@<server_domain>"
Lassen Sie sich eine Liste der verfügbaren Docker-Kontexte ausgeben und wechseln Sie auf den neuen Kontext:
docker context ls
docker context use student
Lassen Sie sich die Docker-Servers mit dem folgenden Befehl ausgeben:
docker version
Unterscheidet sich die Server-Version mit der Version ihrer CLI?
Starten Sie einen einfachen Caddy Server über den Befehl:
docker run -p 443:443 -p 80:80 caddy caddy file-server \
--listen ":443" \
--root /usr/share/caddy \
--domain <server_domain>
Verifizieren Sie, dass Sie über Ihren Browser die Domain https://<server_domain> erreichen können.
Stoppen Sie nun den Caddy Server indem Sie den Prozess mit CTRL + C beenden und wechseln Sie zurück auf den “default”-Kontext:
docker context use default
Die Aufgaben in diesem Abschnitt beziehen sich auf das dritte Folienkapitel “Images”.
Pullen Sie die folgenden Images und beantworten Sie die Fragen:
docker pull nginx:1.27-alpine
docker pull nginx:latest
docker pull python:3.12-slim
docker image ls um die Größen zu vergleichen.nginx:1.27-alpine mit docker image inspect. Welches Betriebssystem und welche Architektur hat das Image?nginx:1.27-alpine mit docker image history anzeigen. Wie viele Layers hat das Image?nginx:1.27-alpine und nginx:latest? Tipp: Vergleichen Sie die Ausgabe von docker image inspect beider Images (z.B. das Feld Os, Architecture, RootFS.Layers).In dieser Aufgabe üben Sie das Erstellen, Steuern und Aufräumen von Containern.
Starten Sie einen Nginx-Container im Hintergrund mit Port-Mapping und einem eigenen Namen:
docker run -d --name mein-nginx -p 8080:80 nginx:1.27-alpine
Öffnen Sie http://localhost:8080 im Browser um zu prüfen, dass der Container läuft.
Lassen Sie sich alle laufenden Container anzeigen (docker ps)
Öffnen Sie eine Shell im laufenden Container und erstellen Sie eine eigene index.html:
docker exec -it mein-nginx sh
echo "<h1>Hallo aus dem Container!</h1>" > /usr/share/nginx/html/index.html
exit
Laden Sie die Seite im Browser neu. Was sehen Sie?
Stoppen Sie den Container mit docker stop mein-nginx. Prüfen Sie mit docker ps -a, dass der Container im Zustand Exited ist.
Starten Sie den Container erneut mit docker start mein-nginx. Ist Ihre angepasste index.html noch da?
Löschen Sie den Container mit docker rm -f mein-nginx. Starten Sie einen neuen Container mit dem gleichen Image. Ist die Änderung an der index.html noch vorhanden? Warum (nicht)?
Räumen Sie auf: Entfernen Sie alle gestoppten Container mit docker container prune.
In dieser Aufgabe erstellen Sie ein eigenes Docker Image mit einem Dockerfile.
Erstellen Sie ein neues Verzeichnis und öffnen Sie es mit dem Editor ihrer Wahl.
Erstellen Sie eine Datei index.html mit beliebigem Inhalt, zum Beispiel:
<!DOCTYPE html>
<html>
<head><title>Meine Seite</title></head>
<body>
<h1>Willkommen auf meiner containerisierten Webseite!</h1>
<p>Erstellt mit Docker.</p>
</body>
</html>
Erstellen Sie ein Dockerfile mit folgendem Inhalt:
FROM nginx:1.27-alpine
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
Erstellen Sie eine .dockerignore-Datei, die die Datei Dockerfile und eventuell vorhandene .git-Verzeichnisse ausschließt.
Bauen Sie das Image und vergeben Sie einen Tag:
docker build -t meine-webseite:1.0 .
Starten Sie einen Container aus Ihrem neuen Image und prüfen Sie das Ergebnis im Browser:
docker run -d --name webseite -p 8080:80 meine-webseite:1.0
Ändern Sie nun die index.html und bauen Sie das Image erneut als meine-webseite:2.0. Beobachten Sie die Build-Ausgabe: Welche Layers werden aus dem Cache genommen und welche neu gebaut?
In dieser Aufgabe üben Sie den Umgang mit Image-Tags, einer lokalen Registry und dem Export/Import von Images.
Starten Sie eine lokale Docker-Registry:
docker run -d -p 5000:5000 --name registry \
-v registry_data:/var/lib/registry \
--restart always \
registry:2
Taggen Sie Ihr zuvor gebautes Image für die lokale Registry und pushen Sie es:
docker tag meine-webseite:1.0 localhost:5000/meine-webseite:1.0
docker push localhost:5000/meine-webseite:1.0
Löschen Sie das lokale Image und pullen Sie es wieder aus Ihrer lokalen Registry:
docker image rm localhost:5000/meine-webseite:1.0
docker pull localhost:5000/meine-webseite:1.0
Starten Sie einen Container daraus, um zu prüfen, dass alles funktioniert.
Exportieren Sie ein Image als .tar-Datei und importieren Sie es wieder:
docker save -o meine-webseite.tar meine-webseite:1.0
docker image rm meine-webseite:1.0
docker load -i meine-webseite.tar
docker image ls | grep meine-webseite
Prüfen Sie den Inhalt Ihrer lokalen Registry über die REST API:
curl http://localhost:5000/v2/_catalog
curl http://localhost:5000/v2/meine-webseite/tags/list
Bonus: Starten Sie die Docker-Registry auf ihrem Server. Können Sie einfach Images pushen?
In dieser Aufgabe erkunden Sie Kernel-Namespaces und Capabilities in der Praxis.
Starten Sie einen Container und inspizieren Sie die Prozessisolation:
docker run -d --name isolated nginx:1.27-alpine
Zeigen Sie die Prozesse innerhalb des Containers an:
docker exec isolated ps aux
Zeigen Sie nun die Host-PID des Container-Hauptprozesses:
docker inspect --format '{{.State.Pid}}' isolated
Vergleichen Sie: Im Container sieht nginx sich als PID 1, auf dem Host hat der Prozess eine andere PID.
Starten Sie einen Container mit Host-PID-Namespace und vergleichen Sie:
docker run --rm --pid=host busybox ps aux
Was fällt auf? Welche Prozesse sehen Sie jetzt?
Testen Sie Kernel-Capabilities. Starten Sie einen Container und versuchen Sie, den Hostnamen zu ändern:
docker run --rm -it busybox hostname neuer-name
Starten Sie nun den gleichen Container mit entfernter Capability:
docker run --rm --cap-add=SYS_ADMIN -it busybox hostname neuer-name
Starten Sie einen Container, bei dem alle Capabilities entfernt werden. Beobachten Sie, was noch funktioniert und was nicht:
docker run --rm --cap-drop=ALL -it busybox sh
# Versuchen Sie im Container:
# ping 8.8.8.8
# id
Frage: Warum funktioniert ping nicht? Welche Capability würden Sie hinzufügen müssen?
In dieser Aufgabe bauen Sie ein Image für mehrere CPU-Architekturen.
Prüfen Sie, welche Architektur Ihr Rechner hat:
uname -m
docker version --format '{{.Server.Arch}}'
Erstellen Sie einen neuen Buildx-Builder und aktivieren Sie ihn:
docker buildx create --name multiarch --driver docker-container --bootstrap --use
docker buildx inspect
Welche Plattformen werden unterstützt?
Erstellen Sie ein neues Verzeichnis mit einem einfachen Dockerfile:
mkdir ~/multi-arch-test && cd ~/multi-arch-test
FROM alpine:3.21
RUN echo "Gebaut auf: $(uname -m)" > /info.txt
CMD ["cat", "/info.txt"]
Bauen Sie das Image für Ihre lokale Plattform und testen Sie es:
docker buildx build -t multi-test:local --load .
docker run --rm multi-test:local
Bauen Sie jetzt das Image für eine andere Architektur (z.B. linux/arm64 wenn Sie auf amd64 sind) und laden Sie es lokal:
docker buildx build --platform linux/arm64 -t multi-test:arm64 --load .
docker run --rm multi-test:arm64
Die Aufgaben in diesem Abschnitt beziehen sich auf das vierte Folienkapitel “Docker Resources”.
In dieser Aufgabe speichern Sie Daten persistent und vergleichen verschiedene Mount-Typen.
Erstellen Sie ein Docker-Volume und prüfen Sie, dass es existiert:
docker volume create workshop_data
docker volume ls
docker volume inspect workshop_data
Starten Sie einen Container, der in dieses Volume schreibt:
docker run --rm --name writer \
-v workshop_data:/data \
alpine:3.21 sh -c "echo 'Hallo von $(date)' > /data/nachricht.txt && cat /data/nachricht.txt"
Starten Sie einen zweiten Container und lesen Sie die gleiche Datei aus dem gleichen Volume:
docker run --rm --name reader \
-v workshop_data:/data \
alpine:3.21 cat /data/nachricht.txt
Frage: Warum ist die Datei noch da, obwohl der erste Container mit --rm gelöscht wurde?
Vergleichen Sie nun mit einem Bind Mount. Erstellen Sie auf dem Host ein Arbeitsverzeichnis:
mkdir -p ~/docker-ressources/bind-demo
echo "Version 1" > ~/docker-ressources/bind-demo/info.txt
Starten Sie einen Container mit Bind Mount und lesen Sie die Datei:
docker run --rm \
-v $HOME/docker-ressources/bind-demo:/workspace \
alpine:3.21 cat /workspace/info.txt
Ändern Sie die Datei auf dem Host und prüfen Sie im Container erneut:
echo "Version 2" > ~/docker-ressources/bind-demo/info.txt
docker run --rm \
-v $HOME/docker-ressources/bind-demo:/workspace \
alpine:3.21 cat /workspace/info.txt
In dieser Aufgabe bauen Sie ein kleines Zwei-Container-Netzwerk aus Web-App und Client.
Erstellen Sie ein eigenes Netzwerk:
docker network create playground_net
docker network ls
Starten Sie den Hello-Docker-Container als internes Backend (ohne Port-Mapping auf den Host):
docker run -d --name hello-docker --network playground_net docker/welcome-to-docker
Prüfen Sie, welche Container im Netzwerk hängen:
docker network inspect playground_net
Starten Sie einen Test-Container im gleichen Netzwerk und prüfen Sie, ob das Backend über den Container-Namen erreichbar ist:
docker run --rm --network playground_net curlimages/curl "curl -I http://hello-docker"
Frage: Warum funktioniert der Aufruf über http://hello-docker ohne IP-Adresse?
In dieser Aufgabe sehen Sie, dass die CLI intern auch nur mit der Docker Engine API spricht.
Fragen Sie die Docker-Version direkt über die API ab:
curl --unix-socket /var/run/docker.sock http://localhost/version
Lassen Sie sich laufende Container per API anzeigen:
curl --unix-socket /var/run/docker.sock http://localhost/containers/json
Nutzen Sie die API-Antwort und suchen Sie in der Ausgabe die Namen hello-docker und caddy-proxy.
Starten Sie Portainer:
docker run -d -p 8000:8000 -p 9443:9443 \
--name portainer --restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
Öffnen Sie https://<server_domain>:9443 (oder lokal https://localhost:9443), erstellen Sie einen Admin-Account und verbinden Sie sich mit der lokalen Docker-Umgebung.
Erstellen Sie in Portainer einen neuen Container hello-ui mit Image docker/welcome-to-docker und Port-Mapping 8090:80.
Prüfen Sie anschließend in der Shell:
docker ps
curl -I http://localhost:8090
Stoppen Sie hello-ui einmal in Portainer und starten Sie ihn wieder über die CLI mit docker start hello-ui.
Die Aufgaben in diesem Abschnitt beziehen sich auf das sechste Folienkapitel “Docker Compose”.
In dieser Aufgabe lernen Sie, einen einfachen docker run Befehl in das Docker Compose Format zu übersetzen.
Schauen Sie sich das folgende “docker run”-Kommando an:
docker run --name compose-nginx -p 8080:80 -p 8443:443 -v /some/content:/usr/share/nginx/html:ro -d nginx:1.27-alpine
Erstellen Sie ein neues Verzeichnis:
mkdir -p ~/compose-nginx && cd ~/compose-nginx
Erstellen Sie eine docker-compose.yml Datei und übersetzen Sie das obige Kommando ins Compose-Format. Beachten Sie dabei:
--name Parameterportsvolumesimage Feld angegebenStarten Sie den Service mit:
docker-compose up -d
Prüfen Sie, dass der Container läuft:
docker-compose ps
curl http://localhost:8080
Stoppen Sie den Service:
docker-compose down
In dieser Aufgabe erstellen Sie ein Multi-Service Docker Compose Setup mit Wordpress, Datenbank und einem TLS-terminating Reverse Proxy auf ihrem Server:
Erstellen Sie ein neues Verzeichnis für das Projekt:
mkdir -p ~/wordpress-compose && cd ~/wordpress-compose
Erstellen Sie eine docker-compose.yml Datei mit dem folgenden Template:
version: '3.8'
services:
db:
image: mariadb:10.6.4-focal
command: '--default-authentication-plugin=mysql_native_password'
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
expose:
- 3306
- 33060
wordpress:
image: wordpress:latest
volumes:
- wp_data:/var/www/html
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
depends_on:
- db
volumes:
db_data:
wp_data:
Ergänzen Sie einen Reverse-Proxy Service mit Caddy, der Wordpress über HTTPS verfügbar macht. Der Reverse Proxy sollte:
Nutzen Sie als Referenz den folgenden “docker run”-Befehl:
docker run -p 80:80 -p 443:443 -v caddy_data:/data -v caddy_config:/config caddy caddy reverse-proxy --from <server_domain> --to wordpress:80
Sorgen Sie dafür, dass der Wordpress Service nicht direkt von außen zugegriffen werden kann. Nur der Reverse Proxy sollte direkt auf den Host-Ports erreichbar sein:
wordpress:
# ... rest of config ...
expose: # statt ports
- 80
Starten Sie alle Services:
docker-compose up -d
Prüfen Sie, dass alle Services laufen:
docker-compose ps
docker-compose logs -f caddy
Öffnen Sie im Browser Ihre Domain und prüfen Sie die HTTPS-Verbindung.
Stoppen und räumen Sie auf:
docker-compose down
In dieser Aufgabe erstellen Sie eine lokale Dev-Umgebung für eine einfache Python-Anwendung mit Docker Compose und Live-Reload.
Erstellen Sie ein neues Verzeichnis für das Projekt:
mkdir -p ~/python-dev-env && cd ~/python-dev-env
Erstellen Sie eine einfache Python-Anwendung mit dem Namen app.py:
from flask import Flask
import os
from datetime import datetime
app = Flask(__name__)
@app.route('/')
def hello():
return f'''
<!DOCTYPE html>
<html>
<head><title>Python Dev App</title></head>
<body>
<h1>Willkommen zur Python Dev-Umgebung!</h1>
<p>Aktuelle Zeit: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
<p>Hostname: {os.getenv('HOSTNAME', 'unknown')}</p>
</body>
</html>
'''
@app.route('/api/status')
def status():
return {'status': 'running', 'timestamp': datetime.now().isoformat()}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Erstellen Sie eine requirements.txt mit den notwendigen Abhängigkeiten:
Flask==3.0.0
Werkzeug==3.0.0
Erstellen Sie ein Dockerfile für die Entwicklung:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
CMD ["python", "app.py"]
Erstellen Sie ein docker-compose.yml File:
services:
app:
build: .
container_name: python-dev-app
ports:
- "5000:5000"
volumes:
- .:/app
environment:
- FLASK_ENV=development
- FLASK_DEBUG=1
- PYTHONUNBUFFERED=1
command: python -m flask run --host=0.0.0.0
Starten Sie die Anwendung mit Docker Compose:
docker-compose up
Öffnen Sie im Browser http://localhost:5000 und beobachten Sie die Ausgabe.
Ändern Sie nun die Datei app.py und ergänzen Sie einen neuen Endpoint. Beobachten Sie, dass die Anwendung aufgrund von Flask Debug-Mode automatisch neu startet, ohne den Container neu zu bauen.
@app.route('/hello/<name>')
def hello_name(name):
return f'<h1>Hallo {name}!</h1>'
Testen Sie den neuen Endpoint im Browser: http://localhost:5000/hello/Docker
Beobachten Sie die Logs der Anwendung mit:
docker-compose logs -f
Stoppen Sie die Services mit:
docker-compose down
Die Aufgaben in diesem Abschnitt beziehen sich auf das erste Folienkapitel “Grundlagen”.
In dieser Aufgabe lernen Sie ein Kubernetes-Cluster in Docker Desktop zu starten.
Öffnen Sie Docker Desktop.
Wählen Sie in der rechten Navigation den Punkt “Kubernetes” aus.
Klicken Sie auf “Create Cluster” (oder “Cluster erstellen”) und wählen Sie die folgenden Optionen an:
Cluster Type: kind
Advanced Settings
Öffnen Sie die Konsole und verifizieren Sie, dass es einen Kubernetes Kontext mit dem Namen “docker-desktop” gibt:
kubectl config get-contexts
Starten Sie den ersten Kubernetes Pod:
kubectl run nginx --image nginx
Verifizieren Sie das der Pod läuft:
kubectl get pods
# Pod sollte im Status running sein
kubectl describe pod nginx
# Letztes Event sollte sein "Started container nginx"
Leiten Sie den Port aus dem Pod auf ihr Hostsystem um:
kubectl port-forward pods/nginx 8080:80
Besuchen Sie die Seite und verifizieren Sie, dass der Pod erreicht werden kann.
Beenden Sie das Port-Forwarding mit CTRL + C.
In dieser Aufgabe untersuchen Sie die Nodes Ihres Kubernetes-Clusters und verstehen, wie die Control Plane den Cluster-Zustand verwaltet.
Zeigen Sie alle Nodes im Cluster an und prüfen Sie deren Status:
kubectl get nodes
Welche Nodes sehen Sie? Welche Rolle hat jeder Node (Control Plane, Worker)?
Zeigen Sie die Nodes mit zusätzlichen Informationen an (IP-Adresse, Kubernetes-Version):
kubectl get nodes -o wide
Untersuchen Sie einen Node im Detail:
kubectl describe node <node-name>
Beantworten Sie folgende Fragen anhand der Ausgabe:
Ready=True?Zeigen Sie alle Pods an, die auf dem Node laufen – einschließlich der System-Pods:
kubectl get pods --all-namespaces -o wide
Auf welchem Node läuft Ihr nginx-Pod aus Aufgabe 1.1?
Zeigen Sie nur die System-Pods im Namespace kube-system an:
kubectl get pods -n kube-system
Welche Kubernetes-Komponenten laufen dort als Pods? Erkennen Sie kube-apiserver, etcd oder coredns?
In dieser Aufgabe installieren Sie k3s auf Ihrem bekannten Virtual Private Server und binden den Cluster anschließend in Ihre lokale kubectl-Konfiguration ein.
Stellen Sie eine SSH-Verbindung zu Ihrem Server her:
ssh student@<server_domain>
Installieren Sie k3s mit dem offiziellen Convenience Script:
curl -sfL https://get.k3s.io | sh -
Das Script lädt k3s herunter, richtet einen systemd-Service ein und startet den Cluster automatisch.
Prüfen Sie, ob der k3s-Service läuft:
sudo systemctl status k3s
Verifizieren Sie, dass der Cluster bereit ist:
sudo kubectl get nodes
Der Node sollte nach kurzer Zeit den Status Ready haben.
k3s legt die Kubeconfig unter /etc/rancher/k3s/k3s.yaml ab. Da sie standardmäßig nur für root lesbar ist, kopieren Sie sie zunächst auf dem Server:
Kopieren Sie die Kubeconfig in Ihr Home-Verzeichnis und passen Sie die Berechtigungen an:
sudo cp /etc/rancher/k3s/k3s.yaml ~/k3s.yaml
sudo chown student:student ~/k3s.yaml
Verlassen Sie die SSH-Verbindung:
exit
Übertragen Sie die Datei auf Ihren lokalen Rechner:
scp student@<server_domain>:~/k3s.yaml ~/.kube/k3s.yaml
Die Kubeconfig enthält als Server-Adresse 127.0.0.1. Ersetzen Sie diesen Wert durch die echte Domain Ihres Servers:
sed -i 's/127.0.0.1/<server_domain>/g' ~/.kube/k3s.yaml
Fügen Sie die neue Kubeconfig Ihrer lokalen Konfiguration hinzu, indem Sie die Umgebungsvariable KUBECONFIG setzen:
export KUBECONFIG=~/.kube/config:~/.kube/k3s.yaml
Um diese Einstellung dauerhaft zu machen, tragen Sie die Zeile in Ihre Shell-Konfigurationsdatei (z. B. ~/.bashrc oder ~/.zshrc) ein.
Listen Sie alle verfügbaren Kontexte auf und wechseln Sie auf den k3s-Kontext:
kubectl config get-contexts
kubectl config use-context default
Der k3s-Kontext heißt standardmäßig default. Benennen Sie ihn zur besseren Übersicht um:
kubectl config rename-context default k3s-server
kubectl config use-context k3s-server
Verifizieren Sie die Verbindung zum Remote-Cluster:
kubectl get nodes
kubectl get pods --all-namespaces
Sie sollten den Node Ihres Servers und die k3s-Systemkomponenten sehen (u. a. traefik als Ingress-Controller und coredns).
Die Aufgaben in diesem Abschnitt beziehen sich auf das Folienkapitel “Kubernetes Objekte”.
In dieser Aufgabe lernen Sie die Kubernetes-Namespaces kennen und legen einen eigenen Namespace an.
Listen Sie alle Namespaces im Cluster auf:
kubectl get namespaces
Sie sollten mindestens vier vorinstallierte Namespaces sehen:
Zeigen Sie Detailinformationen zu einem einzelnen Namespace an:
kubectl describe namespace default
Erstellen Sie eine Datei my-namespace.yaml mit folgendem Inhalt:
apiVersion: v1
kind: Namespace
metadata:
name: training
Legen Sie den Namespace an:
kubectl apply -f my-namespace.yaml
Verifizieren Sie, dass der Namespace angelegt wurde und prüfen Sie seinen Status:
kubectl get namespaces
Starten Sie einen Pod im neuen Namespace:
kubectl run nginx-training --image nginx --namespace training
Zeigen Sie die Pods im Namespace training an:
kubectl get pods -n training
Führen Sie kubectl get pods ohne -n training aus. Ist der Pod sichtbar? Warum nicht?
Löschen Sie den Namespace inklusive aller darin enthaltenen Ressourcen:
kubectl delete namespace training
Beobachten Sie den Status mit kubectl get namespaces: Durchläuft der Namespace kurz den Zustand Terminating?
In dieser Aufgabe starten Sie einen Pod und öffnen eine interaktive Shell direkt im laufenden Container.
Die Begleitmaterialien enthalten die Datei objects-container-shell.yaml.
Legen Sie den Pod an:
kubectl apply -f objects-container-shell.yaml
Verifizieren Sie, dass der Pod läuft:
kubectl get pod shell-demo
Öffnen Sie eine interaktive Shell im Container:
kubectl exec -it shell-demo -- /bin/bash
Der -- trennt die kubectl-Argumente von dem Befehl, der im Container ausgeführt wird.
Erkunden Sie den Container von innen. Führen Sie folgende Befehle innerhalb der Shell aus:
ls /
cat /proc/mounts
Schreiben Sie eine eigene Startseite für nginx:
echo 'Hello shell demo' > /usr/share/nginx/html/index.html
Verlassen Sie die Shell:
exit
Leiten Sie den Port aus dem Pod auf ihr Hostsystem um:
kubectl port-forward pods/nginx 8080:80
Besuchen Sie die Seite und verifizieren Sie, dass Ihre Änderungen sichtbar sind.
Beenden Sie das Port-Forwarding mit CTRL + C.
Löschen Sie den Pod nach der Aufgabe:
kubectl delete pod shell-demo
In dieser Aufgabe lernen Sie, warum Readiness Probes wichtig sind, und fügen dem Pod slow-nginx eine solche Probe hinzu.
Die Begleitmaterialien enthalten die Datei objects-container-readiness.yaml. Der Pod simuliert mit sleep 30 eine langsame Startup-Phase.
Legen Sie den Pod ohne Readiness Probe an und beobachten Sie den Status:
kubectl apply -f objects-container-readiness.yaml
kubectl get pod slow-nginx --watch
Wird der Pod sofort als Running markiert? Ist nginx in dieser Zeit bereits erreichbar?
Beenden Sie das Watching mit CTRL + C.
Löschen Sie den Pod wieder:
kubectl delete pod slow-nginx
Öffnen Sie die Datei objects-container-readiness.yaml und ergänzen Sie eine httpGet Readiness Probe die auf den Pfad / mit dem Port 80 prüft.
Wenden Sie die aktualisierte Datei an und beobachten Sie den Status erneut:
kubectl apply -f objects-container-readiness.yaml
kubectl get pod slow-nginx --watch
READY von 0/1 auf 1/1?Beenden Sie das Watching mit CTRL + C.
Prüfen Sie die Readiness Probe in den Pod-Events:
kubectl describe pod slow-nginx
Sehen Sie Einträge wie Readiness probe failed? Nach wie vielen Sekunden wird der Pod als ready markiert?
Löschen Sie den Pod nach der Aufgabe:
kubectl delete pod slow-nginx
Die Aufgaben in diesem Abschnitt beziehen sich auf das Folienkapitel “Configuration”.
In dieser Aufgabe erstellen Sie eine ConfigMap auf verschiedene Arten und binden deren Daten in einen Pod ein.
Erstellen Sie eine ConfigMap mit einzelnen Schlüssel-Wert-Paaren:
kubectl create configmap special-config \
--from-literal=SPECIAL_LEVEL=very \
--from-literal=SPECIAL_TYPE=charm
Prüfen Sie den Inhalt der ConfigMap:
kubectl get configmap special-config -o yaml
Wie sind die Werte im data-Feld gespeichert?
Bearbeiten Sie die Pod-Datei config-env-pod.yaml und laden Sie alle Werte der Config-Map als Environment-Variables.
Legen Sie den Pod an:
kubectl apply -f config-env-pod.yaml
Prüfen Sie die Ausgabe des Pods:
kubectl logs config-env-pod
Sehen Sie SPECIAL_LEVEL=very und SPECIAL_TYPE=charm?
Löschen Sie den Pod:
kubectl delete pod config-env-pod
Bearbeiten Sie die Pod-Datei config-volume-pod.yaml und mounten Sie alle Werte der Config-Map als Volumes in das Verzeichnis /etc/config
Legen Sie den Pod an und prüfen Sie die Ausgabe:
kubectl apply -f config-volume-pod.yaml
kubectl logs config-volume-pod
Welche Dateien liegen im Verzeichnis /etc/config? Was ist der Inhalt von SPECIAL_LEVEL?
Löschen Sie den Pod:
kubectl delete pod config-volume-pod
Löschen Sie die ConfigMap:
kubectl delete configmap special-config
In dieser Aufgabe erstellen Sie ein Kubernetes Secret, binden es als Volume in einen Pod ein.
Die Begleitmaterialien enthalten die Datei secret-pod.yaml.
Erstellen Sie eine Datei die Passwort enthält:
echo "sec@re%t" > password.txt
Erstellen Sie ein Secret mit Benutzername und Passwort:
kubectl create secret generic test-secret \
--from-literal=username='my-app' \
--from-file=password=./password.txt
Prüfen Sie das angelegte Secret:
kubectl get secret test-secret
kubectl describe secret test-secret
Warum werden die Werte in describe nicht im Klartext angezeigt?
Öffnen Sie die Datei secret-pod.yaml und ergänzen Sie:
volumeMounts-Eintrag, der ein Volume namens secret-volume unter /etc/secret-volume als readOnly einbindet.volumes-Eintrag, der das Secret test-secret als Volume namens secret-volume bereitstellt.Legen Sie den Pod an:
kubectl apply -f secret-pod.yaml
Öffnen Sie eine Shell im laufenden Container und lesen Sie die Secret-Dateien aus:
kubectl exec -it secret-test-pod -- /bin/bash
ls /etc/secret-volume
cat /etc/secret-volume/username
cat /etc/secret-volume/password
Stimmen die Werte mit den Daten überein, die Sie beim Erstellen des Secrets angegeben haben?
Verlassen Sie die Shell und löschen Sie den Pod:
exit
kubectl delete pod secret-test-pod
Die Aufgaben in diesem Abschnitt beziehen sich auf das Folienkapitel “Volumes”.
In dieser Aufgabe lernen Sie die verfügbaren StorageClasses Ihres Clusters kennen und ermitteln, welche als Standard (default) festgelegt ist.
Listen Sie alle StorageClasses im Cluster auf:
kubectl get storageclass
Welche StorageClasses sehen Sie? Ist eine davon als (default) markiert?
Zeigen Sie die Details der Default-StorageClass an:
kubectl describe storageclass <name>
Beantworten Sie folgende Fragen anhand der Ausgabe:
Delete oder Retain?VolumeBindingMode? Was ist der Unterschied zwischen Immediate und WaitForFirstConsumer?AllowVolumeExpansion aktiviert?Zeigen Sie die StorageClass als YAML aus, um die vollständige Konfiguration zu sehen:
kubectl get storageclass <name> -o yaml
Welche Annotation kennzeichnet die StorageClass als Default?
In dieser Aufgabe erstellen Sie einen PVC, binden ihn in einen Pod ein und schreiben Daten auf das persistente Volume.
Die Begleitmaterialien enthalten die Datei volumes-pvc-pod.yaml mit einem PVC und einem Pod.
Wenden Sie die Datei an, um PVC und Pod anzulegen:
kubectl apply -f volumes-pvc-pod.yaml
Prüfen Sie den Status des PVC:
kubectl get pvc nginx-pvc
Welchen Status hat der PVC — Pending oder Bound? Welche StorageClass wurde automatisch zugewiesen?
Prüfen Sie, ob der Pod läuft:
kubectl get pod nginx-pvc-pod
Öffnen Sie eine Shell im Container und schreiben Sie eine eigene index.html auf das persistente Volume:
kubectl exec -it nginx-pvc-pod -- /bin/bash
echo '<h1>Hallo aus dem PVC!</h1>' > /usr/share/nginx/html/index.html
exit
Leiten Sie den Port weiter und rufen Sie die Seite auf:
kubectl port-forward pod/nginx-pvc-pod 8080:80
Besuchen Sie http://localhost:8080 und verifizieren Sie, dass Ihre Seite angezeigt wird.
Beenden Sie das Port-Forwarding mit CTRL + C.
Löschen Sie den Pod und starten Sie ihn erneut:
kubectl delete pod nginx-pvc-pod
kubectl apply -f volumes-pvc-pod.yaml
Leiten Sie den Port erneut weiter. Ist die index.html noch vorhanden? Was sagt das über den Lebenszyklus des PVC aus?
Beenden Sie das Port-Forwarding mit CTRL + C.
Zeigen Sie die Details des PVC an:
kubectl describe pvc nginx-pvc
Welches PersistentVolume wurde gebunden (Volume-Feld)? Zeigen Sie dieses PV ebenfalls an:
kubectl get pv
kubectl describe pv <name>
Löschen Sie Pod und PVC:
kubectl delete pod nginx-pvc-pod
kubectl delete pvc nginx-pvc
Beobachten Sie mit kubectl get pv, was mit dem PV passiert, nachdem der PVC gelöscht wurde. Was bewirkt die ReclaimPolicy?
Die Aufgaben in diesem Abschnitt beziehen sich auf das Folienkapitel “Workloads”.
Liste der verwendeten Images: nginx:1.27 nginx:1.26
In dieser Aufgabe erstellen Sie ein Deployment und untersuchen, welche Kubernetes-Objekte dabei automatisch angelegt werden.
Die Begleitmaterialien enthalten die Datei deployment-nginx.yaml mit einem Deployment.
Legen Sie das Deployment an:
kubectl apply -f deployment-nginx.yaml
Prüfen Sie den Status des Deployments:
kubectl get deployment nginx-deployment
Was bedeuten die Spalten READY, UP-TO-DATE und AVAILABLE?
Lassen Sie sich die Details des Deployments anzeigen:
kubectl describe deployment nginx-deployment
StrategyType, RollingUpdateStrategy (MaxSurge und MaxUnavailable)?Das Deployment erstellt automatisch ein ReplicaSet. Zeigen Sie es an:
kubectl get replicaset
Wie lautet der Name des ReplicaSets?
Zeigen Sie die Pods an, die das ReplicaSet verwaltet:
kubectl get pods
Wie viele Pods laufen? Was fällt Ihnen am Pod-Namen auf?
Untersuchen Sie einen der Pods im Detail:
kubectl describe pod <pod-name>
Controlled By? Was steht dort?Überprüfen Sie die Labels der Pods und vergleichen Sie sie mit dem Selektor des Deployments:
kubectl get pods --show-labels
Sehen Sie das Label pod-template-hash? Was ist dessen Zweck?
Skalieren Sie das Deployment auf 5 Replicas:
kubectl scale deployment nginx-deployment --replicas=5
Beobachten Sie, wie die neuen Pods hochfahren:
kubectl get pods --watch
Beenden Sie das Watching mit CTRL + C.
Hat sich das ReplicaSet verändert?
kubectl get replicaset
Löschen Sie einen der Pods manuell:
kubectl delete pod <pod-name>
Beobachten Sie sofort danach:
kubectl get pods --watch
Verifizieren Sie dass ein neuer Pod gestartet wurde.
Beenden Sie das Watching mit CTRL + C.
In dieser Aufgabe führen Sie ein Rolling Update durch, beobachten den Ablauf im Detail und machen das Update anschließend rückgängig.
Stellen Sie sicher, dass das Deployment nginx-deployment aus der vorherigen Aufgabe noch läuft und 3 Replicas hat:
kubectl scale deployment nginx-deployment --replicas=3
kubectl get deployment nginx-deployment
Setzen Sie eine Annotation, damit die Rollout-Historie aussagekräftig ist:
kubectl annotate deployment nginx-deployment \
kubernetes.io/change-cause="initiales Deployment mit nginx:1.27"
Lösen Sie ein Rolling Update auf nginx:1.29 aus:
kubectl set image deployment/nginx-deployment nginx=nginx:1.29
Beobachten Sie den Rollout-Status in Echtzeit:
kubectl rollout status deployment/nginx-deployment
Beobachten Sie gleichzeitig, wie die ReplicaSets wechseln:
kubectl get replicaset --watch
READY der beiden ReplicaSets während des Updates?Beenden Sie das Watching mit CTRL + C.
Annotieren Sie die neue Revision direkt im Anschluss:
kubectl annotate deployment nginx-deployment \
kubernetes.io/change-cause="Update auf nginx:1.29" --overwrite
Prüfen Sie die Rollout-Historie:
kubectl rollout history deployment/nginx-deployment
Wie viele Revisionen sehen Sie? Was steht unter CHANGE-CAUSE?
Zeigen Sie die Details einer einzelnen Revision an:
kubectl rollout history deployment/nginx-deployment --revision=1
kubectl rollout history deployment/nginx-deployment --revision=2
Welches Image wurde in Revision 1 verwendet, welches in Revision 2?
Lösen Sie nun absichtlich ein fehlerhaftes Update aus (ungültiges Image-Tag):
kubectl set image deployment/nginx-deployment nginx=nginx:does-not-exist
kubectl annotate deployment nginx-deployment \
kubernetes.io/change-cause="fehlerhaftes Update: nginx:does-not-exist" --overwrite
Beobachten Sie, was passiert:
kubectl rollout status deployment/nginx-deployment
Bricht der Befehl nach einiger Zeit ab? Was wird gemeldet?
Schauen Sie sich die Pods an:
kubectl get pods
Welche Pods haben den Status ImagePullBackOff oder ErrImagePull? Wie viele Pods aus der alten Version laufen noch?
Lassen Sie sich die Events des fehlerhaften Pods anzeigen:
kubectl describe pod <pod-name-des-fehlerhaften-pods>
Was steht unter Events?
Beenden Sie den rollout status-Befehl mit CTRL + C, falls er noch läuft.
Machen Sie das fehlerhafte Update rückgängig:
kubectl rollout undo deployment/nginx-deployment
Überprüfen Sie, dass alle Pods wieder laufen:
kubectl rollout status deployment/nginx-deployment
kubectl get pods
Auf welche Image-Version wurde zurückgerollt?
Prüfen Sie die Rollout-Historie erneut:
kubectl rollout history deployment/nginx-deployment
Wie viele Revisionen gibt es jetzt? Was fällt Ihnen an der Revisionsnummer auf?
Rollen Sie gezielt auf Revision 2 zurück (das funktionierende nginx:1.26-Update):
kubectl rollout undo deployment/nginx-deployment --to-revision=2
Verifizieren Sie das verwendete Image:
kubectl describe deployment nginx-deployment | grep Image
Löschen Sie das Deployment nach der Aufgabe:
kubectl delete deployment nginx-deployment
Beobachten Sie mit kubectl get replicaset und kubectl get pods: Werden alle abhängigen Objekte ebenfalls gelöscht?
In dieser Aufgabe untersuchen Sie die DaemonSets, die bereits auf Ihrem Cluster laufen, und verstehen deren Aufgabe.
Listen Sie alle DaemonSets clusterübergreifend auf:
kubectl get daemonset --all-namespaces
Untersuchen Sie das DaemonSet kube-proxy im Detail:
kubectl describe daemonset kube-proxy -n kube-system
/lib/modules, /run/xtables.lock, /var/lib/kube-proxy)? Warum braucht kube-proxy direkten Zugriff auf das Host-Dateisystem?Untersuchen Sie die Toleration von kube-proxy genauer:
kubectl get daemonset kube-proxy -n kube-system -o yaml | grep -A 5 tolerations
Sie sehen eine Toleration der Form op: Exists ohne einen Key. Was bewirkt das? Auf welchen Nodes darf kube-proxy damit laufen?
Untersuchen Sie das DaemonSet kindnet im Detail:
kubectl describe daemonset kindnet -n kube-system
kindnet ist das CNI-Plugin (Container Network Interface) von kind. Es stellt das Pod-Netzwerk bereit — ohne es könnten Pods nicht miteinander kommunizieren.
Zeigen Sie die Pods der DaemonSets an und prüfen Sie, auf welchen Nodes sie laufen:
kubectl get pods -n kube-system -o wide | grep -E 'kindnet|kube-proxy'
In dieser Aufgabe erstellen Sie einen einfachen Kubernetes Job, beobachten seinen Ablauf und verstehen, wie Jobs sich von dauerhaft laufenden Workloads unterscheiden.
Erstellen Sie den folgenden Job, der die Zahl Pi auf 2 Stellen ausgibt:
kubectl create job pi --image=busybox:1.28 -- sh -c "sleep 30; echo 3.14"
Beobachten Sie den Status des Jobs:
kubectl get job pi --watch
COMPLETIONS von 0/1 auf 1/1?DURATION)?Beenden Sie das Watching mit CTRL + C.
Zeigen Sie den Pod an, den der Job erstellt hat:
kubectl get pods
Welchen Status hat der Pod nach Abschluss? Was ist der Unterschied zu einem Pod, der von einem Deployment verwaltet wird?
Lesen Sie die Ausgabe des Jobs:
kubectl logs job/pi
Sehen Sie die Dezimalstellen von Pi?
Untersuchen Sie den abgeschlossenen Job im Detail:
kubectl describe job pi
Pods Statuses?Start Time und ein Completed At? Was ergibt sich daraus als Laufzeit?Erstellen Sie nun einen Job, der absichtlich fehlschlägt, und beobachten Sie das Retry-Verhalten.
Die Datei job-error.yaml finden Sie in den Begleitmaterialien.
kubectl create -f job-error.yaml
Beobachten Sie die Pods:
kubectl get pods --watch
Was passiert? Wie oft versucht Kubernetes den Job neu zu starten? Was bedeutet backoffLimit?
Beenden Sie das Watching mit CTRL + C.
kubectl describe job fail-job
Was steht unter Pods Statuses und Events?
Räumen Sie auf:
kubectl delete job pi
kubectl delete job fail-job
Was passiert mit den zugehörigen Pods beim Löschen des Jobs?
Die Aufgaben in diesem Abschnitt beziehen sich auf das Folienkapitel “Networking”.
In dieser Aufgabe erstellen Sie ein Deployment mit mehreren Replicas, exponieren es über einen ClusterIP-Service und untersuchen, wie Kubernetes den Traffic per Round-Robin auf die Pods verteilt.
Erstellen Sie einen neuen Namespace und wechseln Sie in diesen:
kubectl create namespace web
kubectl config set-context --current --namespace=web
Erstellen Sie ein Deployment mit 3 Replicas:
kubectl create deployment nginx-web --image=nginx:1.27 --replicas=3
Exponieren Sie das Deployment als ClusterIP-Service auf Port 80:
kubectl expose deployment nginx-web --port=80 --target-port=80 --name=nginx-svc
Zeigen Sie den erstellten Service an:
kubectl get service nginx-svc
CLUSTER-IP wurde vergeben?TYPE ist gesetzt?PORT(S))?Starten Sie einen temporären BusyBox-Pod im selben Namespace (web), um den Service von innen zu testen:
kubectl run debug --image=busybox:1.28 --rm -it -- sh
Führen Sie im Container folgende Befehle aus:
Lösen Sie den Service-Namen per DNS auf:
nslookup nginx-svc
nslookup zurück? Stimmt sie mit der CLUSTER-IP des Services überein?Verlassen Sie den Container mit exit.
Starten Sie nun einen BusyBox-Pod in einem anderen Namespace (default), um zu testen, wie der Service von außerhalb des Namespaces erreichbar ist:
kubectl run debug --image=busybox:1.28 --rm -it --namespace=default -- sh
Führen Sie im Container folgende Befehle aus:
Versuchen Sie, den Service nur über den kurzen Namen zu erreichen:
nslookup nginx-svc
Was passiert? Warum schlägt die Auflösung fehl?
Verwenden Sie stattdessen den vollständigen DNS-Namen (FQDN):
nslookup nginx-svc.web.svc.cluster.local
Was ist der Unterschied? Wann ist der kurze Name ausreichend?
Rufen Sie den Service über den FQDN auf:
wget -qO- http://nginx-svc.web.svc.cluster.local
Verlassen Sie den Container mit exit.
Räumen Sie auf:
kubectl delete deployment nginx-web -n web
kubectl delete service nginx-svc -n web
kubectl delete namespace web
kubectl config set-context --current --namespace=default
In dieser Aufgabe untersuchen Sie die EndpointSlices, die Kubernetes automatisch hinter einem Service anlegt. Sie beobachten, wie sich die Einträge bei Skalierung und Pod-Ausfall ändern.
Erstellen Sie ein Deployment und einen Service:
kubectl create deployment nginx-ep --image=nginx:1.27 --replicas=2
kubectl expose deployment nginx-ep --port=80 --name=nginx-ep-svc
Zeigen Sie alle EndpointSlices im default-Namespace an:
kubectl get endpointslices
Welchen Namen hat der EndpointSlice für nginx-ep-svc? Über welches Label ist er mit dem Service verknüpft?
Zeigen Sie den EndpointSlice im Detail an:
kubectl get endpointslice <endpointslice-name> -o yaml
Beantworten Sie folgende Fragen anhand der Ausgabe:
addressType ist gesetzt?addresses eingetragen?conditions hat jeder Endpunkt (ready, serving, terminating)?nodeName ersichtlich?Skalieren Sie das Deployment auf 4 Replicas:
kubectl scale deployment nginx-ep --replicas=4
Warten Sie kurz und zeigen Sie den EndpointSlice erneut an:
kubectl get endpointslice <endpointslice-name> -o yaml
Sind jetzt vier Endpunkte eingetragen?
Räumen Sie auf:
kubectl delete deployment nginx-ep
kubectl delete service nginx-ep-svc
In dieser Aufgabe installieren Sie die Gateway API CRDs sowie den NGINX Gateway Fabric Controller und überprüfen die Installation.
Installieren Sie die Standard-CRDs der Gateway API:
kubectl kustomize \
"https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.5.1" \
| kubectl apply -f -
Erstellen Sie den Namespace für den Gateway-Controller:
kubectl create namespace nginx-gateway
Installieren Sie die NGINX-Gateway-Fabric-eigenen CRDs:
kubectl apply --server-side \
-f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v2.5.1/deploy/crds.yaml
Deployen Sie den NGINX Gateway Fabric Controller:
kubectl apply \
-f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v2.5.1/deploy/default/deploy.yaml
Warten Sie, bis der Controller-Pod bereit ist:
kubectl wait --namespace nginx-gateway \
--for=condition=ready pod \
--selector=app.kubernetes.io/name=nginx-gateway-fabric \
--timeout=120s
Überprüfen Sie, dass die Gateway-API-CRDs installiert wurden:
Unter Linux
kubectl get crds | grep gateway.networking.k8s.io
Unter Windows
kubectl get crds | Select-String -Pattern gateway.networking.k8s.io
Welche CRDs sehen Sie? Erkennen Sie gateways, httproutes und gatewayclasses?
Überprüfen Sie, ob eine GatewayClass registriert wurde:
kubectl get gatewayclass
CONTROLLER ist eingetragen?In dieser Aufgabe deployen Sie zwei Versionen einer Anwendung (Blue und Green) und konfigurieren eine HTTPRoute, die den eingehenden Traffic im Verhältnis 30 % Blue zu 70 % Green aufteilt.
Die Begleitmaterialien enthalten die Dateien gateway-canary-prepare.yaml und gateway-canary.yaml.
Legen Sie die Backend-Ressourcen an:
kubectl apply -f gateway-canary-prepare.yaml
Überprüfen Sie, was angelegt wurde:
kubectl get deployments
kubectl get services
kubectl get configmaps
Schauen Sie sich beide Anwendungen einzeln an. Leiten Sie zunächst den blue-service weiter und öffnen Sie http://localhost:8081 im Browser:
kubectl port-forward svc/blue-service 8081:80
Beenden Sie das Port-Forwarding mit CTRL + C.
Leiten Sie anschließend den green-service weiter und öffnen Sie http://localhost:8082 im Browser:
kubectl port-forward svc/green-service 8082:80
Was unterscheidet die beiden Seiten optisch? Beenden Sie das Port-Forwarding mit CTRL + C.
Öffnen Sie die Datei gateway-canary.yaml. Sie enthält bereits ein Gateway-Objekt. Ergänzen Sie in der HTTPRoute die rules, sodass 30 % des Traffics an blue-service und 70 % an green-service gehen.
Wenden Sie die Datei an:
kubectl apply -f gateway-canary.yaml
Überprüfen Sie den Status des Gateways:
kubectl get gateway my-gateway
kubectl describe gateway my-gateway
Accepted und Programmed?Zeigen Sie die HTTPRoute an:
kubectl get httproute blue-green-route
kubectl describe httproute blue-green-route
Parents)?Besuchen Sie http://localhost:8085. Was ist das Ergebnis? Bleibt der Besuch der Seite bei jeden Aufruf gleich?
Senden Sie in mehrere Anfragen und beobachten Sie die Verteilung:
Unter Linux
for i in $(seq 1 20); do curl -s http://localhost:8085 | grep -o '<h1>.*</h1>'; done
Unter Windows
for ($i=1; $i -le 20; $i++) {
(Invoke-WebRequest "http://localhost:8085").Content -match '<h1>.*</h1>' | Out-Null
$matches[0]
}
Blue, wie oft Green?Räumen Sie auf:
kubectl delete -f gateway-canary.yaml
kubectl delete -f gateway-canary-prepare.yaml
Die Aufgaben in diesem Abschnitt beziehen sich auf das Folienkapitel “Helm”.
In dieser Aufgabe installieren Sie WordPress über ein Helm-Chart aus einem öffentlichen Repository, passen die Installation über Values an und führen anschließend ein Upgrade durch.
Fügen Sie das Bitnami-Repository hinzu und aktualisieren Sie den lokalen Index:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
Suchen Sie nach dem WordPress-Chart und zeigen Sie verfügbare Versionen an:
helm search repo wordpress
Welche Chart-Version und welche APP VERSION sind aktuell verfügbar?
Zeigen Sie die konfigurierbaren Standardwerte des Charts an:
Unter Linux
helm show values bitnami/wordpress | head -80
Unter Windows
helm show values bitnami/wordpress | Select-Object -First 80
Welche Werte steuern die Anzahl der Replicas und das Admin-Passwort?
Erstellen Sie einen Namespace für die Installation:
kubectl create namespace wordpress
Installieren Sie WordPress mit einem eigenen Blog-Titel und einem festen Admin-Passwort:
helm install my-wordpress bitnami/wordpress \
--namespace wordpress \
--set wordpressUsername=admin \
--set wordpressPassword=schulung123 \
--set blogName="Kubernetes Training" \
--set service.type=ClusterIP \
--set mariadb.auth.rootPassword=rootpass123
Beobachten Sie, wie die Pods hochfahren:
kubectl get pods -n wordpress --watch
Beenden Sie das Watching mit CTRL + C, sobald alle Pods im Status Running sind.
Zeigen Sie alle von Helm erzeugten Kubernetes-Ressourcen an:
kubectl get all -n wordpress
Zeigen Sie den Status und die Metadaten des Helm-Releases an:
helm status my-wordpress -n wordpress
helm list -n wordpress
STATUS?CHART- und APP VERSION wurde installiert?Leiten Sie den WordPress-Service auf Ihren Rechner weiter und öffnen Sie http://localhost:8080 im Browser:
kubectl port-forward svc/my-wordpress 8080:80 -n wordpress
Ist die WordPress-Startseite erreichbar? Beenden Sie das Port-Forwarding mit CTRL + C.
Führen Sie ein Upgrade durch und erhöhen Sie die Anzahl der WordPress-Replicas auf 2:
helm upgrade my-wordpress bitnami/wordpress \
--namespace wordpress \
--reuse-values \
--set replicaCount=2
Überprüfen Sie, dass zwei WordPress-Pods laufen:
kubectl get pods -n wordpress
Sehen Sie sich die Upgrade-Historie des Releases an:
helm history my-wordpress -n wordpress
Wie viele Revisionen gibt es? Welche DESCRIPTION hat Revision 1, welche Revision 2?
Machen Sie das Upgrade rückgängig und kehren Sie zu Revision 1 zurück:
helm rollback my-wordpress 1 -n wordpress
Überprüfen Sie den Status nach dem Rollback:
helm list -n wordpress
helm history my-wordpress -n wordpress
Auf wie viele Replicas läuft WordPress jetzt wieder?
Räumen Sie auf:
helm uninstall my-wordpress -n wordpress
kubectl delete namespace wordpress
Werden alle Ressourcen (Pods, Services, PVCs) gelöscht? Beobachten Sie mit kubectl get all -n wordpress.