diff --git a/diagrams/storage_flow.dot b/diagrams/storage_flow.dot new file mode 100644 index 0000000..b1fcde8 --- /dev/null +++ b/diagrams/storage_flow.dot @@ -0,0 +1,226 @@ +digraph storage_flow { + rankdir=LR; + graph [ + fontname="Helvetica Neue", + fontsize=16, + pad=1.2, + nodesep=0.45, + ranksep=1.6, + bgcolor="#f0f4f8", + label="ExpertFab – Speicherfluss & HA-Analyse", + labelloc=t, + labeljust=c, + splines=polyline, + compound=true, + newrank=true, + ]; + node [fontname="Helvetica Neue", fontsize=11, shape=box, style="filled,rounded", margin="0.15,0.10"]; + edge [fontname="Helvetica Neue", fontsize=10, arrowsize=0.8]; + + /* ───────────────────────────────────────────── + SCHICHT 1 – APPLIKATIONEN + ───────────────────────────────────────────── */ + subgraph cluster_apps { + label=<① APPLIKATIONEN
(K3s Pods)>; + style=filled; bgcolor="#e3eef7"; color="#2980b9"; penwidth=2; fontcolor="#1a5276"; + + subgraph cluster_erpnext { + label="ns: erpnext"; style=filled; bgcolor="#d6eaf8"; color="#5dade2"; + + gui [label=<Gunicorn
+ Workers>, shape=hexagon, fillcolor="#aed6f1", color="#2980b9"]; + nginx [label=<Nginx
(Frontend)>, shape=hexagon, fillcolor="#aed6f1", color="#2980b9"]; + mdb [label=<MariaDB 10.6
StatefulSet>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"]; + } + subgraph cluster_paperless { + label="ns: paperless"; style=filled; bgcolor="#d6eaf8"; color="#5dade2"; + ppl [label=<Paperless-NGX>, shape=hexagon, fillcolor="#aed6f1", color="#2980b9"]; + pgp [label=<PostgreSQL>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"]; + } + subgraph cluster_zitadel { + label="ns: zitadel"; style=filled; bgcolor="#d6eaf8"; color="#5dade2"; + pgz [label=<PostgreSQL
(Zitadel)>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"]; + } + subgraph cluster_rmq { + label="ns: rabbitmq"; style=filled; bgcolor="#d6eaf8"; color="#5dade2"; + rmq [label=<RabbitMQ>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"]; + } + } + + /* ───────────────────────────────────────────── + SCHICHT 2 – PVCs + ───────────────────────────────────────────── */ + subgraph cluster_pvcs { + label=<② KUBERNETES PVCs>; + style=filled; bgcolor="#eaf5ea"; color="#27ae60"; penwidth=2; fontcolor="#1e8449"; + + subgraph cluster_pvc_erpnext { + label=<longhorn-erpnext [Retain ✅]>; + style=filled; bgcolor="#d5f5e3"; color="#52be80"; + + pvc_mdb [label=<mariadb-sts-0
3 Gi RWO>, fillcolor="#d5f5e3", color="#1e8449"]; + pvc_sites [label=<erpnext-sites
3 Gi RWX ⚠>, fillcolor="#fef9e7", color="#e67e22"]; + pvc_logs [label=<erpnext-logs
1 Gi RWX ⚠>, fillcolor="#fef9e7", color="#e67e22"]; + } + subgraph cluster_pvc_paperless { + label=<longhorn-paperless [Retain ✅]>; + style=filled; bgcolor="#d5f5e3"; color="#52be80"; + + pvc_ppl [label=<media
10 Gi RWO>, fillcolor="#d5f5e3", color="#1e8449"]; + pvc_pgp [label=<postgres
5 Gi RWO>, fillcolor="#d5f5e3", color="#1e8449"]; + } + subgraph cluster_pvc_del { + label=<longhorn [Delete ]>; + style=filled; bgcolor="#fef9e7"; color="#e67e22"; + + pvc_pgz [label=<zitadel-pg
10 Gi RWO>, fillcolor="#fef9e7", color="#d35400"]; + pvc_rmq [label=<rabbitmq
5 Gi RWO>, fillcolor="#fef9e7", color="#d35400"]; + } + } + + /* ───────────────────────────────────────────── + SCHICHT 3 – LONGHORN ENGINE + ───────────────────────────────────────────── */ + subgraph cluster_longhorn { + label=<③ LONGHORN STORAGE ENGINE
(driver.longhorn.io)>; + style=filled; bgcolor="#f4ecf7"; color="#8e44ad"; penwidth=2; fontcolor="#6c3483"; + + subgraph cluster_sm { + label=<⚠ RWX Share-Manager
läuft auf: efsckubnode02 (Proxmox n01)
→ SPOF: fällt n01, fallen RWX-Volumes (ERPNext)
>; + style=filled; bgcolor="#fef9e7"; color="#e67e22"; penwidth=2; + + sm_sites [label=<share-manager
erpnext-sites>, shape=ellipse, fillcolor="#fdebd0", color="#e67e22"]; + sm_logs [label=<share-manager
erpnext-logs>, shape=ellipse, fillcolor="#fdebd0", color="#e67e22"]; + } + + subgraph cluster_replicas { + label=<✅ Block-Replikation: 2 Replicas je Volume
Daten auf verschiedenen K3s-Worker-Nodes
>; + style=filled; bgcolor="#eafaf1"; color="#27ae60"; penwidth=2; + + rep_a [label=<Replica A
auf: efsckubnode1
(Proxmox n02)>, shape=cylinder, fillcolor="#d5f5e3", color="#1e8449"]; + rep_b [label=<Replica B
auf: efsckubnode02
(Proxmox n01)>, shape=cylinder, fillcolor="#d5f5e3", color="#1e8449"]; + } + + subgraph cluster_csi { + label=<⚠ CSI Controller-Pods
Nur auf efsckubnode1 (n02)
→ fällt n02: keine neuen Volumes
>; + style=filled; bgcolor="#fef9e7"; color="#e67e22"; + + csi [label=<csi-attacher (3×)
csi-provisioner (3×)
csi-resizer (3×)>, fillcolor="#fdebd0", color="#e67e22"]; + } + } + + /* ───────────────────────────────────────────── + SCHICHT 4 – K3s NODES (VMs) + ───────────────────────────────────────────── */ + subgraph cluster_k3s { + label=<④ K3s CLUSTER>; + style=filled; bgcolor="#fdf2f8"; color="#c0392b"; penwidth=2; fontcolor="#922b21"; + + subgraph cluster_ctrl { + label=<🔴 Control Plane – SINGLE POINT OF FAILURE
Nur 1 Node, VM auf Proxmox n01
→ n01 fällt = kein Cluster-Management, kein Pod-Rescheduling
>; + style=filled; bgcolor="#fadbd8"; color="#e74c3c"; penwidth=3; + + kubadm [label=<efsckubadm
10.42.71.50
VM: efsckubctl (n01)>, shape=diamond, fillcolor="#f1948a", color="#c0392b"]; + } + + subgraph cluster_workers { + label=<✅ Worker Nodes auf verschiedenen Proxmox Hosts>; + style=filled; bgcolor="#eafaf1"; color="#27ae60"; + + node1 [label=<efsckubnode1
10.42.71.51
VM auf: Proxmox n02
→ Replica A + CSI Controllers>, fillcolor="#d5f5e3", color="#1e8449"]; + node2 [label=<efsckubnode02
10.42.71.52
VM auf: Proxmox n01
→ Replica B + share-manager>, fillcolor="#fdebd0", color="#e67e22"]; + } + } + + /* ───────────────────────────────────────────── + SCHICHT 5 – PROXMOX HOSTS + ───────────────────────────────────────────── */ + subgraph cluster_proxmox { + label=<⑤ PROXMOX CLUSTER efproxcl02
⚠ Nur 2 Nodes – kein 3-Node-Quorum / kein automatisches Fencing>; + style=filled; bgcolor="#fdfefe"; color="#7f8c8d"; penwidth=2; + + subgraph cluster_pn01 { + label=<efproxcl02n01 10.42.70.1
🔴 KRITISCH: Control-Plane + efsckubnode02 + share-manager
Ausfall → ERPNext vollständig down (kein Rescheduling möglich)
>; + style=filled; bgcolor="#fadbd8"; color="#e74c3c"; penwidth=2; + + pn01 [label=<Proxmox Host 1
64 vCPU / 128 GB RAM>, shape=box, fillcolor="#f1948a", color="#c0392b"]; + disk_n01 [label=<Lokaler Speicher
Replica B
erpnext / paperless
zitadel / rabbitmq
>, shape=cylinder, fillcolor="#fadbd8", color="#e74c3c"]; + } + + subgraph cluster_pn02 { + label=<efproxcl02n02 10.42.70.2
🟡 Ausfall → degradiert: Daten intakt (Replica B ok)
Keine neuen Volumes (CSI weg), ERPNext-Pods reschedule auf node02
>; + style=filled; bgcolor="#fef9e7"; color="#e67e22"; penwidth=2; + + pn02 [label=<Proxmox Host 2
64 vCPU / 128 GB RAM>, shape=box, fillcolor="#fdebd0", color="#d35400"]; + disk_n02 [label=<Lokaler Speicher
Replica A
erpnext / paperless
zitadel / rabbitmq
>, shape=cylinder, fillcolor="#fef9e7", color="#e67e22"]; + } + } + + /* ───────────────────────────────────────────── + EDGES + ───────────────────────────────────────────── */ + + /* Apps → PVCs */ + mdb -> pvc_mdb [color="#2980b9", penwidth=2]; + gui -> pvc_sites [color="#2980b9", penwidth=2]; + nginx -> pvc_logs [color="#2980b9", penwidth=2]; + ppl -> pvc_ppl [color="#2980b9", penwidth=2]; + pgp -> pvc_pgp [color="#2980b9", penwidth=2]; + pgz -> pvc_pgz [color="#2980b9", penwidth=2]; + rmq -> pvc_rmq [color="#2980b9", penwidth=2]; + + /* RWX PVCs → share-manager */ + pvc_sites -> sm_sites [color="#e67e22", penwidth=2, style=dashed, label="NFS"]; + pvc_logs -> sm_logs [color="#e67e22", penwidth=2, style=dashed, label="NFS"]; + + /* share-manager → Replica B */ + sm_sites -> rep_b [color="#e67e22", penwidth=2]; + sm_logs -> rep_b [color="#e67e22", penwidth=2]; + + /* RWO PVCs → beide Replicas (Longhorn CSI) */ + pvc_mdb -> rep_a [color="#27ae60", penwidth=2, label="Longhorn CSI"]; + pvc_mdb -> rep_b [color="#27ae60", penwidth=2]; + pvc_ppl -> rep_a [color="#27ae60", penwidth=2]; + pvc_ppl -> rep_b [color="#27ae60", penwidth=2]; + pvc_pgp -> rep_a [color="#27ae60", penwidth=2]; + pvc_pgp -> rep_b [color="#27ae60", penwidth=2]; + pvc_pgz -> rep_a [color="#27ae60", penwidth=2]; + pvc_pgz -> rep_b [color="#27ae60", penwidth=2]; + pvc_rmq -> rep_a [color="#27ae60", penwidth=2]; + pvc_rmq -> rep_b [color="#27ae60", penwidth=2]; + + /* Sync zwischen Replicas */ + rep_a -> rep_b [color="#27ae60", penwidth=2.5, style=bold, label="sync\n(synchron)"]; + + /* CSI → Volumes */ + csi -> rep_a [color="#95a5a6", style=dotted, label="provision"]; + + /* Replicas → K3s Worker Nodes */ + rep_a -> node1 [color="#27ae60", penwidth=2, label="physisch auf"]; + rep_b -> node2 [color="#27ae60", penwidth=2, label="physisch auf"]; + + /* Control-Plane → Workers */ + kubadm -> node1 [color="#7f8c8d", style=dashed, label="API"]; + kubadm -> node2 [color="#7f8c8d", style=dashed]; + + /* K3s Nodes → Proxmox Hosts */ + kubadm -> pn01 [color="#e74c3c", penwidth=3, label="VM auf n01"]; + node2 -> pn01 [color="#e67e22", penwidth=2.5, label="VM auf n01"]; + node1 -> pn02 [color="#27ae60", penwidth=2, label="VM auf n02"]; + + /* Proxmox → Disk */ + pn01 -> disk_n01 [color="#95a5a6"]; + pn02 -> disk_n02 [color="#95a5a6"]; + + /* Backup */ + disk_n01 -> disk_n02 [color="#95a5a6", style=dashed, + label="daily-backup CronJob\n(Longhorn, auf efsckubnode02)"]; + + /* ───────────────────────────────────────────── + RANK CONSTRAINTS – Spalten erzwingen (newrank=true erlaubt cross-cluster) + ───────────────────────────────────────────── */ + subgraph rank_apps { rank=same; gui; nginx; mdb; ppl; pgp; pgz; rmq; } + subgraph rank_pvcs { rank=same; pvc_mdb; pvc_sites; pvc_logs; pvc_ppl; pvc_pgp; pvc_pgz; pvc_rmq; } + subgraph rank_lh { rank=same; sm_sites; sm_logs; rep_a; rep_b; csi; } + subgraph rank_nodes { rank=same; kubadm; node1; node2; } + subgraph rank_prox { rank=same; pn01; disk_n01; pn02; disk_n02; } +} diff --git a/diagrams/storage_flow.png b/diagrams/storage_flow.png new file mode 100644 index 0000000..7a55bfd Binary files /dev/null and b/diagrams/storage_flow.png differ diff --git a/docs/storage.md b/docs/storage.md index 6491ed4..c98979f 100644 --- a/docs/storage.md +++ b/docs/storage.md @@ -1,6 +1,9 @@ # ExpertFab – Longhorn Storage Architektur -**Schaubild:** [../diagrams/storage_architecture.png](../diagrams/storage_architecture.png) +**Speicherfluss & HA-Analyse:** [../diagrams/storage_flow.png](../diagrams/storage_flow.png) +*(Quelle: [../diagrams/storage_flow.dot](../diagrams/storage_flow.dot))* + +**Übersicht (alt):** [../diagrams/storage_architecture.png](../diagrams/storage_architecture.png) ---