Production-ready Kubernetes homelab running on Raspberry Pi cluster with GitOps-managed infrastructure, comprehensive monitoring, and centralized authentication.
- 4x Raspberry Pi nodes (home-hk1-pi[1-4])
- 1x NFS Storage Server (sd1)
- Network: 192.168.88.0/24
- Cluster Domain: home-hk1-cluster.orbb.li (via Tailscale)
- Kubernetes: K3s (lightweight Kubernetes)
- GitOps: ArgoCD Core (headless)
- Networking: Tailscale + Cloudflare Tunnels
- Identity: Keycloak with Google OAuth
- Monitoring: Prometheus + Loki + Grafana (OAuth integrated)
- Log Collection: Grafana Alloy
- Storage: NFS CSI Driver
homelab/
βββ README.md # This file
βββ .gitignore # Git ignore rules
βββ ansible/ # Infrastructure automation
β βββ 01-setup/ # Initial cluster setup
β β βββ k8s_configs/ # Kubernetes configurations
β βββ 02-install/ # GitOps deployments
β β βββ files/ # Jinja2 templates
β β β βββ helm-values/ # Helm chart values
β β β βββ *.yaml.j2 # OAuth, secrets templates
β β βββ *.yaml # Deployment playbooks
β βββ secrets/ # Sensitive data (gitignored)
βββ kubernetes/ # GitOps-managed resources
β βββ apps/ # Kubernetes manifests
β β βββ argocd/ # Self-hosting config
β β βββ cloudflared/ # Cloudflare Tunnel ingress controller (+ ingress namespace, public hostnames)
β β βββ traefik/ # Traefik: single in-cluster entry point behind the tunnel
β β βββ iam/ # Keycloak & identity
β β βββ observability/ # Monitoring namespace
β βββ gitops/ # ArgoCD Applications
β βββ apps/ # Application definitions
βββ docs/ # Documentation
βββ private/ # Submodule -> orbli/homelab-private (see below)
β βββ tailscale/acl.hujson # tailnet ACL, applied by GitHub Actions
βββ TODOs/ # Future projects
private/ is a git submodule pointing at orbli/homelab-private, a
private repo with the same top-level layout. It holds config that is not
secret but should not be world-readable, currently the Tailscale ACL
(member emails, host map, security notes). The workflows that apply it
stay in this public repo: a push to the private repo opens a PR here
that bumps the submodule pointer; tailscale-acl-test.yml dry-runs the
policy on that PR, and merging runs tailscale-acl-apply.yml, which
pushes it to the live tailnet. Both call the reusable
tailscale-acl-sync.yml, which checks out the private repo (via the
HOMELAB_PRIVATE_TOKEN secret) and runs Tailscale's gitops-pusher
against private/tailscale/acl.hujson.
Without access to the private repo, git submodule update here simply
fails; everything else in this repo works without it.
- Ansible installed locally
- kubectl configured with cluster access
- Access to cluster nodes
- Secrets file:
ansible/secrets/keycloak-secrets.yaml
-
Configure Ansible Inventory
cp ansible/inventory-example.yaml ansible/inventory.yaml # Edit inventory.yaml with your node details -
Bootstrap GitOps (ArgoCD)
cd ansible ansible-playbook 02-install/01-install-argocd.yaml ansible-playbook 02-install/02-argocd-self-hosting.yaml -
Deploy Core Services
# Networking (Cloudflare Tunnel β Traefik β apps): create the one Secret, apply the apps. # See kubernetes/manifests/cloudflared-namespace/README.md and docs/ingress-architecture.md kubectl apply -f kubernetes/argocd/cloudflared/ -f kubernetes/argocd/traefik/ # Identity Provider (Keycloak) ansible-playbook 02-install/04-deploy-keycloak.yaml # Monitoring Stack ansible-playbook 02-install/05-deploy-log-collection.yaml # Loki + Alloy ansible-playbook 02-install/06-config-grafana-oauth.yaml # OAuth Configuration ansible-playbook 02-install/07-deploy-prometheus-grafana.yaml
Check cluster status:
kubectl get nodes
kubectl get pods -A
ARGOCD_OPTS="--core" argocd app listAccess Services:
- Grafana: https://grafana-lab.orbb.li (OAuth via Keycloak)
- Keycloak: https://keycloak-lab.orbb.li/admin
- Prometheus: Internal at prometheus-kube-prometheus-prometheus:9090
Cleanup Playbooks:
ansible-playbook 02-install/cleanup-keycloak.yaml
ansible-playbook 02-install/cleanup-observability.yaml| Namespace | Purpose | Key Services | Management |
|---|---|---|---|
| gitops | ArgoCD Core | ArgoCD components | Self-hosted |
| iam | Identity Management | Keycloak, PostgreSQL | ArgoCD + Ansible |
| ingress | Network Access | Cloudflare Tunnel (edge), Traefik (routing) | ArgoCD |
| observability | Monitoring Stack | Prometheus, Loki, Grafana, Alloy | Helm + Ansible |
- Prometheus: System and application metrics (100Gi storage, 30-day retention)
- Node Exporters: Hardware and OS metrics from all nodes
- Kube State Metrics: Kubernetes object metrics
- Loki: Centralized log storage (50Gi, 30-day retention)
- Grafana Alloy: Kubernetes API-based log collection
- Log Sources: All namespaces and pods
- Grafana: OAuth-integrated dashboards
- Default Dashboards: Kubernetes cluster, node exporter, pod metrics
- Access: https://grafana-lab.orbb.li (SSO via Keycloak)
- Tailscale: Secure cluster access (all pods/services routable)
- Cloudflare Tunnels: Public service exposure
- Internal DNS: home-hk1-cluster.orbb.li domain
- Keycloak: Centralized authentication with Google OAuth
- Grafana OAuth: Role-based access (Admin/Editor/Viewer)
- Protocol Mappers: Proper role extraction in JWT tokens
- Ansible Templates: Jinja2 templates for secret generation
- GitOps Separation: Secrets managed by Ansible, infrastructure by ArgoCD
- Runtime Secrets: Kubernetes secrets for service credentials
- Separation of Concerns: ArgoCD manages infrastructure, Ansible manages secrets
- Declarative Deployments: All resources defined in Git
- Self-Hosted ArgoCD: Core mode for resource efficiency
- Simplified Authentication: No offline_access tokens
- Role Mapping: Automatic role assignment based on email
- Single Sign-On: Google OAuth via Keycloak
- Headless ArgoCD deployment (Core mode)
- Keycloak identity provider
- OAuth integration for Grafana
- Comprehensive monitoring stack
- Ingress: Cloudflare Tunnel ingress controller (edge) β Traefik (single in-cluster entry point) β see docs/ingress-architecture.md
- Certificate management (cert-manager)
- Backup solution (Velero)
- Sealed Secrets or External Secrets Operator
- Network policies for namespace isolation
- Automated testing with homelab-playbook-tester agent
- Create feature branch
- Test changes in dev environment
- Update documentation
- Submit pull request
Private repository - All rights reserved
For issues or questions, check the docs directory or review namespace-specific READMEs.
Last Updated: 2025-08-30 Infrastructure: K3s on Raspberry Pi cluster Architecture: GitOps with ArgoCD Core Status: Production