Cluster¶
The cluster (noah) runs Talos Linux v1.12 on Proxmox VMs across four mini PCs. It is provisioned with OpenTofu and managed via Flux CD.
Physical Hosts¶
| Host | Hardware | CPU | RAM |
|---|---|---|---|
| pve1 | GMKtec M2 Pro | Intel i7-1195G7 (8t) | 32 GB |
| pve2 | GMKtec M5 Plus | AMD Ryzen 7 5825U (16t) | 32 GB |
| pve3 | Beelink S13 | Intel N150 (4t) | 16 GB |
| pve4 | Beelink S13 | Intel N150 (4t) | 16 GB |
Node Topology¶
graph LR
subgraph pve1["pve1 — GMKtec M2 Pro"]
cp00["cp-00\n2 vCPU · 4 GB"]
w0a["worker-0a\n6 vCPU · 14 GB · iGPU"]
w0b["worker-0b\n6 vCPU · 13 GB"]
end
subgraph pve2["pve2 — GMKtec M5 Plus"]
cp01["cp-01\n4 vCPU · 4 GB"]
w1a["worker-1a\n10 vCPU · 14 GB"]
w1b["worker-1b\n10 vCPU · 13 GB"]
end
subgraph pve3["pve3 — Beelink S13"]
cp02["cp-02\n2 vCPU · 4 GB"]
w2a["worker-2a\n4 vCPU · 11 GB"]
end
subgraph pve4["pve4 — Beelink S13"]
w3a["worker-3a\n4 vCPU · 15 GB"]
end
cp00 ~~~ w0a ~~~ w0b
cp01 ~~~ w1a ~~~ w1b
cp02 ~~~ w2a
pve1 ~~~ pve2 ~~~ pve3 ~~~ pve4
Node Details¶
| Node | Host | vCPU | RAM |
|---|---|---|---|
| cp-00 | pve1 | 2 | 4 GB |
| cp-01 | pve2 | 4 | 4 GB |
| cp-02 | pve3 | 2 | 4 GB |
| Node | Host | vCPU | RAM | Local Disk | Notes |
|---|---|---|---|---|---|
| worker-0a | pve1 | 6 | 14 GB | 400 GB | Intel iGPU; tainted dedicated=media:NoSchedule |
| worker-0b | pve1 | 6 | 13 GB | 400 GB | |
| worker-1a | pve2 | 10 | 14 GB | 100 GB | |
| worker-1b | pve2 | 10 | 13 GB | 100 GB | |
| worker-2a | pve3 | 4 | 11 GB | 100 GB | |
| worker-3a | pve4 | 4 | 15 GB | 100 GB |
Media node
worker-0a is dedicated to media workloads (Jellyfin, Emby, etc.) via the dedicated=media:NoSchedule taint. Only pods with the matching toleration are scheduled there.
Networking¶
| Subnet / Range | Purpose |
|---|---|
| 192.168.68.0/22 | Home network / Proxmox hosts |
| 192.168.68.50–192.168.70.255 | DHCP range (dynamic clients) |
| 192.168.71.0/24 | Kubernetes nodes |
Static IPs (Proxmox hosts, NAS, Kubernetes nodes, etc.) are assigned below 192.168.68.50, outside the DHCP range. Cilium manages an L2 LoadBalancer IP pool within the 192.168.71.0/24 subnet, used for the shared Gateway and Ingress Controller.
Storage¶
| Type | Used for |
|---|---|
local-path |
Node-local PVCs; apps requiring fast local storage (e.g. SQLite) |
| Synology NFS CSI | Shared persistent volumes backed by the NAS |
See Storage for StorageClass details and provisioning patterns.
Management¶
The cluster is provisioned with OpenTofu (infrastructure as code) and application deployments are managed by Flux CD watching the flux branch of the Gitea repository.
- See Provisioning for OpenTofu details
- See GitOps for Flux CD structure
Headlamp¶
Headlamp is a Kubernetes UI running at headlamp.hdhomelab.com. It provides a web interface for browsing cluster resources, workloads, events, and logs.
Authentication¶
Headlamp is authenticated via Authentik OIDC. Group membership maps to Kubernetes RBAC roles:
| Authentik Group | Kubernetes ClusterRole |
|---|---|
headlamp_admin |
cluster-admin |
headlamp_editor |
edit |
headlamp_viewer |
view |
Plugins¶
Plugins are installed by init containers at pod startup, each copying their assets into a shared headlamp-plugins PVC:
| Plugin | Source |
|---|---|
| Flux | ghcr.io/headlamp-k8s/headlamp-plugin-flux |
| AI Assistant | ghcr.io/headlamp-k8s/headlamp-plugin-ai-assistant |
| cert-manager | ghcr.io/headlamp-k8s/headlamp-plugin-cert-manager |
| Prometheus | Downloaded from GitHub releases at startup |
| App Catalog | Downloaded from GitHub releases at startup |
| Plugin Catalog | Downloaded from GitHub releases at startup |
Plugin persistence
Plugins are stored in a PVC (headlamp-plugins) so they survive pod restarts without re-downloading. The init containers re-copy on each start to pick up image updates.