HA runs with hostNetwork on roger-nucbox-evo-x2 while Traefik runs on the raspberrypi node, so requests arrive at HA from 10.88.20.11. The previous trusted_proxies entry (10.88.88.0/24) did not include this address, causing HA to reject X-Forwarded-For and return 400 on every ingress request.
K3s Cluster Deployment
Aquest repositori conté les configuracions de Kubernetes per desplegar diverses aplicacions en un clúster K3s. Totes les aplicacions s'executen en l'entorn local amb accés a través del domini rogi.casa.
📋 Visió General
Aquest clúster K3s gestiona els següents serveis:
- Glance - Dashboard personal
- Pi-hole - Bloqueig de publicitat a nivell de xarxa
- LiteLLM - Proxy per a models de llenguatge
- Gitea - Servidor Git self-hosted
- Home Assistant - Automatització de la llar
- Jellyfin - Servidor multimèdia
- n8n - Automatització de fluxos de treball
- OpenWebUI - Interfície web per a LLMs
- Phoenix - Observabilitat per a aplicacions d'IA
- Vaultwarden - Gestor de contrasenyes
- qBittorrent - Client de torrents
- Minecraft Server - Servidor de Minecraft
- Monitoring - Prometheus i Grafana per a monitorització
🏗️ Estructura del Repositori
.
├── README.md # Aquest fitxer
├── argocd-bootstrap.yaml # App-of-apps: llavor per a ArgoCD (aplicar 1 cop)
├── <aplicació>/ # Cada aplicació té el seu directori
│ ├── deployment.yaml # Definició del Deployment
│ ├── service.yaml # Definició del Service
│ ├── ingress.yaml # Configuració d'Ingress de l'aplicació
│ ├── namespace.yaml # Namespace dedicat (opcional)
│ ├── configmap.yaml # ConfigMaps (opcional)
│ └── pvc.yaml # PersistentVolumeClaims (opcional)
├── argocd/ # ArgoCD
│ ├── ingress.yaml # Ingress d'ArgoCD
│ ├── apps/ # Applications + AppProject declaratius
│ └── gen-apps.sh # Genera argocd/apps/* i argocd-bootstrap.yaml
└── nas/ # Servei extern per al NAS
├── transport.yaml # ServersTransport de Traefik
└── ingress.yaml # Ingress del NAS
Nota: Cada aplicació té el seu propi
ingress.yamldins del seu directori. Ja no hi ha capingress.yamlcentralitzat a l'arrel.
🚀 Desplegament
Prerequisits
- K3s instal·lat: El clúster K3s ha d'estar funcionant
- kubectl configurat: Accés al clúster amb
kubectl - cert-manager: Per a certificats SSL (utilitza Cloudflare Origin Issuer)
- DNS configurat: Els dominis
*.rogi.casahan d'apuntar al clúster
Desplegar una Aplicació
Per desplegar una aplicació específica:
# Desplegar una aplicació completa (tots els recursos del directori)
kubectl apply -f <aplicació>/
# Desplegar un recurs específic
kubectl apply -f <aplicació>/<fitxer>.yaml
Desplegar Tot el Clúster
La forma recomanada és deixar que ArgoCD sincronitzi el repo (veure secció ArgoCD (GitOps)). Per a un desplegament manual sense ArgoCD:
# Desplegar totes les aplicacions
for dir in */; do
kubectl apply -f "$dir"
done
# O aplicar recursos globals primer (opcional)
kubectl apply -f nas/
Eliminar una Aplicació
# Eliminar tots els recursos d'una aplicació
kubectl delete -f <aplicació>/
# Eliminar un recurs específic
kubectl delete -f <aplicació>/<fitxer>.yaml
🌐 Ingress i Networking
Configuració d'Ingress per Aplicació
Cada aplicació té el seu propi fitxer ingress.yaml dins del seu directori, seguint el model de pihole/ingress.yaml. Característiques:
- Traefik: Controlador per defecte de K3s (
ingressClassName: traefik) - TLS/SSL: Certificats per host gestionats per cert-manager amb el cluster-issuer
letsencrypt-prod - Secret per aplicació: Cada ingress té el seu propi
<aplicació>-tls - Namespace dedicat: Cada ingress pertany al namespace de la seva aplicació
Exemple (pihole/ingress.yaml):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: pihole
namespace: pihole
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: traefik
tls:
- hosts:
- pihole.rogi.casa
secretName: pihole-tls
rules:
- host: pihole.rogi.casa
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: pihole-web
port:
number: 80
🐙 ArgoCD (GitOps)
Totes les aplicacions del repo es despleguen de forma declarativa amb ArgoCD. Hi ha un Application per cada directori d'aplicació, agrupades sota un AppProject anomenat k3s-cluster.
Estructura
argocd/apps/project.yaml—AppProjectk3s-cluster(sync-wave -1).argocd/apps/<app>.yaml— unApplicationper aplicació (sync-wave 0), cadascun apunta al seu directori del repo.argocd-bootstrap.yaml—Application"app-of-apps" que sincronitza tot el directoriargocd/apps/. És l'únic recurs que cal aplicar a mà.argocd/gen-apps.sh— regenera tots els fitxers anteriors a partir d'una llista d'aplicacions.
Flux
- El
AppProjecti tots elsApplicationestan versionats aargocd/apps/. - L'app
k3s-cluster-root(aargocd-bootstrap.yaml) llegeixargocd/apps/i crea/actualitza el projecte i totes les applications. - Cada
Applicationsincronitza el seu directori (ex:pihole/) cap al seu namespace, ambpruneiselfHealactivats.
Bootstrap (una sola vegada)
Prerequisits:
- ArgoCD instal·lat al clúster (namespace
argocd). cert-managerinstal·lat (veurecert-manager/install.sh) — elClusterIssuerdepèn dels seus CRDs.- El repo registrat a ArgoCD (
Settings → Repositories). Si el repo és públic a GitHub, l'HTTPS funciona sense credencials.
Llançar la llavor:
kubectl apply -f argocd-bootstrap.yaml
A partir d'aquí ArgoCD crea el projecte k3s-cluster, totes les Application i les sincronitza automàticament. Qualsevol canvi al repo es propaga sol (self-heal).
Recrear el clúster des de zero
# 1. Instal·lar K3s
# 2. Instal·lar ArgoCD
# 3. Instal·lar cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
kubectl wait --for=condition=available --timeout=120s deployment/cert-manager -n cert-manager
# 4. Registrar el repo a ArgoCD (o deixar-lo públic)
# 5. Llançar la llavor
kubectl apply -f argocd-bootstrap.yaml
Afegir o treure una aplicació
- Crea/esborra el directori de l'aplicació.
- Afegeix/treu la línia corresponent a l'array
APPSdeargocd/gen-apps.shamb el formatname|namespace|path|recurse|validate. - Executa
./argocd/gen-apps.shper regenerar els manifests. - Fes commit i push; ArgoCD ho sincronitza sol.
Notes
- Els
Application/AppProjectpertanyen al namespaceargocd(recursos propis d'ArgoCD). - L'app
argocdtérecurse: falsesobre el directoriargocd/per gestionar nomésingress.yamli no els seus propis manifests sotaargocd/apps/. - L'app
phoenixusaValidate=falseper tolerar el CRDServiceMonitorsi el Prometheus Operator encara no és instal·lat. - Els secrets que no estan al repo (ex:
gitea-registryper agym-tracker) s'han de crear manualment al seu namespace; Argo no els gestiona ni els esborra.
💾 Persistència de Dades
Les aplicacions que necessiten emmagatzematge persistent utilitzen:
- PersistentVolumeClaims (PVC): Per a volums dinàmics
- ConfigMaps: Per a fitxers de configuració
- StatefulSets: Per a aplicacions que requereixen identitat persistent (ex: bases de dades)
Exemple: Minecraft utilitza pvc.yaml i ss.yaml (StatefulSet).
📊 Monitorització
El directori monitoring/ conté un stack complet de monitorització:
- Prometheus: Recollida de mètriques
- Grafana: Visualització de dades
- RBAC: Permisos per a Prometheus
- ServiceMonitors: Descobriment automàtic de serveis (ex: Phoenix)
Accés:
- Grafana: Configurat a través de l'Ingress principal
- Datasources preconfigurats per connectar amb Prometheus
🔧 Gestió de Configuracions
ConfigMaps
Les aplicacions utilitzen ConfigMaps per gestionar configuracions:
# Veure ConfigMaps
kubectl get configmaps -n <namespace>
# Editar un ConfigMap
kubectl edit configmap <nom> -n <namespace>
Secrets
Els secrets es gestionen de forma segura:
# Crear un secret
kubectl create secret generic <nom> --from-literal=key=value -n <namespace>
# Veure secrets (encoded)
kubectl get secrets -n <namespace>
Secret per al Registre de Gitea
Per utilitzar imatges del registre privat de Gitea, cal crear un secret de tipus docker-registry:
# Crear el secret per al registre de Gitea (namespace default)
kubectl create secret docker-registry gitea-registry \
--docker-server=gitea.rogi.casa \
--docker-username=<teu-usuari-gitea> \
--docker-password=<teu-password-o-token> \
--docker-email=<teu-email>
# Si l'aplicació està en un namespace específic, afegeix -n <namespace>
kubectl create secret docker-registry gitea-registry \
--docker-server=gitea.rogi.casa \
--docker-username=<teu-usuari-gitea> \
--docker-password=<teu-password-o-token> \
--docker-email=<teu-email> \
-n <namespace>
Nota: És recomanable utilitzar un token d'accés personal de Gitea en lloc de la contrasenya. Pots generar-lo a: Gitea > Settings > Applications > Generate New Token.
Les aplicacions que utilitzen imatges del registre de Gitea (com gym-tracker) han d'incloure imagePullSecrets al seu deployment:
spec:
imagePullSecrets:
- name: gitea-registry
containers:
- name: app
image: gitea.rogi.casa/user/repo/image:tag
🔍 Troubleshooting
Verificar l'estat dels Pods
# Veure tots els pods
kubectl get pods --all-namespaces
# Descriure un pod amb problemes
kubectl describe pod <nom-pod> -n <namespace>
# Veure logs
kubectl logs <nom-pod> -n <namespace>
kubectl logs <nom-pod> -n <namespace> --previous # Logs del contenidor anterior
Verificar Serveis i Ingress
# Veure serveis
kubectl get services --all-namespaces
# Veure configuració d'Ingress
kubectl get ingress --all-namespaces
kubectl describe ingress <nom> -n <namespace>
Verificar Volums
# Veure PVCs
kubectl get pvc --all-namespaces
# Veure PVs
kubectl get pv
📝 Bones Pràctiques
- Namespaces: Totes les aplicacions tenen un namespace dedicat; cap queda al namespace
default - Labels: Tots els recursos utilitzen labels consistents per facilitar la gestió
- Resources Limits: Configura limits de CPU/memòria per evitar overconsumption
- Health Checks: Implementa liveness i readiness probes quan sigui possible
- Backup: Fes còpies de seguretat regulars dels PVCs i ConfigMaps crítics
🔄 Actualitzacions
Per actualitzar una aplicació:
# Editar el fitxer YAML amb la nova versió de la imatge
vim <aplicació>/deployment.yaml
# Aplicar els canvis
kubectl apply -f <aplicació>/deployment.yaml
# Verificar el rollout
kubectl rollout status deployment/<nom> -n <namespace>
# Revertir si cal
kubectl rollout undo deployment/<nom> -n <namespace>
🌟 Serveis Externs
NAS
El fitxer nas/nas.yaml configura un servei extern que apunta al NAS local (10.88.88.238:5000) sense desplegar pods dins del clúster. L'Ingress corresponent és a nas/ingress.yaml.