Skip to content

Repository files navigation

Homelab

FluxCD GitOps configuration for my homelab Kubernetes cluster.

Table of Contents

Hardware

I run all virtual machines inside a single physical machine with Proxmox VE:

  • CPU: Intel(R) Xeon(R) CPU E5-2670 v3
  • RAM: 64 GB
  • SSD: 1.5 TB

Three VMs on Proxmox VE running Talos Linux as the Kubernetes node OS.

List of Applications

Networking & Gateway

Secrets & Security

Storage & Databases

Observability

CI/CD

Applications

Repository Structure

.
├── apps
│   ├── base                    # Reusable app definitions (HelmRelease, HelmRepository, namespace, …)
│   │   ├── cert-manager
│   │   ├── cilium
│   │   ├── envoy-gateway
│   │   └── …
│   └── bundles                 # Environment aggregations with version-constraint patches
│       ├── dev-flex            # Loose constraints — picks up any new release
│       └── prod-stable         # Exact pins — only explicitly approved versions
├── clusters
│   ├── local                   # Local Kind cluster for development and testing
│   │   └── …
│   └── homelab                 # Production Talos cluster
│       ├── apps
│       │   ├── kustomization.yaml   # Includes prod-stable bundle + cluster overlays + patches
│       │   └── …
│       ├── bundle.yaml         # Flux Kustomization → ./clusters/homelab/apps
│       └── crds.yaml           # Flux Kustomization → ./crds/homelab
├── crds                        # Operator CRDs reconciled before app bundles
│   └── homelab
├── scripts                     # Utility scripts (validation, SOPS helpers)
└── .github/workflows
    ├── e2e.yaml                # End-to-end test on a Kind cluster
    ├── commitlint.yaml         # Conventional commit message validation
    └── test.yaml               # Manifest validation and linting

Structure Idea

The basic idea is to define three levels of Kustomize layering:

  1. Base (apps/base/<name>) — common HelmRelease defaults, HelmRepository, and namespace. No environment specifics.
  2. Bundle (apps/bundles/<bundle>) — aggregates base apps and overrides only spec.chart.spec.version via a single patch file.
  3. Cluster (clusters/<cluster>/apps/) — entry point that includes a bundle plus cluster-specific resources (storage, routing, secrets refs, network policies) and values patches.

Update Strategy

Application updates are managed by Renovate tracking Docker container image tags. Each cluster values file that overrides an application image includes a # renovate: datasource=docker annotation. Renovate detects new image tags and opens PRs.

Update flow:

Renovate detects new image tag → Opens PR with image bump → CI validates manifests → Review & merge → Flux reconciles homelab

Helm chart versions remain pinned in prod-stable and are updated manually when needed. Renovate does not track chart version changes.

Secrets Management

  • local — secrets are encrypted in Git with SOPS (age keys) and decrypted by Flux at reconcile time using the sops-age secret in flux-system.
  • homelab (production) — External Secrets Operator pulls runtime credentials from Vaultwarden (via the in-cluster bitwarden-cli webhook) into Kubernetes Secrets. SOPS is only used to solve the chicken-and-egg problem during initial cluster bootstrap.

Local Testing

Requirements:

  • flux, kubectl, and kind available in PATH
  • clusters/local/sops.agekey present for make bootstrap
  • GITHUB_OWNER and GITHUB_REPO exported in the environment
make bootstrap   # create Kind cluster and bootstrap Flux
make reconcile   # trigger Flux reconciliation
make wait        # wait for all Kustomizations and HelmReleases to become Ready
make smoke       # run basic health checks (podinfo HTTP probe)
make e2e         # full end-to-end: bootstrap → reconcile → wait → smoke
make validate    # run manifest validation (kustomize build + kubeconform)
make clean       # delete the local Kind cluster

About

FluxCD repo for my homelab

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages