A hybrid homelab managed entirely through GitOps — Docker Compose stacks on a NAS for media workloads, and a 3-node RKE2 Kubernetes cluster for platform services. A separate lab tier (Nutanix on an R620, Proxmox on an XPS) hosts AAP, a TFE agent, and other enterprise tooling for skills prep — kept outside the GitOps loop because it's expected to be temporary.
| Device | Role | CPU | RAM | Storage | OS |
|---|---|---|---|---|---|
| UGREEN DXP6800 Pro | NAS + Docker host | Intel i5-1235U | 40GB | 53TB | TrueNAS SCALE |
| Intel NUC #1 | RKE2 worker | Intel Core i5-8259U | 32GB | 500GB | Elemental OS |
| Intel NUC #2 | RKE2 worker | Intel Core i7-8559U | 32GB | 250GB | Elemental OS |
| Intel NUC #3 | RKE2 worker | Intel Core i7-8559U | 32GB | 250GB | Elemental OS |
| Device | Role | CPU | RAM | Storage | OS |
|---|---|---|---|---|---|
| Dell PowerEdge R620 | Nutanix CE host (AHV + CVM) | 2x Xeon | 128GB | Mixed SSD/HDD | Nutanix CE (AHV) |
| Dell XPS 15 9510 | Proxmox host (AAP + TFE agent VMs) | Intel Core (11th gen) | 32GB | 1TB SSD | Proxmox VE |
homelab/
├── .github/workflows/ # CI/CD — linting, Flux diff, NAS deploy
├── docs/ # Architecture decisions, runbooks
│ ├── adr.md # Architecture Decision Records
│ ├── bootstrap.md # Cluster bootstrap procedure
│ ├── naming-and-ips.md # Hostnames, VLANs, IP allocations
│ └── disaster-recovery.md # Backup strategy, restore procedures
│
├── docker/ # NAS Docker Compose stacks (deployed via nas-deploy workflow)
│ ├── ansible/ # Ansible playbook and inventory for stack bring-up
│ ├── openbao/ # Example stack
│ │ ├── docker-compose.yaml
│ │ ├── .env.sops # SOPS-encrypted env vars (decrypted at deploy time)
│ │ └── config/ # Optional: stack config files
│ │ └── openbao.hcl # synced to /volume3/docker_config/<stack>/
│ └── <stack>/ # Compose + env sync to /volume3/docker_compose/<stack>/
│
└── clusters/
└── hlcl1/ # RKE2 cluster (Flux CD managed)
├── flux-system/ # Flux bootstrap
├── kustomization.yaml # Cluster entrypoint
├── vars/ # Cluster-specific values (IPs, domains)
│ └── cluster-config.yaml
├── infra/ # Foundational platform components
│ ├── network/
│ │ └── metallb/
│ │ ├── ks-chart.yaml # Flux Kustomization: Helm chart
│ │ ├── ks-config.yaml # Flux Kustomization: IP pool config (dependsOn chart)
│ │ ├── chart/ # Namespace, HelmRepository, HelmRelease
│ │ └── config/ # IPAddressPool, L2Advertisement
│ ├── storage/
│ │ ├── longhorn/
│ │ └── nfs/
│ ├── traefik/
│ ├── cert-manager/
│ └── external-dns/
└── apps/ # Cluster applications
├── pihole/
└── monitoring/
Media workloads (Plex, Sonarr, Radarr, DL) stay on the NAS as Docker Compose stacks because they need local filesystem access for hardlinks (no storage duplication), QuickSync hardware transcoding, and direct disk I/O. Kubernetes adds complexity without benefit here.
Platform services (DNS, monitoring, ingress, secrets management) run on the RKE2 cluster where they benefit from orchestration, self-healing, and LoadBalancer IPs.
See ADR-005 for the full rationale.
See setup-guide.md, for the full bootstrap procedure. (TODO: Add setup-guide.md)
- Architecture — service map, data flows, storage topology
- TODO: Write setupguide.md
- Networking — VLANs, DNS, IP allocations
- Disaster Recovery — backup strategy, restore procedures