FFFF GitHub - buroa/home-ops: Husband-approved homelab deployed with Talos Linux; managed with Flux, Renovate, and GitHub Actions πŸ€– Β· GitHub
[go: up one dir, main page]

Skip to content
buroaPublic

About

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

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

396 stars

Watchers

5 watching

Forks

Repository files navigation

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 holds all of the configuration for my home Kubernetes cluster and the workloads that run on it. Every resource of the cluster is code, from the operating system to the Helm release of each application. The cluster applies changes to this code automatically.

The stack is simple on purpose, and you can build it again from this repository:

  • Talos Linux: a read-only, API-managed operating system for Kubernetes.
  • Flux: continuous sync of the cluster with this repository.
  • Renovate: automatic dependency updates for the whole cluster.
  • GitHub Actions: tests and automation on every commit.

The cluster can recover from a full loss. If you erase every disk in the rack, the cluster comes back within minutes. The applications run again and the persistent data is intact, with no manual steps. The cluster continues from the point where it stopped.

To build a similar cluster, start with onedr0p/cluster-template.


πŸ“¦ Repository Layout

πŸ“ bootstrap     # One-time cluster bootstrap (helmfile + kustomize)
πŸ“ kubernetes    # Everything that Flux applies
β”œβ”€πŸ“ apps        # Workloads, grouped by namespace
β”œβ”€πŸ“ components  # Reusable Kustomize components (alerts, kopiur, etc.)
πŸ“ talos         # Talos machine configuration and overrides for each node

🎑 Cluster

The cluster has three Kubernetes nodes on bare-metal MS-A2 workstations. It is semi hyper-converged: the same nodes run the workloads and most of the storage. Rook Ceph keeps the persistent storage inside the cluster. A dedicated TrueNAS server keeps the bulk media and shares it over NFS.

Core components

  • actions-runner-controller: self-hosted GitHub runners for CI/CD workflows.
  • cert-manager: automatic issue and renewal of SSL certificates.
  • cilium: container networking with eBPF.
  • cloudflared: a tunnel to cluster services through Cloudflare, which protects them.
  • envoy-gateway: the ingress controller for traffic into the cluster.
  • external-dns: automatic DNS records for the ingress resources.
  • external-secrets: Kubernetes secrets from 1Password.
  • kopiur: backup and recovery for persistent volume claims.
  • multus: extra network interfaces for pods.
  • rook: distributed storage for persistent volumes.
  • spegel: a stateless OCI registry mirror inside the cluster, for faster image pulls.

GitOps workflow

Flux watches the kubernetes directory. On every commit, Flux makes the cluster match it in these steps:

  1. Flux scans kubernetes/apps and all of its subdirectories, and reads each top-level kustomization.yaml.
  2. Each of these entry points usually declares a Namespace and one or more Flux Kustomization resources (ks.yaml).
  3. Each Flux Kustomization creates a HelmRelease, or raw manifests, for an application.
  4. Flux applies them in the order of their dependencies. For example, 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

The home network has several tiers and uses UniFi hardware. The UDM Beast does the routing and the firewall between the LAN and the 5Gbps WAN from RCN. A 25G aggregation switch is the backbone. It connects to the NAS with 25G LACP and to each Kubernetes node with 10G LACP. A 24-port PoE+ switch connects the wired clients and the 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 manage the DNS records. The private instance syncs every route to the UDM Beast through the ExternalDNS UniFi webhook. The public instance syncs the routes on the external Gateway to Cloudflare.

The result is split-horizon DNS, which gives different answers inside and outside the home. At home, public hostnames resolve to LAN IPs. Traffic from home to my own services thus 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 workstation (AMD Ryzenβ„’ 9 9955HX) has these parts:


πŸ™ Thanks

Thank you to @onedr0p and the Home Operations Discord community. Their help and their patterns made this cluster possible. For more examples of apps in a homelab, browse kubesearch.dev.


Ask DeepWiki

About

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

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

396 stars

Watchers

5 watching

Forks

Sponsor this project

Used by

Contributors

Languages

0