dorkhub

k8s-gitops

Husband-approved homelab deployed with Talos Linux; managed with Flux, Renovate, and GitHub Actions πŸ€–

buroa
YAMLβ˜… 388β‘‚ 22 forksWTFPLupdated 1 day ago
visit the demogit clone https://github.com/buroa/k8s-gitops.gitburoa/k8s-gitops

A slightly overengineered homelab 🏠

... managed with Flux, Renovate, and GitHub Actions πŸ€–

Home-InternetΒ Β  Status-PageΒ Β  Alertmanager

DiscordΒ Β  TalosΒ Β  KubernetesΒ Β  FluxΒ Β  Renovate

AgeΒ Β  UptimeΒ Β  NodesΒ Β  PodsΒ Β  CPUΒ Β  MemoryΒ Β  PowerΒ Β  Alerts


πŸ’‘ Overview

This repository is the single source of truth for my home Kubernetes cluster and the workloads that run on it. Every cluster resource β€” from the operating system layer down to individual application Helm releases β€” is declared as code and reconciled automatically.

The stack is intentionally boring and reproducible:

  • Talos Linux β€” Immutable, API-driven OS that runs nothing but Kubernetes.
  • Flux β€” Continuous reconciliation of cluster state against this repository.
  • Renovate β€” Automated dependency updates across the entire cluster.
  • GitHub Actions β€” Validation and automation on every commit.

Disaster recovery is built in. Wipe every disk in the rack. Minutes later, the cluster is back β€” applications running, persistent data intact, zero manual steps. It picks up exactly where it left off.

Want to build something similar? Start with onedr0p/cluster-template.


πŸ“¦ Repository Layout

πŸ“ bootstrap     # One-time cluster bootstrap (helmfile + kustomize)
πŸ“ kubernetes    # Everything Flux reconciles
β”œβ”€πŸ“ apps        # Workloads, grouped by namespace
β”œβ”€πŸ“ components  # Reusable Kustomize components (alerts, kopiur, etc.)
β””β”€πŸ“ flux        # Flux system configuration and source repositories
πŸ“ talos         # Talos machine configs and per-node overrides

🎑 Cluster

A semi hyper-converged, three-node Kubernetes cluster running on bare-metal MS-A2 workstations. Persistent storage lives inside the cluster via Rook Ceph, with bulk media offloaded to a dedicated TrueNAS box over NFS.

Core components

  • actions-runner-controller β€” Self-hosted GitHub runners for CI/CD workflows.
  • cert-manager β€” Automated SSL certificate management and provisioning.
  • cilium β€” High-performance container networking powered by eBPF.
  • cloudflared β€” Secure tunnel providing Cloudflare-protected access to cluster services.
  • envoy-gateway β€” Modern ingress controller for cluster traffic management.
  • external-dns β€” Automated DNS record synchronization for ingress resources.
  • external-secrets β€” Kubernetes secrets management integrated with 1Password.
  • kopiur β€” Advanced backup and recovery solution for persistent volume claims.
  • multus β€” Multi-homed pod networking for advanced network configurations.
  • rook β€” Cloud-native distributed storage orchestrator for persistent storage.
  • spegel β€” Stateless cluster-local OCI registry mirror for improved performance.

GitOps workflow

Flux watches the kubernetes directory and reconciles the cluster on every commit. The flow is:

  1. Flux recursively scans kubernetes/apps and reads each top-level kustomization.yaml.
  2. Those entrypoints typically declare a Namespace and one or more Flux Kustomization resources (ks.yaml).
  3. Each Flux Kustomization materializes a HelmRelease (or raw manifests) for an application.
  4. Flux applies them in dependency order β€” e.g. nothing in rook-ceph deploys until its prerequisites are healthy.
graph LR
    classDef kustom fill:#43A047,stroke:#2E7D32,stroke-width:3px,color:#fff,font-weight:bold,rx:10,ry:10
    classDef helm fill:#1976D2,stroke:#0D47A1,stroke-width:3px,color:#fff,font-weight:bold,rx:10,ry:10

    A["πŸ“¦ Kustomization<br/>rook-ceph"]:::kustom
    B["πŸ“¦ Kustomization<br/>rook-ceph-cluster"]:::kustom
    C["🎯 HelmRelease<br/>rook-ceph"]:::helm
    D["🎯 HelmRelease<br/>rook-ceph-cluster"]:::helm
    E["πŸ“¦ Kustomization<br/>atuin"]:::kustom
    F["🎯 HelmRelease<br/>atuin"]:::helm

    A -->|Creates| C
    B -->|Creates| D
    B -.->|Depends on| A
    E -->|Creates| F
    E -.->|Depends on| B
Loading

🌎 Networking

A multi-tier home network built on UniFi hardware. The UDM Beast handles routing and firewalling between RCN's 5Gbps WAN and the LAN. A 25G aggregation switch forms the backbone β€” bonded to the NAS at 25G LACP and to each Kubernetes node at 10G LACP β€” while a 24-port PoE+ switch fans out to wired clients and access points.

