Files
k8s-manifests/monitoring/argocd-app-kube-prometheus-stack.yaml
chemavxandClaude Opus 5 40205eddc3 monitoring: Fase 2, el kube-prometheus-stack pasa a ArgoCD
El chart era un release Helm gestionado a mano (helm upgrade) desde abril.
Ahora lo gestiona su propia Application con source Helm, version clavada a
83.2.0 (la que ya corria: esto es una adopcion, no una actualizacion).

Los valores se mudan de values-kube-prometheus-stack.yaml al valuesObject de
la Application, con sus comentarios: ahi esta el historial de los retoques a
mano que se recuperaron en julio (alerting, SSO de Authentik, token de
Telegram), y perderlo seria perder el mapa. Inline y no multi-source $values
porque ese montaje se auto-podo la Application de infisical el 2026-06-18, y
tener los valores en dos sitios es la deriva que veniamos a matar.

La adopcion se verifico ANTES de activar el auto-sync: aplicada sin
syncPolicy, ArgoCD daba 96/97 Synced sin haber sincronizado nunca. El que
faltaba era el Deployment de Grafana, y no por deriva: el render del subchart
no declara managed-by: Helm ni el restartedAt del podTemplate, asi que el
merge a 3 bandas del cliente los habria BORRADO (reinicio de Grafana + Helm
perdiendo la propiedad del objeto). Con ServerSideApply/ServerSideDiff ArgoCD
solo toca lo que declara: 97/97 Synced, cero operaciones de sync, cero pods
reiniciados. selfHeal probado con replicas 1->2 en kube-state-metrics,
revertido en 11s.

skipCrds: true a proposito: ArgoCD pasa --include-crds por defecto y los 10
CRD de monitoring.coreos.com no los gestiona nadie hoy. Contrapartida
documentada en el fichero: al subir de chart hay que aplicarlos a mano.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 20:22:27 +00:00

208 lines
11 KiB
YAML

