IDIAL Kubernetes Setup-Anleitung
| Version | Datum | Autor | Änderung |
|---|---|---|---|
| 1.0 | 25.03.2026 | Maximilian Wilke (BxC Security) | Erste Version |
Dieses Dokument beschreibt das formale Installations- und Deploymentverfahren für die IDIAL-Plattform auf einem Kubernetes-Cluster. Es umfasst die initiale Cluster-Einrichtung, die Installation der erforderlichen Infrastrukturkomponenten, das Deployment der IDIAL-Applikation, den Dienstzugriff, das erwartete Failover-Verhalten sowie Hinweise zur Fehlersuche.
Die Anleitung richtet sich an Administratoren, die für die Vorbereitung und den Betrieb der Ziel-Kubernetes-Umgebung verantwortlich sind. Alle Befehlsblöcke und Konfigurationsbeispiele sind exakt wie dargestellt auszuführen.
1. Allgemeines
1.1 Einleitung
IDIAL läuft auf einem Bare-Metal-Kubernetes-Cluster, bestehend aus einem Control-Plane-Knoten und zwei Worker-Knoten. Der Infrastruktur-Stack setzt sich wie folgt zusammen:
- containerd als Container-Laufzeitumgebung
- Flannel als CNI-Plugin (Pod-CIDR
10.244.0.0/16) - Longhorn für verteilten, replizierten persistenten Speicher
- MetalLB für die LoadBalancer-IP-Zuweisung auf Bare Metal
- nginx-ingress als einheitlicher TLS-Einstiegspunkt
2. Grundlegende Vorbereitung
Aktualisieren Sie zunächst den Paketindex und führen Sie ein Upgrade aller installierten Pakete auf jedem Knoten durch. Installieren Sie anschließend die Container-Laufzeitumgebung.
sudo apt update -y && sudo apt upgrade -y
sudo apt install -y containerd
Konfigurieren Sie containerd, indem Sie das erforderliche Konfigurationsverzeichnis anlegen und die Standardkonfigurationsdatei erzeugen.
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
Ändern Sie in /etc/containerd/config.toml den Wert von SystemdCgroup von false auf true, um die Container-Laufzeitumgebung mit der systemd-basierten Cgroup-Verwaltung von Kubernetes abzustimmen.
sudo vim /etc/containerd/config.toml
# Find: SystemdCgroup = false
# Change: SystemdCgroup = true
Laden Sie die für das Kubernetes-Netzwerk erforderlichen Kernelmodule.
sudo vim /etc/modules-load.d/k8s.conf
Fügen Sie folgenden Inhalt hinzu:
overlay
br_netfilter
Konfigurieren Sie die erforderlichen netzwerkbezogenen Kernelparameter.
sudo vim /etc/sysctl.conf
Fügen Sie folgende Zeilen hinzu oder kommentieren Sie diese ein:
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
Starten Sie den Knoten neu, um sicherzustellen, dass alle Konfigurationsänderungen und Kerneleinstellungen übernommen werden.
2.1 Installation der Kubernetes-Pakete
Installieren Sie die erforderlichen Voraussetzungspakete für den Zugriff auf das Kubernetes-Paket-Repository. Fügen Sie anschließend den Kubernetes-Signierschlüssel und das Repository hinzu, aktualisieren Sie den Paketindex und installieren Sie die Kubernetes-Knotenkomponenten. Dies muss auf allen Knoten durchgeführt werden.
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key \
| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \
https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /' \
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
2.2 Initialisierung der Control Plane
Initialisieren Sie die Kubernetes-Control-Plane auf dem Master-Knoten mit dem angegebenen Control-Plane-Endpunkt, Knotennamen und Pod-Netzwerk-CIDR.
sudo kubeadm init \
--control-plane-endpoint=<MASTER-IP-ADDRESS> \
--node-name k8s-idial-master-orange \
--pod-network-cidr=10.244.0.0/16
Konfigurieren Sie nach der Initialisierung den kubectl-Zugriff für den aktuellen Benutzer.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Installieren Sie das Flannel-CNI-Plugin, um die Pod-Kommunikation innerhalb des Clusters zu ermöglichen.
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Überprüfen Sie, ob alle System-Pods betriebsbereit sind.
kubectl get pods --all-namespaces
2.3 Beitritt der Worker-Knoten
Generieren Sie den Beitrittsbefehl für Worker-Knoten auf dem Master-Knoten.
kubeadm token create --print-join-command
Führen Sie die erzeugte Ausgabe auf jedem Worker-Knoten aus, um dem Cluster beizutreten.
sudo kubeadm join <MASTER-IP-ADDRESS>:6443 --token <TOKEN> \
--discovery-token-ca-cert-hash sha256:<HASH>
Überprüfen Sie nach dem Beitritt aller Worker-Knoten den Cluster-Knotenstatus vom Master-Knoten aus.
kubectl get nodes
Erwartete Ausgabe:

