HomeLab GitOps repository. Reconciled by flux.
  • JavaScript 100%
Find a file
Renovate Bot 9ed761b550
All checks were successful
ci/woodpecker/cron/renovate Pipeline was successful
chore(deps): update helm release kube-prometheus-stack to v87.15.2
2026-07-14 04:51:46 +00:00
.docs chore(docs): update reconcile script 2026-05-25 10:16:50 +02:00
.woodpecker config(renovate): add cron name renovate to main pipeline 2026-06-04 13:57:39 +02:00
apps chore(deps): update helm release kube-prometheus-stack to v87.15.2 2026-07-14 04:51:46 +00:00
clusters/phonk chore(deps): update dependency fluxcd/flux2 to v2.9.2 2026-07-14 04:02:59 +00:00
infrastructure chore(deps): update helm release cert-manager-webhook-hetzner to v0.8.0 2026-07-14 04:51:39 +00:00
.gitignore add(ops/bao): deploy OpenBao with CNPG backend and HTTPRoute 2026-05-17 16:09:56 +02:00
README.md add(gatus): deploy gatus 2026-06-05 13:33:29 +02:00
renovate.js config(renovate): enable kubernetes again 2026-06-04 13:57:39 +02:00
renovate.json add(renovate): add renovate.json 2026-06-04 13:57:39 +02:00
TODO.md add(home): deploy homeassistant 2026-07-10 23:15:48 +02:00

Gigawave

Renovate Flux Talos Kubernetes Helferlein

GitOps repo for the phonk Talos Linux homelab cluster (3 nodes), managed by Flux v2.

Cluster Overview

  • OS: Talos Linux
  • Hardware
    • HP ProDesk 400 G5 (4c, 48GB, 500GB SATA SSD, 2TB NVME)
    • HP ProDesk 400 G5 (4c, 48GB, 500GB SATA SSD, 2TB NVME)
    • HP ProDesk 400 G5 (4c, 64GB, 500GB SATA SSD, 2TB NVME)
  • Network: Local 2.5GbE
  • CNI
    • Cilium
      • kube-proxy replacement
      • Hubble (tbh i dont see much value here... thinking of turning it off)
  • Storage
    • Local Path — workloads with PVCs are pinned to a node for rescheduling
  • Secrets
    • OpenBao
      • PostgreSQL backend
      • Unseal via static seal secret applied before flux bootstrap
    • External Secrets Operator
  • Gateway
    • Envoy
      • external
        • 1bleim.de
        • anuth.dev
        • fullbyte.de
      • internal
        • ops.phonk.jukebox.fullbyte.de
        • home.anuth.dev

GitOps

  • Bootstrap from forge.fullbyte.de/fullbyte/gigawave
  • Self-hosted RenovateBot is acting as @helferlein
    • no Flux image automation

Docs

  • Bootstrap — Flux install, manual secrets, SSH deploy key, reconcile reference
  • OpenBao — init, zone KV + auth setup, OIDC, initial secrets
  • Talos / BGP — node operations, MikroTik BGP config
  • Each app has its own README detailing why it exists and what should be deployed here

Repository Structure

gigawave/
├── clusters/phonk/          # Flux Kustomization CRs
│   ├── flux-system/         # flux-operator FluxInstance
│   ├── infrastructure/      # one .yaml per infra layer
│   └── apps/                # one .yaml per zone
├── infrastructure/
│   ├── namespaces/          # zone + operator namespaces
│   ├── sources/             # HelmRepository + GitRepository CRs
│   ├── cni/cilium/          # Cilium HelmRelease (kube-system)
│   ├── csi/local-path/      # local-path-provisioner HelmRelease
│   ├── gateway/envoy/       # stub — Envoy Gateway migration (future)
│   └── operators/
│       ├── cert/            # cert-manager, cert-manager-webhook-hetzner
│       ├── kafka/strimzi/
│       ├── opensearch/opensearch-operator/
│       ├── postgresql/cnpg/
│       ├── redis/redis-operator/
│       ├── secrets/external-secrets/
│       └── storage/garage-operator/
└── apps/
    ├── ops/                 # namespace: ops — cluster services
    │   ├── bao/             # OpenBao HelmRelease + bao-db CNPG cluster
    │   ├── config/          # SecretStore, ClusterIssuer, wildcard certs
    │   ├── gitops/flux-operator/
    │   ├── monitoring/      # kube-prometheus-stack + Thanos
    │   ├── network/dns/zone/# CoreDNS for *.ops.phonk.jukebox.fullbyte.de
    │   └── pgadmin/
    ├── fullbyte/            # namespace: fullbyte — fullbyte.de services
    │   ├── config/          # SecretStore
    │   ├── ci/              # Woodpecker CI
    │   ├── forge/           # Forgejo + forgejo-db
    │   ├── httpbin/
    │   ├── id/              # PocketID + pocketid-db
    │   └── s3/              # GarageCluster
    ├── home/                # namespace: home — home.anuth.dev services
    │   ├── config/          # SecretStore
    │   └── network/dns/
    │       ├── zone/        # CoreDNS for *.home.anuth.dev
    │       └── resolver/    # Blocky (upstreams: ops zone + home zone)
    ├── 1bleim/              # stub (future: 1bleim.de)
    ├── anuth/               # stub (future: anuth.dev)
    └── vanknel/             # stub (future: vanknel.de)