graph LR
    %% Class Definitions
    classDef wan fill:#f87171,stroke:#fff,stroke-width:2px,color:#fff,font-weight:bold;
    classDef core fill:#60a5fa,stroke:#fff,stroke-width:2px,color:#fff,font-weight:bold;
    classDef agg fill:#34d399,stroke:#fff,stroke-width:2px,color:#fff,font-weight:bold;
    classDef switch fill:#a78bfa,stroke:#fff,stroke-width:2px,color:#fff,font-weight:bold;
    classDef device fill:#facc15,stroke:#fff,stroke-width:2px,color:#000,font-weight:bold;
    classDef vlan fill:#1f2937,stroke:#fff,stroke-width:1px,color:#fff,font-size:12px;

    %% Nodes
    RCN[πŸ›œ RCN<br/>5Gbps WAN]:::wan
    UDM[πŸ“¦ UDM Beast]:::core
    AGG[πŸ”— Pro Aggregation XG]:::agg
    NAS[πŸ’Ύ NAS]:::device
    K8s[☸️ Kubernetes<br/>3 Nodes]:::device
    SW[πŸ”Œ Pro XG 24 PoE]:::switch
    DEV[πŸ’» Devices]:::device
    WIFI[πŸ“Ά WiFi Clients]:::device

    %% Subgraph for VLANs
    subgraph VLANs [LAN +vlan]
        direction TB
        LOCAL[LOCAL<br/>192.168.0.0/24]:::vlan
        TRUSTED[TRUSTED*<br/>192.168.1.0/24]:::vlan
        SERVERS[SERVERS*<br/>192.168.10.0/24]:::vlan
        SERVICES[SERVICES*<br/>192.168.20.0/24]:::vlan
        IOT[IOT*<br/>192.168.30.0/24]:::vlan
        GUEST[GUEST*<br/>192.168.40.0/24]:::vlan
    end

    style VLANs fill:#111,stroke:#fff,stroke-width:2px,rx:0,ry:0,padding:20px;

    %% Links
    SERVERS -.-> RCN
    RCN -.->|WAN| UDM
    UDM -- 25G --- AGG
    UDM -- 25G --- SW
    AGG -- 10G LACP --> K8s
    AGG -- 25G LACP --> NAS
    SW --> DEV
    SW --> WIFI

    %% Keep SERVERS->RCN as a hidden layout constraint and style bonded links thicker
    linkStyle 0 stroke:transparent,stroke-width:0px,color:transparent;
    linkStyle 2 stroke-width:4px;
    linkStyle 3 stroke-width:4px;
    linkStyle 4 stroke-width:2px;
    linkStyle 5 stroke-width:4px;
Loading

DNS

Two ExternalDNS instances handle DNS automation:

  • Private β€” Syncs every route to the UDM Beast via the ExternalDNS UniFi webhook.
  • Public β€” Syncs routes on the external Gateway to Cloudflare.

The result is split-horizon DNS: at home, public hostnames resolve to LAN IPs, so traffic to my own services never leaves the network.


βš™ Hardware

Click to see my rack rack
Device Count OS Disk Data Disk RAM OS Purpose
Minisforum MS-A2 3 1.92TB M.2 3.84TB U.2 + 1.92TB M.2 96GB Talos Kubernetes
45HomeLab HL15 2.0 1 1.92TB M.2 12Γ—22TB HDD + 2Γ—7.68TB U.2 512GB TrueNAS SCALE NFS + Backup Storage
JetKVM 3 - - - - KVM for Kubernetes
UniFi Dream Machine Beast 1 - 2Γ—960GB SSD - UniFi OS Router & NVR
UniFi Pro XG Aggregation 1 - - - UniFi OS 25G SFP28 Switch
UniFi Pro XG 24 PoE 1 - - - UniFi OS 10G PoE+ Switch
UniFi Power Distribution Pro 1 - - - UniFi OS PDU
APC SMT1500RM2UNC UPS 1 - - - - UPS

MS-A2 build

Each MS-A2 (AMD Ryzenβ„’ 9 9955HX) workstation is equipped with:


πŸ™ Thanks

A huge thank you to @onedr0p and the Home Operations Discord community for the knowledge, patterns, and support that made this cluster possible. For more inspiration on running apps in a homelab, browse kubesearch.dev.


🌟 Stargazers

Star History Chart

βš– License

See LICENSE.


Ask DeepWiki

more like this

flightjar

A self-hosted Mode S/ADS-B receiver UI: connects to a BEAST feed (readsb / dump1090-fa), decodes ADS-B + Comm-B (BDS…

C#β˜… 53

policyfs

Linux FUSE storage daemon with routing rules and SQLite metadata index.

Goβ˜… 53

findarr

Self-hosted discovery engine for movies and TV that learns your taste and avoids showing already rated content

TypeScriptβ˜… 55

search

search projects, people, and tags