Ces nœuds tournent sous Docker, et leur racine est ailleurs — la collecte lisait le vide
Helm Charts / Detect changed charts (pull_request) Successful in 41s
Helm Charts / Library charts tool (pull_request) Skipped
Helm Charts / Application charts crowdsec (pull_request) Skipped
Helm Charts / Application charts pgcat (pull_request) Skipped
Helm Charts / Application charts prometheus (pull_request) Skipped
Helm Charts / Application charts redis (pull_request) Skipped
Helm Charts / Application charts alloy (pull_request) Successful in 14s
Helm Charts / Application charts chart (pull_request) Successful in 36s
Helm Charts / Application charts loki (pull_request) Successful in 51s
Helm Charts / Application charts grafana (pull_request) Successful in 56s
Helm Charts / Application charts hashicorp-vault (pull_request) Skipped
Helm Charts / Application charts minio (pull_request) Skipped
Helm Charts / Application charts pgbouncer (pull_request) Skipped
Helm Charts / Detect changed charts (pull_request) Successful in 41s
Helm Charts / Library charts tool (pull_request) Skipped
Helm Charts / Application charts crowdsec (pull_request) Skipped
Helm Charts / Application charts pgcat (pull_request) Skipped
Helm Charts / Application charts prometheus (pull_request) Skipped
Helm Charts / Application charts redis (pull_request) Skipped
Helm Charts / Application charts alloy (pull_request) Successful in 14s
Helm Charts / Application charts chart (pull_request) Successful in 36s
Helm Charts / Application charts loki (pull_request) Successful in 51s
Helm Charts / Application charts grafana (pull_request) Successful in 56s
Helm Charts / Application charts hashicorp-vault (pull_request) Skipped
Helm Charts / Application charts minio (pull_request) Skipped
Helm Charts / Application charts pgbouncer (pull_request) Skipped
Trois faits mesurés au déploiement, qu'aucune lecture du chart n'aurait donnés.
1. LE CLUSTER TOURNE SOUS DOCKER, PAS SOUS CONTAINERD.
`kubectl get nodes -o …containerRuntimeVersion` :
pi1 docker://29.1.3
pi2 docker://28.4.0
pi3 docker://27.4.0
Le commentaire du premier jet affirmait le contraire. Il était faux.
2. LES JOURNAUX NE SONT PAS SOUS /var/log — CE SONT DES LIENS.
/var/log/pods/<ns>_<pod>_<uid>/<conteneur>/0.log
-> /mnt/arcodange/docker/containers/<id>/<id>-json.log
La racine Docker est déplacée sur un disque externe. Monter /var/log donne
les liens et PAS leurs cibles : `ls` les montre, `stat` échoue dessus. Le
drapeau `dockercontainers` du chart monterait /var/lib/docker/containers,
qui n'existe pas ici. On monte la vraie racine, en lecture seule.
Chemin vérifié identique sur pi1 et pi3, pod par pod.
3. LE FORMAT EST DU JSON DOCKER, DONC `stage.docker`, PAS `stage.cri`.
Avec le mauvais décodeur, l'horodatage stocké serait celui de la LECTURE et
non celui de l'écriture — or dater une panne à la minute est précisément
l'usage qui motive ce lot (tools#36).
⚠⚠ CE QUI REND CE DÉFAUT DANGEREUX : IL SE PRÉSENTE COMME UNE SANTÉ PARFAITE.
Les six composants d'Alloy se déclaraient `healthy`, aucune erreur de poussée,
Loki répondait `ready`, les trois agents étaient 2/2 Running. La seule chose
qui parlait était `loki_source_file_files_active_total = 0` et l'export vide de
`local.file_match`. Une pile de journaux qui rassure sans rien garder : le
défaut même que l'issue #38 demande de ne pas reproduire.
Le hostPath est en `type: Directory` et non `DirectoryOrCreate`, exprès — si un
nœud n'a pas ce chemin, son agent doit refuser de démarrer et le DIRE, plutôt
que de monter un dossier vide et de rapporter zéro en se déclarant sain.
Corrige aussi le second conteneur non plafonné, jumeau de celui de Loki :
`config-reloader` arrive avec une REQUÊTE de 50Mi et AUCUNE limite. Une requête
sans limite n'est pas un plafond, c'est une réservation — et sur un DaemonSet
cela vaut sur les trois nœuds. On ne peut pas l'éteindre sans perdre le
rechargement à chaud : on le plafonne (32Mi / 64Mi).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
+80
-6
@@ -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/<ns>_<pod>_<uid>/<conteneur>/0.log
|
||||
# -> /mnt/arcodange/docker/containers/<id>/<id>-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
|
||||
// « <horodatage> <flux> <F|P> <message> ». 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
|
||||
// « <horodatage> <flux> <F|P> <message> ».
|
||||
//
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user