from diagrams import Cluster, Diagram, Edge from diagrams.k8s.compute import Deployment, StatefulSet, Pod, DaemonSet, Job from diagrams.k8s.storage import PVC, StorageClass from diagrams.generic.storage import Storage graph_attr = { "fontsize": "13", "pad": "0.8", "nodesep": "0.6", "ranksep": "1.2", } with Diagram( "ExpertFab – Longhorn Storage Architektur", filename="storage_architecture", outformat="png", show=False, direction="TB", graph_attr=graph_attr, ): # ── Longhorn System Pods pro Node ───────────────────────────────────────── with Cluster("K3s Worker Nodes (Longhorn System Pods)"): with Cluster("efsckubnode1 (4 vCPU / 8 GB)"): n1_mgr = Pod("longhorn-manager") n1_csi = Pod("longhorn-csi-plugin") n1_eng = Pod("engine-image") n1_inst = Pod("instance-manager") n1_driver = Deployment("driver-deployer") n1_ui = Deployment("longhorn-ui (2×)") n1_attacher = Deployment("csi-attacher (3×)") n1_prov = Deployment("csi-provisioner (3×)") n1_resizer = Deployment("csi-resizer (3×)") n1_snap = Deployment("csi-snapshotter (3×)") with Cluster("efsckubnode2 (4 vCPU / 8 GB)"): n2_mgr = Pod("longhorn-manager") n2_csi = Pod("longhorn-csi-plugin") n2_eng = Pod("engine-image") n2_inst = Pod("instance-manager") n2_smgr1 = Pod("share-manager\n(erpnext RWX)") n2_smgr2 = Pod("share-manager\n(erpnext-logs RWX)") n2_backup = Job("daily-backup\n(CronJob)") # ── StorageClasses ──────────────────────────────────────────────────────── with Cluster("StorageClasses (driver.longhorn.io)"): sc_erpnext = StorageClass("longhorn-erpnext\nRetain / Immediate") sc_paperless = StorageClass("longhorn-paperless\nRetain / Immediate") sc_default = StorageClass("longhorn\nDelete / Immediate") # ── PVCs pro Namespace ──────────────────────────────────────────────────── with Cluster("PVCs"): with Cluster("namespace: erpnext"): pvc_mariadb = PVC("data-erpnext-mariadb-sts-0\n3 Gi RWO") pvc_sites = PVC("erpnext\n3 Gi RWX") pvc_logs = PVC("erpnext-logs\n1 Gi RWX") with Cluster("namespace: paperless"): pvc_pl_media = PVC("paperless-media\n10 Gi RWO") pvc_pl_consume = PVC("paperless-consume\n5 Gi RWO") pvc_pl_data = PVC("paperless-data\n5 Gi RWO") pvc_pl_pg = PVC("postgres-data\n5 Gi RWO") with Cluster("namespace: rabbitmq"): pvc_rmq = PVC("rabbitmq-data-rabbitmq-0\n5 Gi RWO") with Cluster("namespace: zitadel"): pvc_zit_pg = PVC("postgres-data-postgres-0\n10 Gi RWO") # ── StorageClass → PVC ──────────────────────────────────────────────────── sc_erpnext >> [pvc_mariadb, pvc_sites, pvc_logs] sc_paperless >> [pvc_pl_media, pvc_pl_consume, pvc_pl_data, pvc_pl_pg] sc_default >> [pvc_rmq, pvc_zit_pg] # ── Share-Manager bedient die RWX-Volumes ───────────────────────────────── n2_smgr1 >> Edge(label="serves", style="dashed") >> pvc_sites n2_smgr2 >> Edge(label="serves", style="dashed") >> pvc_logs # ── Longhorn Manager koordiniert über beide Nodes ───────────────────────── n1_mgr >> Edge(style="dotted", color="gray") >> n2_mgr