Add storage flow & HA analysis diagram

Graphviz DOT-based diagram showing the complete storage path:
App pods → PVCs (StorageClass/Retain-Policy) → Longhorn replicas →
K3s worker nodes → Proxmox hosts.

HA analysis annotated with color coding:
- Red: SPOF (control-plane on n01, share-manager on n01)
- Orange: Degraded on failure (CSI controllers on n02, RWX volumes)
- Green: HA covered (2 Longhorn replicas on different Proxmox hosts)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-03 14:00:45 +02:00
parent bbe86c55d9
commit 2f8fb1349c
3 changed files with 230 additions and 1 deletions

226
diagrams/storage_flow.dot Normal file
View File

@@ -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=<<b>① APPLIKATIONEN</b><br/>(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=<<b>Gunicorn</b><br/>+ Workers>, shape=hexagon, fillcolor="#aed6f1", color="#2980b9"];
nginx [label=<<b>Nginx</b><br/>(Frontend)>, shape=hexagon, fillcolor="#aed6f1", color="#2980b9"];
mdb [label=<<b>MariaDB 10.6</b><br/>StatefulSet>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"];
}
subgraph cluster_paperless {
label="ns: paperless"; style=filled; bgcolor="#d6eaf8"; color="#5dade2";
ppl [label=<<b>Paperless-NGX</b>>, shape=hexagon, fillcolor="#aed6f1", color="#2980b9"];
pgp [label=<<b>PostgreSQL</b>>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"];
}
subgraph cluster_zitadel {
label="ns: zitadel"; style=filled; bgcolor="#d6eaf8"; color="#5dade2";
pgz [label=<<b>PostgreSQL</b><br/>(Zitadel)>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"];
}
subgraph cluster_rmq {
label="ns: rabbitmq"; style=filled; bgcolor="#d6eaf8"; color="#5dade2";
rmq [label=<<b>RabbitMQ</b>>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"];
}
}
/* ─────────────────────────────────────────────
SCHICHT 2 PVCs
───────────────────────────────────────────── */
subgraph cluster_pvcs {
label=<<b>② KUBERNETES PVCs</b>>;
style=filled; bgcolor="#eaf5ea"; color="#27ae60"; penwidth=2; fontcolor="#1e8449";
subgraph cluster_pvc_erpnext {
label=<<font point-size="10"><b>longhorn-erpnext</b> [Retain ✅]</font>>;
style=filled; bgcolor="#d5f5e3"; color="#52be80";
pvc_mdb [label=<<b>mariadb-sts-0</b><br/>3 Gi RWO>, fillcolor="#d5f5e3", color="#1e8449"];
pvc_sites [label=<<b>erpnext-sites</b><br/>3 Gi <font color="#e67e22"><b>RWX ⚠</b></font>>, fillcolor="#fef9e7", color="#e67e22"];
pvc_logs [label=<<b>erpnext-logs</b><br/>1 Gi <font color="#e67e22"><b>RWX ⚠</b></font>>, fillcolor="#fef9e7", color="#e67e22"];
}
subgraph cluster_pvc_paperless {
label=<<font point-size="10"><b>longhorn-paperless</b> [Retain ✅]</font>>;
style=filled; bgcolor="#d5f5e3"; color="#52be80";
pvc_ppl [label=<<b>media</b><br/>10 Gi RWO>, fillcolor="#d5f5e3", color="#1e8449"];
pvc_pgp [label=<<b>postgres</b><br/>5 Gi RWO>, fillcolor="#d5f5e3", color="#1e8449"];
}
subgraph cluster_pvc_del {
label=<<font point-size="10"><b>longhorn</b> [Delete <font color="#e67e22">⚠</font>]</font>>;
style=filled; bgcolor="#fef9e7"; color="#e67e22";
pvc_pgz [label=<<b>zitadel-pg</b><br/>10 Gi RWO>, fillcolor="#fef9e7", color="#d35400"];
pvc_rmq [label=<<b>rabbitmq</b><br/>5 Gi RWO>, fillcolor="#fef9e7", color="#d35400"];
}
}
/* ─────────────────────────────────────────────
SCHICHT 3 LONGHORN ENGINE
───────────────────────────────────────────── */
subgraph cluster_longhorn {
label=<<b>③ LONGHORN STORAGE ENGINE</b><br/><font point-size="10">(driver.longhorn.io)</font>>;
style=filled; bgcolor="#f4ecf7"; color="#8e44ad"; penwidth=2; fontcolor="#6c3483";
subgraph cluster_sm {
label=<<font point-size="10" color="#e67e22"><b>⚠ RWX Share-Manager</b><br/>läuft auf: efsckubnode02 (Proxmox n01)<br/>→ SPOF: fällt n01, fallen RWX-Volumes (ERPNext)</font>>;
style=filled; bgcolor="#fef9e7"; color="#e67e22"; penwidth=2;
sm_sites [label=<<b>share-manager</b><br/>erpnext-sites>, shape=ellipse, fillcolor="#fdebd0", color="#e67e22"];
sm_logs [label=<<b>share-manager</b><br/>erpnext-logs>, shape=ellipse, fillcolor="#fdebd0", color="#e67e22"];
}
subgraph cluster_replicas {
label=<<font point-size="10" color="#27ae60"><b>✅ Block-Replikation: 2 Replicas je Volume</b><br/>Daten auf verschiedenen K3s-Worker-Nodes</font>>;
style=filled; bgcolor="#eafaf1"; color="#27ae60"; penwidth=2;
rep_a [label=<<b>Replica A</b><br/>auf: efsckubnode1<br/>(Proxmox n02)>, shape=cylinder, fillcolor="#d5f5e3", color="#1e8449"];
rep_b [label=<<b>Replica B</b><br/>auf: efsckubnode02<br/>(Proxmox n01)>, shape=cylinder, fillcolor="#d5f5e3", color="#1e8449"];
}
subgraph cluster_csi {
label=<<font point-size="10" color="#e67e22"><b>⚠ CSI Controller-Pods</b><br/>Nur auf efsckubnode1 (n02)<br/>→ fällt n02: keine neuen Volumes</font>>;
style=filled; bgcolor="#fef9e7"; color="#e67e22";
csi [label=<<b>csi-attacher (3×)</b><br/>csi-provisioner (3×)<br/>csi-resizer (3×)>, fillcolor="#fdebd0", color="#e67e22"];
}
}
/* ─────────────────────────────────────────────
SCHICHT 4 K3s NODES (VMs)
───────────────────────────────────────────── */
subgraph cluster_k3s {
label=<<b>④ K3s CLUSTER</b>>;
style=filled; bgcolor="#fdf2f8"; color="#c0392b"; penwidth=2; fontcolor="#922b21";
subgraph cluster_ctrl {
label=<<font color="#c0392b" point-size="10"><b>🔴 Control Plane SINGLE POINT OF FAILURE</b><br/>Nur 1 Node, VM auf Proxmox n01<br/>→ n01 fällt = kein Cluster-Management, kein Pod-Rescheduling</font>>;
style=filled; bgcolor="#fadbd8"; color="#e74c3c"; penwidth=3;
kubadm [label=<<b>efsckubadm</b><br/>10.42.71.50<br/><font point-size="10">VM: efsckubctl (n01)</font>>, shape=diamond, fillcolor="#f1948a", color="#c0392b"];
}
subgraph cluster_workers {
label=<<font point-size="10" color="#27ae60"><b>✅ Worker Nodes auf verschiedenen Proxmox Hosts</b></font>>;
style=filled; bgcolor="#eafaf1"; color="#27ae60";
node1 [label=<<b>efsckubnode1</b><br/>10.42.71.51<br/><font point-size="10">VM auf: Proxmox n02</font><br/><font point-size="9">→ Replica A + CSI Controllers</font>>, fillcolor="#d5f5e3", color="#1e8449"];
node2 [label=<<b>efsckubnode02</b><br/>10.42.71.52<br/><font point-size="10">VM auf: Proxmox n01</font><br/><font point-size="9">→ Replica B + share-manager</font>>, fillcolor="#fdebd0", color="#e67e22"];
}
}
/* ─────────────────────────────────────────────
SCHICHT 5 PROXMOX HOSTS
───────────────────────────────────────────── */
subgraph cluster_proxmox {
label=<<b>⑤ PROXMOX CLUSTER efproxcl02</b><br/><font point-size="10">⚠ Nur 2 Nodes kein 3-Node-Quorum / kein automatisches Fencing</font>>;
style=filled; bgcolor="#fdfefe"; color="#7f8c8d"; penwidth=2;
subgraph cluster_pn01 {
label=<<b>efproxcl02n01</b> 10.42.70.1<br/><font point-size="10" color="#c0392b"><b>🔴 KRITISCH: Control-Plane + efsckubnode02 + share-manager</b><br/>Ausfall → ERPNext vollständig down (kein Rescheduling möglich)</font>>;
style=filled; bgcolor="#fadbd8"; color="#e74c3c"; penwidth=2;
pn01 [label=<<b>Proxmox Host 1</b><br/>64 vCPU / 128 GB RAM>, shape=box, fillcolor="#f1948a", color="#c0392b"];
disk_n01 [label=<<b>Lokaler Speicher</b><br/>Replica B<br/><font point-size="9">erpnext / paperless<br/>zitadel / rabbitmq</font>>, shape=cylinder, fillcolor="#fadbd8", color="#e74c3c"];
}
subgraph cluster_pn02 {
label=<<b>efproxcl02n02</b> 10.42.70.2<br/><font point-size="10" color="#e67e22"><b>🟡 Ausfall → degradiert:</b> Daten intakt (Replica B ok)<br/>Keine neuen Volumes (CSI weg), ERPNext-Pods reschedule auf node02</font>>;
style=filled; bgcolor="#fef9e7"; color="#e67e22"; penwidth=2;
pn02 [label=<<b>Proxmox Host 2</b><br/>64 vCPU / 128 GB RAM>, shape=box, fillcolor="#fdebd0", color="#d35400"];
disk_n02 [label=<<b>Lokaler Speicher</b><br/>Replica A<br/><font point-size="9">erpnext / paperless<br/>zitadel / rabbitmq</font>>, 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; }
}

BIN
diagrams/storage_flow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 KiB