1. Einführung
1.1. Was ist Health Monitoring?
Unter Health Monitoring versteht man den Prozess der Überprüfung des Zustands einer Anwendung, um sicherzustellen, dass sie ordnungsgemäß und zuverlässig funktioniert. Dabei wird die Fähigkeit der Anwendung verfolgt, zu starten, auszuführen und den Datenverkehr effektiv zu verarbeiten. Health Monitoring ist ein Eckpfeiler des modernen Anwendungsmanagements, insbesondere in verteilten und Cloud-nativen Umgebungen.
1.2. Warum ist Health Monitoring wichtig?
-
Reliability (Zuverlässigkeit): Erkennt Probleme frühzeitig, um Ausfallzeiten zu verhindern.
-
Scalability (Skalierbarkeit): Stellt sicher, dass Systeme skaliert werden können, ohne dass kritische Komponenten beschädigt werden.
-
Integration: Funktioniert mit Tools wie Kubernetes, um die Wiederherstellung zu automatisieren und die Ressourcennutzung zu verbessern. → Probes
1.3. Eclipse MicroProfile Health
-
Spezifikation im MicroProfile-Ökosystem, bietet standardisierte Möglichkeit zur Implementierung von Health-Checks

2. Praxisbeispiel: SmallRye Health in Quarkus
2.1. Standard Health Checks ausprobieren
2.1.1. Maven-Projekt erstellen
Details
mvn io.quarkus.platform:quarkus-maven-plugin:3.18.1:create \
-DprojectGroupId==at.htlleonding \
-DprojectArtifactId==microprofile-health-demo \
-Dextensions=='smallrye-health' \
-DnoCode
cd microprofile-health-demo
2.1.2. Oder Extension zu bestehendem Projekt hinzufügen
Details
./mvnw quarkus:add-extension -Dextensions=='smallrye-health'
oder
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-health</artifactId>
</dependency>
2.1.4. Standard-Endpoints
Der Import der smallrye-health
Extension stellt direkt 3 REST-Endpunkte bereit:
Liveness (Live)
-
GET /q/health/live
-
Zeigt an, dass die Anwendung ausgeführt wird und kein kritischer Fehler aufgetreten ist, der einen Neustart erforderlich macht.
-
Falls die JVM oder der Container abstürzt oder sich in einem fehlerhaften Zustand befindet, schlägt der Liveness-Check fehl.
Readiness (Ready)
-
GET /q/health/ready
-
Zeigt an, dass die Anwendung zur Bearbeitung von Anfragen bereit und voll funktionsfähig ist.
-
Falls Quarkus eine Abhängigkeit erkennt (z. B. Datenbank oder externe API), kann es automatisch bestimmen, dass die Anwendung nicht bereit ist, falls diese Abhängigkeit nicht verfügbar ist.
Started
-
GET /q/health/started
-
Zeigt an, ob der vollständige Startprozess abgeschlossen ist.
-
Dies geschieht, nachdem alle Startup-Beans und StartupEvent-Listener vollständig ausgeführt wurden.
Mit GET /q/health werden alle Health-Checks angezeigt. Du kannst diese Endpoints nun ausprobieren. /q/health-ui zeigt eine UI zur Darstellung der Checks an.
|
Anzeige aller Checks:
Details
/q/health
{
"status": "UP", (1)
"checks": [ (2)
]
}
/q/health/live
{
"status": "UP", (1)
"checks": [ (2)
]
}
/q/health/ready
{
"status": "UP", (1)
"checks": [ (2)
]
}
/q/health/started
{
"status": "UP", (1)
"checks": [ (2)
]
}
-
status
gibt an, ob alle Health-Checks erfolgreich waren. -
checks
ist ein Array von individuellen Health-Checks (dazu später mehr).
2.2. Automatischer Health-Check für JDBC-Verbindungen
Wenn wir zu unserem Projekt eine JDBC-Datasource hinzufügen, wird automatisch ein Health Check (Readiness) erstellt, der die Verbindung zur Datenbank prüft. Hier wird dies mit einer PostgreSQL-DB demonstriert. |
Nach der Konfiguration einer JDBC-Datasource ist bei den Readiness-Checks ist nun auch sichtbar, ob die Datenbank-Verbindung aufrecht ist:
Details
/q/health/ready
{
"status": "UP",
"checks": [
{
"name": "Database connections health check",
"status": "UP",
"data": {
"<default>": "UP"
}
}
]
}
Stoppe nun die Datenbank und sieh dir die Readiness-Checks erneut an:
Details
/q/health/ready
{
"status": "DOWN",
"checks": [
{
"name": "Database connections health check",
"status": "DOWN",
"data": {
"<default>": "Unable to execute the validation check for the default DataSource: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections."
}
}
]
}
2.3. Eigene Health-Checks erstellen
Quarkus bietet die Möglichkeit, eigene Health-Checks zu erstellen.
Dabei implementiert deine Health-Check-Klasse das Interface HealthCheck
und trägt die @Liveness
, @Readiness
oder @Startup
Annotation - je nach dem welche Art von Health-Check gefordert ist.
2.3.1. Beispiel mit einer Readiness Health-Check Prozedur
package at.htlleonding.healthchecks;
import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Readiness;
import java.util.Random;
@Readiness (1)
@ApplicationScoped (2)
public class CustomReadinessCheck implements HealthCheck { (3)
@Override
public HealthCheckResponse call() { (4)
boolean b = new Random().nextBoolean(); (5)
if(b) {
return HealthCheckResponse.up("custom readiness check"); (6)
} else {
return HealthCheckResponse.down("custom readiness check"); (7)
}
}
}
-
Die Klasse soll einen Readiness-Check durchführen, daher die Annotation
@Readiness
. -
@ApplicationScoped
wird empfohlen, damit nur eine Instanz für alle Requests verwendet wird. -
Die Klasse implementiert das Interface
HealthCheck
-
call()
führt den Check durch und liefert einHealthCheckResponse
zurück -
Hier wird durch einen zufälligen Boolean das Ergebnis des Health-Checks simuliert. Dies ist dann in einem Produktivsystem durch eine sinnvolle Methode zu erstzen (z.B. Ist die DB-Verbindung aufrecht?)
-
Im positiven Falle wird
HealthCheckResponse.up
mit dem Namen des Health-Checks zurückgegeben. -
Im negativen Falle wird
HealthCheckResponse.down
mit dem Namen des Health-Checks zurückgegeben.
2.4. SmallRye Health für Probes in Kubernetes verwenden
Kubernetes nutzt Probes zur Überwachung von Containern: Liveness für Neustarts, Readiness für die Traffic-Steuerung und Startup für lange Startprozesse. SmallRye Health stellt dafür die Endpunkte/q/health/live
,/q/health/ready
und/q/health/started
bereit, die Kubernetes direkt nutzen kann, um den Zustand der Anwendung automatisch zu verwalten.
2.4.2. LeoCloud CLI & kubectl installieren
Siehe auch: LeoCloud User Manual
2.4.3. LeoCloud Dashboard starten
Siehe auch: LeoCloud User Manual > Dashboard
2.4.4. Credentials für GitHub Container Registry einpflegen (falls Image privat)
kubectl create secret docker-registry regcred \
--docker-server=ghcr.io \
--docker-username=YOUR_GITHUB_USERNAME \
--docker-password=YOUR_GITHUB_PAT \ (1)
--docker-email=YOUR_EMAIL
-
Hier ist ein Token erforderlich, die einfache Eingabe des Passwortes funktioniert nicht
2.4.5. Konfigurationsdateien erstellen
1. PVC, Service & Deployment für die PostgreSQL-Datenbank
Details
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: postgres
spec:
selector:
app: postgres
ports:
- protocol: TCP
port: 5432
targetPort: 5432
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:17-alpine
ports:
- containerPort: 5432
env:
- name: POSTGRES_USER
value: app
- name: POSTGRES_PASSWORD
value: app
- name: POSTGRES_DB
value: db
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres-storage
livenessProbe:
exec:
command:
- pg_isready
- -U
- app
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
exec:
command:
- pg_isready
- -U
- app
initialDelaySeconds: 3
periodSeconds: 5
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: postgres-pvc
2. Deployment & Service für die Quarkus-Applikation
Details
apiVersion: apps/v1
kind: Deployment
metadata:
name: quarkus-app
spec:
replicas: 4
selector:
matchLabels:
app: quarkus
template:
metadata:
labels:
app: quarkus
spec:
imagePullSecrets: (1)
- name: regcred
containers:
- name: quarkus-app
image: ghcr.io/2425-5bhif-wmc/01-referate-marksuus/mp-health-demo:latest (2)
ports:
- containerPort: 8080
env:
- name: QUARKUS_DATASOURCE_JDBC_URL
value: jdbc:postgresql://postgres:5432/db
- name: QUARKUS_DATASOURCE_USERNAME
value: app
- name: QUARKUS_DATASOURCE_PASSWORD
value: app
livenessProbe: (3)
httpGet:
path: /q/health/live
port: 8080
initialDelaySeconds: 5
periodSeconds: 2
timeoutSeconds: 2
failureThreshold: 3
readinessProbe: (4)
httpGet:
path: /q/health/ready
port: 8080
initialDelaySeconds: 3
periodSeconds: 2
timeoutSeconds: 2
failureThreshold: 3
startupProbe: (5)
httpGet:
path: /q/health/started
port: 8080
initialDelaySeconds: 0
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
---
apiVersion: v1
kind: Service
metadata:
name: quarkus-service
spec:
selector:
app: quarkus
ports:
- protocol: TCP
port: 8080
targetPort: 8080
type: NodePort
-
Dies wird bei nicht-öffentlichen Images benötigt. Hierbei greifen wir auf das vorhin angelegt Secret zu.
-
Image-Name mit deinem ersetzen.
-
Konfiguration der Liveness-Probe. Als Endpunkt wird
/q/health/live
verwendet. -
Konfiguration der Readiness-Probe. Als Endpunkt wird
/q/health/ready
verwendet. -
Konfiguration der Startup-Probe. Als Endpunkt wird
/q/health/started
verwendet.
initialDelaySeconds: Gibt an, wie lange Kubernetes nach dem Start des Containers wartet, bevor es die erste Probe durchführt. |
periodSeconds: Gibt an, wie oft (in Sekunden) Kubernetes die Probe wiederholt. |
timeoutSeconds: Gibt an, wie lange Kubernetes auf eine Antwort wartet, bevor die Probe als fehlgeschlagen gilt. |
failureThreshold: Gibt an, wie oft die Probe fehlschlagen darf, bis der Pod als gescheitert gilt. |
3. Ingress für die Quarkus-Applikation
Details
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: quarkus-ingress
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS, DELETE"
#nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: if200156.cloud.htl-leonding.ac.at (1)
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: quarkus-service
port:
number: 8080
-
Mit deinem Namespace ersetzen
2.5. Was macht Kubernetes nun, wenn eine der Probes fehlschlägt?
Probe | Prüft was? | Verhalten bei Fehlschlag |
---|---|---|
Liveness |
Läuft die App noch oder ist sie abgestürzt? |
Container wird als "unhealthy" markiert. Nach |
Readiness |
Kann die App Anfragen verarbeiten? |
Container bleibt am Leben, aber erhält keinen Traffic mehr. Sobald die Probe wieder erfolgreich ist, wird der Container wieder in den Load Balancer aufgenommen. |
Startup |
Ist die App noch im Startprozess? |
Solange die Startup Probe fehlschlägt, werden die Readiness- & Liveness-Probes ignoriert. Erst wenn die Startup Probe erfolgreich ist, starten die anderen Probes. |

