diff --git a/alloy/values.yaml b/alloy/values.yaml index 1b25cac..264d2ba 100644 --- a/alloy/values.yaml +++ b/alloy/values.yaml @@ -30,6 +30,20 @@ alloy: # structurante — un agent par nœud, donc trois fois le coût mémoire. type: daemonset + # Le volume que consomme le montage `alloy.mounts.extra` ci-dessous : la + # racine Docker de ces machines, où aboutissent les liens de /var/log/pods. + volumes: + extra: + - name: docker-containers + hostPath: + path: /mnt/arcodange/docker/containers + # `Directory` (et non `DirectoryOrCreate`) EXPRÈS : si un jour un + # nœud n'a pas ce chemin, on veut que son agent refuse de démarrer + # et le DISE, plutôt que de monter un dossier vide et de rapporter + # zéro journal en se déclarant sain — le défaut exact qu'on vient + # de traverser. + type: Directory + alloy: # -- Le montage de /var/log : c'est par là que l'agent lit les journaux. # On tail des FICHIERS plutôt que d'interroger l'API du kubelet : sur trois @@ -37,9 +51,37 @@ alloy: # serveur d'API une charge qu'il n'a pas à porter. mounts: varlog: true - # k3s utilise containerd, pas Docker : ce montage-là ne servirait à rien. + # ⚠⚠ CE CLUSTER TOURNE SOUS DOCKER, PAS SOUS CONTAINERD — et son magasin + # d'images n'est pas là où le chart le cherche. Les deux faits ensemble + # rendent ce drapeau inutilisable. + # + # Mesuré le 2026-09-07 (`kubectl get nodes -o …containerRuntimeVersion`) : + # pi1 docker://29.1.3 + # pi2 docker://28.4.0 + # pi3 docker://27.4.0 + # + # Et sous /var/log/pods, les journaux ne sont PAS des fichiers : ce sont + # des liens symboliques vers la racine Docker, DÉPLACÉE sur un disque + # externe (identique sur pi1 et pi3, vérifié pod par pod) : + # + # /var/log/pods/__//0.log + # -> /mnt/arcodange/docker/containers//-json.log + # + # `dockercontainers: true` monterait `/var/lib/docker/containers`, qui + # n'existe pas ici. On monte donc la vraie racine, plus bas, en `extra`. dockercontainers: false + # ⚠ SANS CE MONTAGE, LA COLLECTE EST SILENCIEUSEMENT VIDE — et c'est le + # mode d'échec le plus traître de ce lot, parce que TOUT A L'AIR SAIN : + # les six composants d'Alloy se déclarent `healthy`, aucune erreur de + # poussée, Loki répond `ready`. Le seul relevé qui le dit est + # `loki_source_file_files_active_total = 0`, et l'export vide de + # `local.file_match`. `ls` montre les liens, `stat` échoue sur la cible. + extra: + - name: docker-containers + mountPath: /mnt/arcodange/docker/containers + readOnly: true + # ⚠ LA MÉMOIRE EST LA RESSOURCE RARE, ET UN DAEMONSET LA PREND TROIS FOIS. # Mesuré le 2026-09-07 avant tout déploiement : pi1 79 %, pi2 109 %, # pi3 58 % de leur mémoire ALLOUABLE. pi2 est en surengagement — c'est @@ -140,12 +182,17 @@ alloy: forward_to = [loki.process.journaux_de_pods.receiver] } - // ⚠ containerd n'écrit PAS du JSON de Docker : chaque ligne est - // « ». Sans `stage.cri`, l'horodatage - // stocké serait celui de la LECTURE et non celui de l'écriture — ce qui - // ruinerait précisément l'usage qui motive ce lot : dater une panne. + // ⚠⚠ `stage.docker`, PAS `stage.cri` — ces nœuds tournent sous Docker + // (mesuré : docker://29.1.3, 28.4.0, 27.4.0), donc chaque ligne est un + // objet JSON {"log":…,"stream":…,"time":…} et non le format CRI + // « ». + // + // Ce n'est pas cosmétique : sans le bon décodeur, l'horodatage stocké + // serait celui de la LECTURE et non celui de l'écriture, et les lignes + // arriveraient encore encapsulées dans leur JSON. Or dater une panne à + // la minute est PRÉCISÉMENT l'usage qui motive ce lot (tools#36). loki.process "journaux_de_pods" { - stage.cri {} + stage.docker {} forward_to = [loki.write.loki.receiver] } @@ -173,3 +220,30 @@ alloy: ingress: enabled: false + + # ⚠⚠ LE MÊME PIÈGE QUE LE SIDE-CAR DE LOKI, DEUXIÈME OCCURRENCE — et celle-ci + # est plus sournoise, parce qu'elle RESSEMBLE à un plafond. + # + # Le chart ajoute au pod un second conteneur, `config-reloader`, qui recharge + # Alloy quand sa ConfigMap change. Mesuré sur le premier déploiement, ses + # ressources amont sont : + # + # resources: + # requests: { cpu: 10m, memory: 50Mi } + # ← et RIEN d'autre + # + # Une requête SANS limite n'est pas un plafond : c'est une réservation. Le + # conteneur peut croître jusqu'à épuiser le nœud, et comme il partage le + # cgroup du pod, il emporte Alloy avec lui. Sur un DaemonSet, cela vaut sur + # les TROIS nœuds — pi2 compris, mesuré à 108 % de son allouable. + # + # ⚠ On ne peut pas l'éteindre : sans lui, un changement de configuration + # n'atteindrait l'agent qu'au prochain redémarrage du pod. On le PLAFONNE. + configReloader: + enabled: true + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + memory: 64Mi