# Fase 2 de meter monitoring/ bajo ArgoCD (2026-07-25): adoptar el chart.
#
# Hasta hoy el kube-prometheus-stack era un release Helm gestionado A MANO
# (helm upgrade desde este directorio) y sus ~40 manifiestos renderizados
# estaban volcados en git sin que nadie los aplicara: decoracion. Ahora la
# fuente de verdad es esta Application y git manda.
#
# EL NOMBRE IMPORTA: ArgoCD usa el nombre de la Application como Release.Name
# al renderizar. Tiene que ser "kube-prometheus-stack" o TODOS los objetos
# cambiarian de nombre (kube-prometheus-stack-grafana -> otro-grafana) y
# ArgoCD crearia un stack paralelo en vez de adoptar el que ya corre.
#
# skipCrds: true A PROPOSITO. ArgoCD pasa --include-crds por defecto, lo que
# le daria los 10 CRD de monitoring.coreos.com. Esos CRD NO los gestiona nadie
# hoy (no llevan label managed-by ni anotacion de release: Helm los instalo
# desde crds/ y no los rastrea). Dejarlos fuera evita que ArgoCD se pelee por
# ellos y evita el limite de 262144 bytes de last-applied en CRDs enormes.
# Contrapartida: al subir de version de chart, los CRD hay que actualizarlos
# a mano (kubectl apply -f del directorio crds/ del chart nuevo).
#
# La version va CLAVADA a 83.2.0, que es lo que corre. Esto es una adopcion,
# NO una actualizacion (el repo ya va por 87.x). Subir de version es otro dia
# y otro commit, para que si algo se rompe se sepa que lo rompio.
#
# Los valores van INLINE, no en un fichero aparte con multi-source $values:
# ese montaje se auto-podo la Application de infisical el 2026-06-18. Y tener
# los valores en dos sitios es justo la deriva que veniamos a matar.
#
# Verificado antes de adoptar: helm template con estos valores == lo desplegado
# campo a campo (las unicas diferencias eran nulls y ceros que el API server
# omite), y CERO objetos vivos con instance=kube-prometheus-stack que el chart
# no renderice, asi que prune no tiene nada que llevarse por delante.
#
# Para diffear a mano lo que ArgoCD va a aplicar:
# helm template kube-prometheus-stack prometheus-community/kube-prometheus-stack \
# --version 83.2.0 -n monitoring --skip-crds -f <(yq '.spec.source.helm.valuesObject' este-fichero)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: kube-prometheus-stack
namespace: argocd
annotations:
notifications.argoproj.io/subscribe.on-sync-failed.telegram: "5138407666"
notifications.argoproj.io/subscribe.on-health-degraded.telegram: "5138407666"
# Diff en el servidor, NO el merge a 3 bandas del cliente. Sin esto la
# adopcion NO era gratis: el render del subchart de grafana no declara
# managed-by: Helm ni el restartedAt del podTemplate, y el merge clasico
# los habria BORRADO -> Grafana se reinicia y Helm pierde la propiedad del
# Deployment (helm upgrade/uninstall empezarian a fallar por ownership).
# Con ServerSideDiff, ArgoCD solo mira los campos que declara y deja en paz
# los que puso otro. Medido: 96/97 Synced con el diff clasico, 97/97 con
# este. Va de la mano de ServerSideApply de abajo (uno diffea como el otro
# aplica; mezclarlos deja la app OutOfSync para siempre).
argocd.argoproj.io/compare-options: ServerSideDiff=true
spec:
project: default
source:
repoURL: https://prometheus-community.github.io/helm-charts
chart: kube-prometheus-stack
targetRevision: 83.2.0
helm:
skipCrds: true
valuesObject:
# rev 2 (2026-07-21): silenciadas 4 alertas que llevaban meses disparadas sin
# significar nada — ver kubeControllerManager/kubeScheduler/kubeProxy y
# defaultRules.disabled.
# rev 3 (2026-07-21): grafana.extraConfigmapMounts. El montaje del ConfigMap
# grafana-alerting (reglas + contact points + política → Telegram) se había
# añadido A MANO al Deployment y NO lo generaba el chart: sobrevivía solo por
# el three-way merge de Helm. Reconstruir el release desde este fichero se
# habría llevado por delante TODO el alerting, en silencio.
# rev 4 (2026-07-21): grafana.admin.existingSecret y FUERA adminPassword.
# El valor en git era "admin", que no abría nada: la cuenta admin local se
# configuró el 26-abr y no se ha usado desde entonces (se entra por Authentik).
# Los sidecars de dashboards y datasources SÍ la usaban y recibían 401 al
# intentar recargar por API. Ahora la contraseña es aleatoria, vive solo en el
# Secret grafana-admin (creado fuera del chart, nunca en git) y la cuenta queda
# como acceso de emergencia. Leerla:
# kubectl get secret grafana-admin -n monitoring \
# -o jsonpath='{.data.admin-password}' | base64 -d; echo
# rev 5 (2026-07-22): fuera la datasource Alertmanager. OJO: NO la apaga
# alertmanager.enabled=false — el chart la provisiona igual, apuntando a un
# servicio que no existe (error 500 al consultarla). El interruptor real es
# grafana.sidecar.datasources.alertmanager.enabled. Y quitarla del fichero de
# provisioning NO la borra de grafana.db: hay que provisionar el borrado con
# una directiva deleteDatasources de un solo uso (se hizo y se retiró).
# rev 7 (2026-07-22): recuperado el SSO de Authentik, roto desde hace ~15 días
# (último acceso de akadmin). Grafana ignoraba la cabecera X-authentik-username
# -> Authentik te dejaba pasar y Grafana te pedía credenciales igual. El bloque
# auth.proxy existía en el ConfigMap vivo en abril (está en el export de git),
# pero el chart NUNCA lo ha generado en ninguna de sus 6 revisiones, así que
# era otro retoque a mano que se perdió por el camino. Ahora va declarado.
# Junto con él, la anotación del middleware de Traefik: tampoco la generaba el
# chart, y sin ella Grafana queda expuesta sin Authentik delante.
# rev 6 (2026-07-22): grafana.envValueFrom. Mismo caso que rev 3, encontrado al
# auditar el Deployment contra el render: TELEGRAM_BOT_TOKEN y TELEGRAM_CHAT_ID
# estaban puestas A MANO y el chart no las generaba. El contact point de
# alerting usa ${TELEGRAM_BOT_TOKEN}: reconstruir el release desde cero habría
# dejado las alertas de Telegram mudas. Se declaran aquí sin tocar nada vivo.
# (CHAT_ID hoy no lo usa nadie —el chatid del contact point va literal— pero se
# deja para que el render coincida exactamente con lo desplegado.)
alertmanager:
enabled: false
defaultRules:
create: true
disabled:
PrometheusNotConnectedToAlertmanagers: true
rules:
alertmanager: false
grafana:
admin:
existingSecret: grafana-admin
envValueFrom:
TELEGRAM_BOT_TOKEN:
secretKeyRef:
key: TELEGRAM_BOT_TOKEN
name: grafana-telegram-infisical
TELEGRAM_CHAT_ID:
secretKeyRef:
key: TELEGRAM_CHAT_ID
name: grafana-telegram-infisical
extraConfigmapMounts:
- configMap: grafana-alerting
mountPath: /etc/grafana/provisioning/alerting
name: grafana-alerting
grafana.ini:
# SSO con Authentik. Traefik autentica en el borde con el middleware de
# abajo y reenvía X-authentik-username; esto es lo que hace que Grafana se
# fíe de esa cabecera y no vuelva a pedir credenciales. Sin este bloque el
# SSO queda a medias: Authentik te deja pasar y Grafana te enseña SU
# formulario. auto_sign_up crea el usuario (así nació akadmin).
# disable_login_form cierra el formulario local: por la web sólo se entra
# por Authentik. NO cierra la auth básica de la API, que es de donde cuelgan
# los dos sidecars y la puerta de emergencia.
#
# SI EL SSO SE CAE Y NO PUEDES ENTRAR POR LA WEB:
# 1. La API sigue abierta con la contraseña del secret grafana-admin:
# kubectl get secret grafana-admin -n monitoring \
# -o jsonpath='{.data.admin-password}' | base64 -d; echo
# y contra localhost:3000 dentro del pod, o por port-forward.
# 2. Para recuperar el formulario, poner disable_login_form: false aquí,
# commit y push: ArgoCD lo sincroniza solo. Tarda un minuto y no
# pierde nada. (Ya NO se hace con helm upgrade: manda ArgoCD.)
auth:
disable_login_form: true
auth.proxy:
auto_sign_up: true
enabled: true
header_name: X-authentik-username
header_property: username
server:
root_url: https://grafana.chemavx.xyz
ingress:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
# Sin esta anotación Grafana queda expuesta sin Authentik delante. Estaba
# puesta a mano en el Ingress vivo y el chart no la generaba: sobrevivía
# sólo por el three-way merge, como el montaje de alerting (rev 3).
traefik.ingress.kubernetes.io/router.middlewares: authentik-authentik-forward-auth@kubernetescrd
traefik.ingress.kubernetes.io/router.entrypoints: websecure
enabled: true
hosts:
- grafana.chemavx.xyz
ingressClassName: traefik
tls:
- hosts:
- grafana.chemavx.xyz
secretName: grafana-tls
persistence:
enabled: true
size: 5Gi
storageClassName: local-path
sidecar:
datasources:
alertmanager:
enabled: false
kubeControllerManager:
enabled: false
kubeProxy:
enabled: false
kubeScheduler:
enabled: false
prometheus:
prometheusSpec:
retention: 30d
storageSpec:
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: local-path
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
# Ver la nota de ServerSideDiff arriba: ArgoCD se declara un field manager
# mas y solo toca lo suyo, en vez de arrasar con lo que no aparece en el
# last-applied. Imprescindible al adoptar un release Helm ya vivo.
- ServerSideApply=true