Dependency Graph

graph TD
    namespaces[infrastructure-namespaces]
    sources[infrastructure-sources]
    csi[infrastructure-csi]
    crds_gw[infrastructure-crds-gateway-api]
    crds_prom[infrastructure-crds-prometheus]
    cni[infrastructure-cni]
    gateway[infrastructure-gateway]
    operators[infrastructure-operators]
    ops[apps-ops]
    fullbyte[apps-fullbyte]
    home[apps-home]
    stubs["apps-1bleim / apps-anuth / apps-vanknel"]

    namespaces --> sources
    namespaces --> csi
    sources --> crds_gw
    sources --> crds_prom
    crds_gw --> cni
    crds_gw --> gateway
    cni --> operators
    operators --> ops
    crds_prom --> ops
    ops --> fullbyte
    ops --> home
    ops --> stubs

Key Conventions

  • New namespace → add to infrastructure/namespaces/namespaces.yaml
  • New Helm repo → add to infrastructure/sources/helm-repos.yaml
  • Operator HelmRelease → goes in infrastructure/operators/<category>/<name>/helmrelease.yaml
  • Operator instances: one cluster per tenant (e.g. bao-db, grafana-db, <app>-db). Always use instances: 3 with enablePodAntiAffinity: required and topologyKey: kubernetes.io/hostname — one replica per node, survives two node failures. No nodeSelector needed.
  • pgAdmin: add server to pgAdmin manually after deploy
  • New HTTPRoute → add the corresponding link to apps/ops/glance/configmap.yaml under the matching namespace/tenant group in the Services page bookmarks widget
  • New HTTPRoute → add an endpoint entry to apps/ops/gatus/helmrelease.yaml under values.config.endpoints for uptime monitoring (Gatus does not support Gateway API HTTPRoute autodiscovery, static config only)
  • Secrets pattern: ExternalSecret (pulls from OpenBao) → Kubernetes Secret → consumed by HelmRelease valuesFrom
  • SecretStore: one namespace-scoped SecretStore named openbao per zone (apps/<zone>/config/secretstore.yaml), pointing to bao.ops.svc.cluster.local. Use ClusterSecretStore only for cross-namespace infra (e.g. cert-manager-webhook-hetzner).
  • Stages: most workloads prod-only. If dev is required, create namespace <name>-dev and deploy a separate instance.
  • Variable substitution: cluster-wide vars in cluster-config ConfigMap; Flux postBuild.substituteFrom injects them. Reference as ${VAR_NAME} in manifests.
  • Deployment mode: single instance where possible. Stateful workloads: pin to node, deploy ≥2 if HA is possible, otherwise add backup TODO.
  • Storage: prefer emptyDir for ephemeral state; PVCs only for data that must survive pod restarts.
  • Email: outbound via Brevo (SMTP relay)
    • Verified senders
      • id@fullbyte.de (PocketID)
      • git@fullbyte.de (Forgejo)
      • noreply@fullbyte.de (all others)

Learnings

  • routing
    • less is more
    • bridge is like a partition for network ports on a switch/router
    • add DNS and NTP server to your network early
    • wait for NTP to fully sync before relying on time-sensitive services