3. Begriffsklärung
-
Cluster: Ein Cluster ist eine Gruppe von Nodes, die gemeinsam von Kubernetes verwaltet werden. Es stellt eine skalierbare Umgebung für die Bereitstellung, Verwaltung und Orchestrierung von Containern bereit (z.B.: LeoCloud, Azure AKS, Amazon EKS, Google GKE).
-
Service: Ein Service stellt eine stabile Netzwerkadresse für eine Gruppe von Pods bereit. Er ermöglicht die Kommunikation zwischen Diensten innerhalb des Clusters und optional den externen Zugriff.
-
Deployment: Ein Deployment verwaltet die Bereitstellung und Skalierung von Pods. Es sorgt für Ausfallsicherheit, automatische Neustarts und ermöglicht Rollbacks sowie Updates.
-
Ingress: Ein Ingress ist ein HTTP(S)-Router, der Anfragen basierend auf definierten Regeln an verschiedene Services weiterleitet. Er ermöglicht den externen Zugriff auf Anwendungen innerhalb des Clusters.
-
Pod: Ein Pod ist die kleinste ausführbare Einheit in Kubernetes und enthält einen oder mehrere Container, die gemeinsam Ressourcen wie Netzwerk und Speicher nutzen.
-
Container: Ein Container ist eine isolierte Laufzeitumgebung, die eine Anwendung mit allen benötigten Abhängigkeiten enthält. Kubernetes verwaltet Container innerhalb von Pods.
-
Node: Ein Node ist ein physischer oder virtueller Rechner im Kubernetes-Cluster, auf dem Pods ausgeführt werden. Jeder Node enthält eine Kubelet-Instanz, die die Pods steuert und mit dem Cluster kommuniziert.
-
Load Balancer: Der Load Balancer ist eine Kubernetes-Komponente, die den eingehenden Traffic auf mehrere laufende Pods verteilt. Dadurch werden die Last und Anfragen optimal verteilt, um eine hohe Verfügbarkeit und Skalierbarkeit sicherzustellen.