2.4 Vorbereitung der Worker-Knoten für Longhorn
Nur erforderlich, wenn Sie Longhorn mit Volume-Replikation für den Failover-Betrieb einsetzen möchten. Bei einem Single-Worker-Setup kann dieser Schritt übersprungen werden.
Installieren Sie die von Longhorn benötigten Pakete und aktivieren Sie den iSCSI-Daemon.
sudo apt-get install -y open-iscsi nfs-common
sudo systemctl enable --now iscsid
Um Konflikte zwischen multipathd und Longhorn-Blockgeräten zu vermeiden, wenden Sie die folgende Konfiguration an und starten Sie den Dienst neu.
cat << 'EOF' | sudo tee /etc/multipath.conf
defaults {
user_friendly_names yes
}
blacklist {
devnode "^sd[a-z0-9]+"
}
EOF
sudo systemctl restart multipathd
3. Infrastrukturkomponenten
3.1 Longhorn – Verteilter Speicher
Longhorn ist nur dann zu deployen, wenn Failover mit replizierten Volumes erforderlich ist. Andernfalls fahren Sie mit 3.2 MetalLB fort.
Deployen Sie Longhorn im Cluster.
kubectl apply -f \
https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/deploy/longhorn.yaml
# Wait until all Longhorn components are ready (~2–3 min)
kubectl wait --namespace longhorn-system \
--for=condition=ready pod \
--selector=app=longhorn-manager \
--timeout=300s
kubectl get pods -n longhorn-system
Passen Sie die Standard-Speichereinstellungen von Longhorn an, um Umgebungen mit kleineren Festplatten besser gerecht zu werden (optional).
# Reduce minimum free space from 25% to 10%
kubectl patch settings.longhorn.io storage-minimal-available-percentage \
-n longhorn-system --type=merge -p '{"value":"10"}'
# Reduce reserved storage per node from 30% to 10%
kubectl patch settings.longhorn.io storage-reserved-percentage-for-default-disk \
-n longhorn-system --type=merge -p '{"value":"10"}'
# Automatically delete pods on node failure to enable failover
kubectl patch settings.longhorn.io node-down-pod-deletion-policy \
-n longhorn-system --type=merge \
-p '{"value":"delete-both-statefulset-and-deployment-pod"}'
Die Longhorn-Weboberfläche kann optional lokal für Monitoring- und Administrationszwecke aufgerufen werden.
kubectl port-forward -n longhorn-system svc/longhorn-frontend 8080:80
3.2 MetalLB
Deployen Sie MetalLB, um in der Bare-Metal-Kubernetes-Umgebung LoadBalancer-Funktionalität bereitzustellen.
kubectl apply -f \
https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml
kubectl wait --namespace metallb-system \
--for=condition=ready pod \
--selector=app=metallb \
--timeout=120s
Wenden Sie die vordefinierte IP-Adresspool-Konfiguration an.
kubectl apply -f metallb/metallb-config.yaml
Der in metallb/metallb-config.yaml definierte IP-Bereich muss vor der Anwendung an die im Knotennetzwerk verfügbaren Adressen angepasst werden.
3.3 NGINX-Ingress-Controller
Deployen Sie den nginx-Ingress-Controller.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.3/deploy/static/provider/cloud/deploy.yaml
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=120s
# Verify external IP – must show an address from the MetalLB pool
kubectl get svc -n ingress-nginx ingress-nginx-controller
Für eine höhere Verfügbarkeit skalieren Sie den Controller auf zwei Replikate und erzwingen Sie mithilfe von Pod-Anti-Affinität eine knotenübergreifende Verteilung.
kubectl scale deployment ingress-nginx-controller -n ingress-nginx --replicas=2
kubectl patch deployment ingress-nginx-controller -n ingress-nginx --type=merge -p '{
"spec": {
"template": {
"spec": {
"affinity": {
"podAntiAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": [{
"labelSelector": {
"matchLabels": {"app.kubernetes.io/component": "controller"}
},
"topologyKey": "kubernetes.io/hostname"
}]
}
}
}
}
}
}'
4. Deployment von IDIAL
4.1 Anpassung der Konfigurationsdateien
Legen Sie die IDIAL-Image-Version fest (Pflichtschritt). Um die verfügbaren Image-Tags einzusehen, verwenden Sie folgenden Befehl:
curl -s -u <DOCKER_USERNAME>:<TOKEN> \
"https://hub.docker.com/v2/repositories/bxc2security/idial/tags/?page_size=25" \
| python3 -c "import sys,json; [print(t['name']) for t in json.load(sys.stdin)['results']]"
Geben Sie eine stabile Image-Version in 05-idial.yaml an:
image: docker.io/bxc2security/idial:<STABLE_VERSION>
Aktualisieren Sie die Anwendungsgeheimnisse in 02-app-secrets.yaml:
SECRET_KEYmuss auf einen sicheren Zufallswert gesetzt werden.PKCS8_PWmuss mit dem Passwort übereinstimmen, das bei der Zertifikatgenerierung verwendet wurde.
4.2 Erstellung von Namespace und Registry-Zugangsdaten
Erstellen Sie den Ziel-Namespace und anschließend das Docker-Registry-Secret, das für den Image-Pull erforderlich ist.
kubectl apply -f 00-namespace.yaml
kubectl create secret docker-registry registry-credentials \
--docker-server=https://index.docker.io/v1/ \
--docker-username=<DOCKER_USERNAME> \
--docker-password=<DOCKER_PASSWORD_OR_ACCESS_TOKEN> \
--docker-email=<EMAIL> \
-n idial
4.3 Erstellung des TLS-Secrets für den Ingress
Generieren Sie ein selbstsigniertes Wildcard-Zertifikat für *.company.local, erstellen Sie das Kubernetes-TLS-Secret und entfernen Sie anschließend die lokalen Zertifikatsdateien.
Sie können auch Ihr eigenes Zertifikat verwenden. Überspringen Sie in diesem Fall den openssl-Befehl und erstellen Sie das Secret direkt aus Ihren vorhandenen .crt- und .key-Dateien.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout idial-ingress.key \
-out idial-ingress.crt \
-subj "/CN=*.company.local/O=Company" \
-addext "subjectAltName=DNS:idial.company.local,DNS:idial-api.company.local,DNS:ua.company.local,DNS:db.company.local"
kubectl create secret tls idial-ingress-tls \
--cert=idial-ingress.crt \
--key=idial-ingress.key \
-n idial
rm idial-ingress.key idial-ingress.crt
4.4 Deployment aller Applikationskomponenten
Deployen Sie den vollständigen Applikations-Stack mithilfe der Kustomization im aktuellen Verzeichnis.
kubectl apply -k .
Überwachen Sie den Deployment-Fortschritt, bis alle Pods laufen und alle Persistent Volume Claims gebunden sind.
kubectl get pods -n idial -w
kubectl get pvc -n idial # All PVCs must be Bound
kubectl get ingress -n idial
4.5 DNS & Dienstzugriff
Erstellen Sie nach erfolgreichem Deployment A-Records, die auf die MetalLB-VIP verweisen. Beispiel:
| Hostname | IP |
|---|---|
idial.bxc.local | 10.10.10.230 |
idial-api.bxc.local | 10.10.10.230 |
ua.bxc.local | 10.10.10.230 |
Alternative – lokales Testen über die Hosts-Datei:
<METALLB-VIP> idial.company.local idial-api.company.local ua.company.local
- Linux / macOS:
/etc/hosts - Windows:
C:\Windows\System32\drivers\etc\hosts
4.6 Zugriff auf die Dienste
| Dienst | URL |
|---|---|
| IDIAL Web UI | https://idial.bxc.local |
| IDIAL REST API | https://idial-api.bxc.local |
| OPC UA Expert (VNC) | https://ua.bxc.local |
Um die MetalLB-Virtual-IP-Zuweisung zu überprüfen, führen Sie folgenden Befehl aus:
kubectl get svc -n ingress-nginx ingress-nginx-controller
5. Failover-Verhalten
Die Umgebung betreibt zwei Worker-Knoten mit Longhorn-Volume-Replikation und zwei Kopien pro Volume. Fällt ein Worker-Knoten aus, werden Workloads erwartet, automatisch auf dem verbleibenden Worker-Knoten neu zu starten.
Erwarteter Failover-Zeitplan:
| Phase | Dauer |
|---|---|
Knoten wechselt in NotReady | ~40 s |
| Pods werden evakuiert | ~5 min (Kubernetes-Standard) |
| Longhorn-Volumes werden neu verbunden | ~60 s |
| Pods starten auf Worker 2 | ~30 s |
| Gesamt | ~7 Minuten |
Failover-Test:
# Watch from the master while shutting down one node:
kubectl get pods -n idial -o wide -w
Manuelle Wiederherstellung, wenn Pods hängen bleiben:
# Force-delete stuck Terminating pods
kubectl delete pods -n idial --all --force --grace-period=0
# Release Longhorn volumes stuck on the failed node
kubectl get volumes.longhorn.io -n longhorn-system -o json | \
python3 -c "
import sys, json, subprocess
data = json.load(sys.stdin)
for v in data['items']:
if v['status'].get('currentNodeID') == 'k8s-idial-worker01-orange':
name = v['metadata']['name']
subprocess.run([
'kubectl', '-n', 'longhorn-system', 'patch', 'volume.longhorn.io', name,
'--type=merge', '--patch', '{\"spec\":{\"nodeID\":\"\",\"migrationNodeID\":\"\"}}'
])
"
6. Fehlerbehebung
Diagnosebefehle
# Pod details (e.g. for Pending or CrashLoop)
kubectl describe pod -n idial <POD_NAME>
# Application logs
kubectl logs -n idial deployment/idial
kubectl logs -n idial deployment/idial-web-backend
# Longhorn volume status
kubectl get volumes.longhorn.io -n longhorn-system
# Ingress controller logs
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller
# Events in the namespace
kubectl get events -n idial --sort-by='.lastTimestamp'
# MetalLB status
kubectl get ipaddresspool -n metallb-system
kubectl get l2advertisement -n metallb-system
Häufige Symptome
| Symptom | Wahrscheinliche Ursache | Lösung |
|---|---|---|
Pod Pending | Longhorn-Volume nicht bereit | kubectl get pods -n longhorn-system |
ImagePullBackOff | Registry-Zugangsdaten fehlen oder sind falsch | Schritt 4.2 wiederholen |
PVC Pending | Longhorn nicht bereit oder DiskPressure | kubectl get nodes.longhorn.io -n longhorn-system |
| Longhorn-Volume fehlerhaft | DiskPressure – nicht genug freier Speicher | storage-minimal-available-percentage auf 10 setzen |
CrashLoopBackOff (idial) | Falsches Image-Tag (latest ist defekt) | Stabiles Tag in 05-idial.yaml setzen |
Ingress EXTERNAL-IP: <pending> | MetalLB nicht installiert oder kein IP-Pool | Schritt 3.2 prüfen |
503 Service Unavailable | Backend-Pod nicht bereit | kubectl get pods -n idial |
502 Bad Gateway nach Failover | Pods auf Worker 2 noch nicht gestartet | Warten (~7 min) oder hängende Pods force-löschen |
Longhorn-Manager 1/2 | multipathd-Konflikt auf Worker | /etc/multipath.conf-Fix anwenden (Schritt 2.4) |
Volume hängt bei Attaching | Alter Pod hält Volume (Multi-Attach) | kubectl delete pod <POD> -n idial --force --grace-period=0 |
Nicht migrierte Dienste
Die folgenden Dienste aus dem Docker-Compose-Deployment sind nicht im Kubernetes-Setup enthalten:
| Dienst | Grund |
|---|---|
dockhand | Benötigt Docker-Socket – nicht verfügbar mit containerd |
status_check | Docker-spezifischer Pre-Flight-Check – in K8S nicht erforderlich |
finish-idial | Interaktiver Docker-Compose-Hinweis – in K8S nicht relevant |