Homelab setup based on Omni and Talos.
This repository contains the configuration files for my homelab. The homelab is a collection of servers and services that I run at home or in the cloud. The homelab is used for learning, testing, and hosting projects.
To avoid headaches and to keep things simple, I use Talos to manage the Kubernetes cluster (don't hesitate to check a little article I wrote about it). To be more specific, I have a self-hosted Omni instance to manage all clusters with a single endpoint and secure them with SSO.
- Omni (Self-hosted) : Manage all nodes between clusters and regions.
- Cilium as CNI and LB (ARP mode)
- ArgoCD to manage the GitOps workflow
- Traefik as Ingress controller (and for middleware management)
- Cert Manager for TLS certificates
- External DNS to publish records from Ingresses
- Storage:
- Rook (Ceph) on
turing, plus csi-driver-nfs for the NAS. - OpenEBS + LVM on
mocha(openebs-lvmpvis the only StorageClass there).
- Rook (Ceph) on
- External Secrets to fetch secrets from a remote store
- Vault (via bank-vaults) as secret store
- Authentik for SSO / forward-auth (
mocha) - SigNoz + OpenTelemetry Operator for metrics, logs and traces
- CrowdSec to filter traffic hitting the Ingress (
mocha) - Cloudflare Tunnels to expose services to the internet (
turing) - Volsync to back up PVCs with restic (
mocha) - Spegel to share images between nodes (
turing) - Reloader to restart workloads when a ConfigMap/Secret changes
- Cluster API (KubeVirt + Talos providers) to run guest clusters on
mocha
- Mocha : single bare-metal node hosted by OVH (128GB RAM, 8 CPU, 2x512GB NVMe). Production cluster, also the management plane for guest clusters.
- Turing : cluster made of small devices (ARM and x86) at home. Local hosting, storage (Rook + NAS) and testing.
cortado and the standalone kubevirt cluster have been retired — the old configs live in the git history.
- Americano : a bare host running podman quadlets, reconciled by Materia instead of ArgoCD. See
americano/README.mdfor the branch trick that makes it work from a subdirectory. external/: OTel collector and exporter units for machines outside the clusters (Proxmox hosts, theaffogatobackup box).
Instead of a second physical cluster for tests, mocha hosts Cluster API guest clusters running as KubeVirt VMs — plain Talos + Cilium clusters, one values file each.
Two reasons to keep them around:
- Network isolation: their pod/service CIDRs live inside the VMs, so they can overlap freely with the host cluster (and with each other).
- Configuration testing: same core components as production, disposable.
Creating, destroying and adopting them is documented in mocha/clusters/README.md. The chart doing the work is qjoly/kubevirt-capi-easy. For the story of the previous (Omni-managed) KubeVirt setup, see my article about Omni and Kubevirt.
To use this repository, you need to have the Omni CLI installed. You can find the installation instructions here.
Download the omniconfig file from the Omni instance and merge it with the one in your home directory.
omnictl config merge ./omniconfig.yamlThen, you can deploy the cluster based on the MachineClass you have configured.
cd mocha
omnictl cluster template sync -f template.yamlThis will create a new cluster based on the configuration you have set in the template.yaml file. You can download the kubeconfig file using the following command:
omnictl kubeconfig --cluster mochaRecurring operations (Vault unseal, guest cluster kubeconfig) are mise tasks:
mise tasks # list them
mise run vault:status| Workflow | What it does |
|---|---|
omni-template-sync.yaml |
Syncs the Omni cluster templates on every push to main (see below) |
materia-americano.yaml |
Republishes americano/ to the root of the americano branch for Materia |
tangled-mirror.yaml |
Mirrors the repo to tangled |
page.yaml |
Builds and publishes the mkdocs site (docs) |
spindle-image.yaml, abcdesktop-image.yaml, atcr-hold-image.yaml |
Build the container images for a few self-hosted apps |
The workflow .github/workflows/omni-template-sync.yaml runs omnictl cluster template sync automatically on every push to main that modifies files under turing/ or mocha/.
A detect job inspects the diff and builds a matrix of changed clusters. A parallel sync job then syncs each one independently — touching only mocha/ never triggers a turing sync, and a failure in one cluster does not block the other.
archives/ is intentionally excluded from CI sync. More details in docs/github-actions.md.
It authenticates against Omni using a service account (not a Kubernetes ServiceAccount — it is an Omni-native token-based credential).
Run this once from a machine where omnictl is already configured:
omnictl serviceaccount create github-actions --role Operator --ttl 8760hThe command prints an OMNI_ENDPOINT and an OMNI_SERVICE_ACCOUNT_KEY. Store both as GitHub Actions secrets:
| Secret name | Value |
|---|---|
OMNI_ENDPOINT |
Endpoint printed by the command |
OMNI_SERVICE_ACCOUNT_KEY |
Key printed by the command |
The
OMNI_SERVICE_ACCOUNT_KEYis shown only once — save it immediately.
Add them at: Repository → Settings → Secrets and variables → Actions → New repository secret
Example of kubeconfig file
apiVersion: v1
kind: Config
clusters:
- cluster:
server: https://omni.home.une-tasse-de.cafe:8100/
name: omni-mocha
contexts:
- context:
cluster: omni-mocha
namespace: default
user: omni-mocha-quentinj@une-pause-cafe.fr
name: omni-mocha
current-context: omni-mocha
users:
- name: omni-mocha-quentinj@une-pause-cafe.fr
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
args:
- oidc-login
- get-token
- --oidc-issuer-url=https://omni.home.une-tasse-de.cafe/oidc
- --oidc-client-id=native
- --oidc-extra-scope=cluster:mocha
command: kubectl
env: null
provideClusterInfo: false