❯ apps · Running

Retirer un second dashboard cassé pour un centre de contrôle statique fait main Retiring a Broken Second Dashboard for a Hand-Built Static Control Center

Le homelab avait deux dashboards qui faisaient le même travail, dont un chroniquement cassé. La solution n'était pas un meilleur outil d'auto-découverte — c'était de le supprimer et de construire à la main un dashboard statique sombre, servi par ConfigMap, sans pièce mobile, pensé pour un écran 4K. The homelab had two dashboards doing the same job, one of them chronically broken. The fix wasn't a better auto-discovery tool — it was deleting it and hand-rolling a static, ConfigMap-served dark dashboard with zero moving parts, sized for a 4K wall display.

· 7 min de lecture 7 min read ·
dashboarduxconfigmaptraefikapps
🇬🇧 Read this article in English

Le problème : deux dashboards, un seul qui marche

L’article Dashboard du cluster avec Homepage + Glances documentait Homepage + Glances comme point d’entrée « auto-découvert » du homelab. En pratique, ce dashboard cohabitait depuis des mois avec un second hub personnel — celui qui sert cet article — et Homepage était devenu peu fiable et de moins en moins consulté : services mal découverts, widgets qui timeoutent, une YAML de configuration qu’il fallait rouvrir à chaque nouvelle app pour retrouver la bonne syntaxe.

Plutôt que de le réparer une énième fois, la décision a été plus radicale : décommission complète. Aucun remplacement « meilleur outil d’auto-découverte » — juste sa suppression pure et simple du cluster.

Le choix : statique plutôt que dynamique

Le hub qui reste tourne sur un principe volontairement pauvre : un unique index.html stocké dans une ConfigMap Kubernetes (hub-static-html, namespace yb-personal), servi par un simple nginx:1.27-alpine monté en volume :

# yb-personal/deploy-hub-static.yaml (extrait)
containers:
- image: nginx:1.27-alpine
  ports:
  - containerPort: 80
  volumeMounts:
  - mountPath: /usr/share/nginx/html
    name: html-volume
volumes:
- configMap:
    name: hub-static-html
  name: html-volume

Aucune dépendance runtime, aucun pod qui peut planter faute de connexion à une API tierce, aucun DSL YAML à apprendre pour ajouter un service. Éditer le hub, c’est modifier un fichier HTML dans le repo GitOps, commit, et laisser ArgoCD synchroniser — le même geste que pour n’importe quel autre composant du cluster. Pour un dashboard à usage strictement personnel, la « découverte automatique » de Homepage résolvait un problème que je n’avais pas vraiment : la liste des services change une fois toutes les deux semaines, pas toutes les heures.

Design system « Pro Ops »

La palette part d’un fond quasi-noir plutôt que du classique thème sombre à dégradé : #0a0e14 en canvas, #10151d pour les surfaces, bordures #1f2733. Un seul accent — un teal #2dd4bf — et les trois couleurs sémantiques classiques réservées exclusivement aux statuts : vert #3fb950 (ok), ambre #d29922 (warn), rouge #f85149 (err). Deux polices : Inter pour l’interface, JetBrains Mono pour tout ce qui est valeur, IP ou métrique — la distinction typographique aide à repérer d’un coup d’œil ce qui est donnée brute versus ce qui est libellé.

Le layout est pensé pour un mur d’écran, pas pour un laptop. Les breakpoints Tailwind par défaut s’arrêtent à 2xl (1536px) ; j’en ai ajouté deux au-delà :

screens: {
  '3xl': '2200px',
  '4xl': '2800px',
},

Le catalogue de services est un layout masonry en colonnes CSS, qui s’élargit avec l’écran : une colonne en mobile, jusqu’à six en 4K.

<main class="columns-1 md:columns-2 xl:columns-3 2xl:columns-4 3xl:columns-5 4xl:columns-6 gap-5 2xl:gap-6">

Le conteneur principal suit la même logique (max-w-[2560px], 4xl:max-w-[3360px]) : sur un écran 4K accroché au mur, le hub utilise vraiment la largeur disponible au lieu de rester figé dans une colonne centrale étroite.

Le seul bout dynamique : un proxy API pour le vivant

Tout le HTML est statique — sauf les quelques widgets qui ont besoin de données en temps réel (état des nœuds, à terme cpu/mem live). Plutôt que de dupliquer une API dans le hub lui-même, ces appels sont routés vers le service homelab-admin déjà existant, via une IngressRoute Traefik dédiée :

# homelab-admin/ingressroute-hub-proxy.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: hub-admin-proxy
  namespace: homelab-admin
spec:
  routes:
    - match: Host(`hub.olig-homelab-2025.win`) && PathPrefix(`/admin/api`)
      kind: Rule
      priority: 1000
      services:
        - name: homelab-admin
          namespace: homelab-admin
          port: 8080

Le détail qui compte ici, c’est la priority: 1000. L’Ingress Kubernetes standard du hub route déjà / vers hub-static-svc. Sans priorité explicite plus élevée sur la règle /admin/api, Traefik pourrait laisser la règle la plus large (le préfixe racine) intercepter des requêtes qui devraient partir vers homelab-admin. Une priorité forcée à 1000 lève toute ambiguïté : le préfixe API gagne toujours, peu importe l’ordre de déclaration des deux ressources dans le cluster.

Sections ajoutées au fil de l’eau

Le hub n’a pas été livré figé un jour puis oublié — il reflète l’infra au fur et à mesure que celle-ci change. Le déploiement du pipeline de scan documentaire (Paperless-ngx, Paperless-AI, scanservjs) a immédiatement donné lieu à l’ajout d’une section « Scan & OCR » dans le catalogue. Le lendemain, une fois la décommission de Homepage actée, son lien dans la section « Sites & Apps » a été retiré à son tour — deux commits distincts, chacun réagissant à un changement réel de l’infra plutôt qu’anticipant un plan figé à l’avance.

C’est la différence pratique entre un dashboard « intelligent » qui devrait en théorie suivre tout seul, et un fichier statique versionné : ce dernier ne suit rien automatiquement, mais chaque changement est un diff Git lisible, daté, et volontaire.

Leçon transférable

Pour un dashboard personnel à faible fréquence de changement, un fichier HTML statique versionné dans Git bat presque toujours un outil « intelligent » de plus à opérer. Moins de surface de panne — pas de pod supplémentaire qui peut planter, pas de découverte automatique qui se trompe de service. Un historique Git lisible plutôt qu’un état caché dans une base de config. Et le vrai coût, le temps passé à éditer du HTML à la main, reste marginal comparé au temps qu’aurait coûté un nouveau débogage de Homepage.

Le hub tourne aujourd’hui derrière hub.olig-homelab-2025.win, GitOps via ArgoCD comme le reste du cluster, avec homelab-admin comme unique dépendance dynamique. Pas de dashboard de plus — un dashboard de moins, et celui qui reste est plus simple que les deux qu’il remplace.

dashboarduxconfigmaptraefikapps