# ----------------------------------------------------------------------------- # Loki — binaire unique, stockage fichier, sur trois Raspberry Pi. # ----------------------------------------------------------------------------- # ⚠⚠ LES DÉFAUTS AMONT SONT ÉCRITS POUR UN CLUSTER DE SERVEURS, PAS POUR CECI. # Mesurés sur le chart 7.3.0 (`helm show values grafana/loki --version 7.3.0`) : # # deploymentMode SimpleScalable → read + write + backend, 3 jeux # chunksCache.enabled true → un memcached à … # chunksCache.allocatedMemory 8192 → … 8 Gio, sur un nœud qui en # alloue 5,6 (pi2) # resultsCache.enabled true → un second memcached # gateway.enabled true → un nginx de plus # lokiCanary.enabled true → un DaemonSet de plus # test.enabled true → un pod de test # loki.commonConfig.replication_factor 3 → 3 exemplaires de chaque flux # loki.storage.type s3 → un magasin objet qu'on n'a pas # loki.auth_enabled true → multi-locataire (en-tête # X-Scope-OrgID exigé à chaque appel) # # Laisser ces défauts, c'est exactement la deuxième propriété de tools#38 # violée : « la collecte ne doit pas faire tomber ce qu'elle observe ». Chaque # `false` ci-dessous est donc une décision, pas une omission. # ----------------------------------------------------------------------------- loki: # -- Un seul processus, une seule réplique. Le reste des modes est éteint plus bas. deploymentMode: SingleBinary loki: # Locataire unique : personne d'autre que le homelab n'écrit ici. Laisser # `true` obligerait chaque requête (et chaque source de données Grafana) à # porter un en-tête X-Scope-OrgID, pour aucun bénéfice. auth_enabled: false commonConfig: path_prefix: /var/loki # -- UNE réplique de chaque flux : il n'y a qu'un ingesteur. # Le défaut amont (3) ferait refuser toute écriture, faute de quorum. replication_factor: 1 storage: type: filesystem filesystem: chunks_directory: /var/loki/chunks rules_directory: /var/loki/rules # ⚠ PAS de `admin_api_directory` ici. Le chart l'accepte (il est dans # ses valeurs par défaut), mais le binaire OSS le REFUSE : # failed parsing config: field admin_api_directory not found in # type common.FilesystemConfig # C'est un champ de l'édition entreprise (GEL). Mesuré : le pod part en # CrashLoopBackOff, 3 redémarrages en 4 min. Le chart ne valide pas la # config qu'il écrit — seul le démarrage réel le dit. # ⚠ Le chart n'écrit AUCUN schéma par défaut (`schemaConfig: {}`) et refuse # de démarrer sans. tsdb + v13 est le couple courant de Loki 3.x. schemaConfig: configs: - from: "2026-09-07" store: tsdb object_store: filesystem schema: v13 index: prefix: loki_index_ period: 24h # ⚠⚠ UNE RÉTENTION QUI NE SUPPRIME RIEN EST UNE RÉTENTION QUI MENT. # `limits_config.retention_period` seul ne fait RIEN : c'est le compacteur # qui efface, et il ne le fait que si `retention_enabled` est vrai. Le # couple est indissociable — l'un sans l'autre laisse le volume grossir # jusqu'à saturation, en silence. compactor: working_directory: /var/loki/compactor retention_enabled: true delete_request_store: filesystem limits_config: # -- 30 jours. Voir `RETENTION` en fin de fichier pour la mesure. retention_period: 720h # Le défaut amont refuse tout échantillon de plus de 168 h. À la première # remontée d'un agent resté hors ligne, ces lignes seraient jetées. reject_old_samples: true reject_old_samples_max_age: 720h max_cache_freshness_per_query: 10m split_queries_by_interval: 15m query_timeout: 300s volume_enabled: true # Débit mesuré du cluster : ~305 Mio/jour TOUS pods confondus, soit # ~3,6 Kio/s. Les bornes amont (4 Mio/s par flux) sont hors sujet ici ; # on les laisse, elles ne mordent pas. allow_structured_metadata: true # Pas de vitrine : personne d'extérieur n'interroge ce Loki. analytics: reporting_enabled: false singleBinary: replicas: 1 persistence: enabled: true # ⚠ DEUX StorageClass portent le drapeau `(default)` sur ce cluster # (`local-path` ET `longhorn`, mesuré le 2026-09-07). Un PVC sans classe # explicite est donc un tirage au sort — et `local-path` ne survit pas au # déplacement du pod, ce qui viderait la mémoire qu'on vient de bâtir. # On NOMME la classe. storageClass: longhorn # 30 j × 305 Mio/j = 8,9 Gio BRUTS ; Loki compresse (facteur 5 à 10 sur # du journal), donc 0,9 à 1,8 Gio attendus. 10 Gi laisse 5 à 10× de marge # pour la croissance de kadans, sans immobiliser le disque. size: 10Gi resources: requests: cpu: 100m memory: 256Mi limits: # Pas de limite CPU : l'étranglement d'un compacteur est pire que sa # lenteur. La mémoire, elle, est PLAFONNÉE — c'est la ressource rare # (pi2 mesuré à 109 % de son allouable le 2026-09-07). memory: 512Mi # --------------------------------------------------------------------------- # Tout ce qui suit existe pour un déploiement distribué. Ici, chacun de ces # blocs est du poids mort sur des Raspberry Pi — on les éteint NOMMÉMENT # plutôt que par un `deploymentMode` qui « devrait » suffire. # --------------------------------------------------------------------------- write: { replicas: 0 } read: { replicas: 0 } backend: { replicas: 0 } ingester: { replicas: 0 } distributor: { replicas: 0 } querier: { replicas: 0 } queryFrontend: { replicas: 0 } queryScheduler: { replicas: 0 } indexGateway: { replicas: 0 } compactor: { replicas: 0 } bloomPlanner: { replicas: 0 } bloomBuilder: { replicas: 0 } bloomGateway: { replicas: 0 } patternIngester: { replicas: 0 } ruler: { replicas: 0 } overridesExporter: { replicas: 0 } # Les deux memcached. Le premier réclame 8 Gio à lui seul par défaut. chunksCache: enabled: false resultsCache: enabled: false # Un nginx devant un service que seul Grafana interroge, depuis le cluster. gateway: enabled: false # Un DaemonSet qui écrit des journaux pour vérifier qu'on lit les journaux : # trois pods de plus sur trois nœuds, pour une propriété que le sabotage de # la PR démontre mieux (écrire une ligne, tuer le pod, la relire). lokiCanary: enabled: false test: enabled: false # Le chart sait déployer SON PROPRE MinIO. On en a déjà un, et on n'en veut # pas ici : le stockage est le disque. minio: enabled: false monitoring: dashboards: enabled: false rules: enabled: false serviceMonitor: enabled: false metricsInstance: enabled: false selfMonitoring: enabled: false grafanaAgent: installOperator: false # Pas d'opérateur de déploiement progressif pour une réplique unique. rollout_operator: enabled: false # ⚠ UN SECOND CONTENEUR SANS PLAFOND ANNULE LE PLAFOND DU PREMIER. # Le chart ajoute au pod un side-car `loki-sc-rules` (kiwigrid/k8s-sidecar) # qui surveille des ConfigMaps de règles d'alerte. Mesuré sur le premier # déploiement : il arrive avec `resources: {}` — ni requête ni limite — dans # un pod posé sur pi2, le nœud à 108 % de son allouable. On l'éteint : le # `ruler` est à 0 réplique, il n'y a aucune règle à ingérer, donc ce side-car # surveille des ConfigMaps qui n'existent pas. sidecar: rules: enabled: false # ----------------------------------------------------------------------------- # RETENTION — l'arbitrage, et la mesure qui le porte # ----------------------------------------------------------------------------- # Mesuré le 2026-09-07 sur ce cluster, par l'API (donc ce que Loki ingérerait) : # # fenêtre de 10 min, tous pods : 2 182 015 octets # fenêtre de 1 h, tous pods : 7 897 505 octets # # Les deux instruments ne s'accordent pas (l'heure ne vaut que 0,60 fois six # fois les dix minutes) — et le désaccord est LE résultat. Par conteneur, le # rapport 1 h / 10 min vaut ~6 partout (débit stable) SAUF : # # kube-system/traefik ratio 1,18 → la fenêtre d'une heure est TRONQUÉE # tools/clickhouse-0 ratio 3,98 → tronquée aussi # # Vérifié directement, en demandant à chaque journal jusqu'où il remonte : # # traefik pod démarré il y a 12 j — journal remontant à 10 MINUTES # clickhouse pod démarré il y a 8 j — journal remontant à 2 MINUTES # # Autrement dit, les deux composants les plus bavards du cluster gardent entre # deux et dix minutes d'histoire. C'est l'issue tools#38 en un chiffre. # # Estimation corrigée (max(1 h, 10 min × 6) par conteneur, pour ne pas hériter # de la troncature) : 13 333 645 octets/h = 305 Mio/jour bruts. # # 30 j bruts 8,94 Gio # 30 j compressés (facteur 5) 1,79 Gio # 30 j compressés (facteur 10) 0,89 Gio # # POURQUOI 30 JOURS et pas 7 : les deux pannes qui motivent ce lot ont duré des # SEMAINES avant d'être vues (la mise à l'abri de kadans#1033) ou trois jours # (tools#36). Une rétention de 7 jours aurait perdu le début des deux. 30 jours # couvre le délai réel entre « ça casse » et « quelqu'un s'en aperçoit », et # coûte 1 à 2 Gio — sur 99 Gio libres au plus serré des trois nœuds Longhorn. # # ⚠ CE QUI RENDRAIT CE CHIFFRE FAUX : la mesure est une photo d'un mardi # après-midi. Elle ne dit rien d'un pod qui part en boucle d'erreur, cas où le # débit d'un seul conteneur peut dépasser à lui seul tout le reste du cluster. # La marge de 5 à 10× est là pour ça, pas pour la croissance ordinaire. # -----------------------------------------------------------------------------