모니터링 드리프트 정리 (Grafana no-data + argocd metrics + promtail/loki SSOT 정합)

요약Grafana 'AlgoSu Service Debug' 대시보드의 3개 패널(Container CPU/Memory, Loki 로그 2종)이 라이브에서 no-data. 라이브 진단으로 두 근본 원인 확정: (A) Prometheus에 kubelet/cAdvisor scrape_config 부재 → container_* 메트릭 전체 미수집(0 시리즈). (B) 라이브 promtail이 service 라벨을 부여하는데 대시보드가 없는 pod 라벨을 참조 → 로그 패널 항상 0. 배포 SSOT인 aether-gitops에서 PR #8(+0a7156d) 머지·ArgoCD Synced·라이브 3종 검증 통과(container_* 75 시리즈, 로그 패널 스트림 표출)로 라이브 해결. 본 스프린트는 비배포 참조 미러 infra/k3s/monitoring을 라이브 최종 형태에 정합: prometheus-config에 kubernetes-cadvisor/nodes job(apiserver proxy 경유)+SA/ClusterRole/CRB, 대시보드 $service 변수값 Loki service 라벨 기준 통일·Loki 패널 service= 셀렉터·job=~ 12곳, promtail은 service 라벨 정합(Critic R1 P2). 게이트 check-grafana-metrics 통과. Critic R1 [P2](미러 promtail service 라벨 부재)→R2 CLEAN. 스프린트 진행 중 동일 모니터링 드리프트 정리가 확장: AlgoSu #414(argocd-metrics/argocd-server-metrics scrape job + revisionHistoryLimit 10→5)·#415(promtail kubernetes_sd→static_configs SSOT 완전 교체 + loki allow_structured_metadata false→true 짝 정합), 서버 aether-gitops #8(no-data 라이브)·#9(CB 패널 stale 교정 + revisionHistoryLimit, ReplicaSet 126→73)·#10(cloudflared-monitoring GitOps 편입)·curl-test pod 정리 병렬 완료.

날짜
영향도높음

목표

  • 라이브 Grafana "AlgoSu Service Debug" 대시보드 3개 패널(Container CPU/Memory, Loki 로그 2종) no-data 근본 원인 규명 + 수정.
  • 라이브(aether-gitops) 수정 완료 후, 비배포 참조 미러 infra/k3s/monitoring을 라이브 최종 형태에 정합해 드리프트 차단.

배경

  • 사용자가 라이브 대시보드에서 CPU/Memory/Loki 3개 패널 no-data 보고. infra/k3s는 비배포 참조 미러이고 배포 SSOT는 aether-gitops(Sprint 232 확정) → 정적 매니페스트로 단정 금지, 라이브 진단 선행([[feedback-source-vs-live-drift]]).

근본 원인 (라이브 진단)

  • (A) cAdvisor 메트릭 미수집: container_cpu_usage_seconds_total namespace 무관 전체 0 시리즈. 라이브 Prometheus도 전부 static_configs 방식이고 kubelet/cAdvisor/role:node 타겟 부재. kube-state-metrics는 kube_* 객체 상태만 제공(컨테이너 리소스 사용량 ≠). → 데이터 소스(수집) 결함.
  • (B) Loki 라벨 모델 불일치: 로그는 정상 수집({namespace="algosu"} 6 streams). 라이브 promtail은 service 라벨 부여(값: gateway/submission/problem/identity/ai-analysis/github-worker)인데 대시보드 셀렉터가 없는 pod 라벨 참조 → 항상 0. 변수값(submission-service)과 service 라벨값(submission)도 불일치. → 대시보드 쿼리 결함.

핵심 결정

  1. 라이브 우선 수정(aether-gitops PR #8): (A) kubernetes-cadvisor/kubernetes-nodes job(apiserver proxy /api/v1/nodes/${node}/proxy/metrics[/cadvisor]) + prometheus SA/ClusterRole(nodes/nodes-metrics/nodes-proxy + nonResourceURLs)/CRB. (B) 대시보드 $service 변수값을 Loki service 라벨값으로 통일하고 패널별 셀렉터 매핑: Loki service="${service}", Prometheus job=~"${service}.*"(submission→submission-service prefix 매칭), cAdvisor/KSM pod=~"${service}.*" 유지.
  2. id19 Error Logs 죽은 분기 차단(Critic, 라이브 PR): 서버 초안 |= "error" | json | level=~"error|fatal|CRITICAL"는 Sprint 231이 제거한 죽은 분기 재도입(promtail이 level 라벨 승격→json 재파싱 불필요·level_extracted 충돌, fatal/CRITICAL 미출력, |= 본문 우연 매칭) → service="${service}", level="error" level 라벨 직접 필터로 교정. 라이브 level 값 = debug/error/info/warn로 죽은 분기 실측 확정.
  3. 미러 정합 범위(본 스프린트): 게이트 check-grafana-metrics.mjsALWAYS_AUTO_LABELS(service/pod/job 포함)로 Loki 셀렉터·container_* 패널을 silent skip → promtail 정합은 게이트상 불필요. 그러나 Critic R1 P2(미러 내부 정합: 대시보드 service= ↔ promtail service 라벨 부재)를 반영해 promtail도 라이브 라벨 모델로 정합.

작업 요약 (start 9f844db, 3 commit)

  • 6a47973: fix(infra) prometheus-config cadvisor/nodes job + SA/ClusterRole/CRB + serviceAccountName / grafana-service-dashboard 변수단축·Loki service=·job=~ 12곳·헤더 주석 / promtail 드리프트 배너.
  • ea54009: fix(infra) 미러 promtail service 라벨 정합(Critic R1 P2) — JSON service 필드 추출·승격, pod/app/container 라벨 드롭(대시보드 service 전환으로 불필요+카디널리티 절감), 라벨셋 namespace+service+level+tag(4).
  • ADR commit(본 문서) + README 171→172.

검증

  • 치환 카운트: job=~"${service}.*" 12, 잔존 pod=~"${service}.*" 3(KSM/cAdvisor×2), Loki service="${service}" 2, 비정규식 job="${service}" 0.
  • YAML 유효(3 파일) + 임베드 대시보드 JSON 파싱 OK(20 panels, uid algosu-service-debug), 변수값 [gateway,submission,problem,identity,ai-analysis,github-worker].
  • promtail 라벨셋 namespace+service+level+tag = 4(≤5 가이드), service = SERVICE_NAME 단축형(전 서비스 grep 확정).
  • 게이트 check-grafana-metrics.mjs 전 항목 [OK]. check-prometheus-rules.mjs는 rules.yaml(미수정) 검증이라 무영향.
  • 라이브 실증(aether-gitops, 본 스프린트 선행): cadvisor/nodes 타겟 UP, container_*{namespace=algosu} 75 시리즈(이전 0), id18 gateway/problem/submission 2/2/2, id19 problem level=error 2.
  • Critic(Codex gpt-5.5, --base 9f844db): R1 [P2] 미러 promtail service 라벨 부재 → ea54009 정합 → R2 CLEAN("no discrete regression... label changes consistent with service names emitted by structured loggers and metric job mappings").

부록: 동일 스프린트 추가 작업 (모니터링 드리프트 정리 확장)

#413(본 ADR 본문) 이후, 동일 모니터링 드리프트 정리가 AlgoSu 미러 2건 + 서버 aether-gitops 3건으로 확장됨:

AlgoSu 미러 (이 레포)

  • #414 (317de34): 미러 잔여 드리프트 — argocd-metrics/argocd-server-metrics scrape job 추가(라이브엔 이미 존재, Sprint 130 B-1) + kustomize patch로 전 Deployment revisionHistoryLimit 10→5(미사용 ReplicaSet 누적 차단, aether-gitops #9 정합).
  • #415 (8ef4edf): promtail SSOT 완전 정합 — kubernetes_sd(role:pod)static_configs로 교체(DaemonSet HOSTNAME env·-config.expand-env 등 부속 제거, −60/+12) + traceId를 structured_metadata로 복원 + loki-config allow_structured_metadata false→true(promtail structured_metadata 동작에 필수인 짝 설정). 실측: 라이브 promtail-config 전문 == gitops. #413 대시보드 service= 셀렉터는 SSOT promtail이 동일 service 라벨 생성하여 정합 유지(회귀 없음). → Sprint 234 이월 "promtail discovery 정합" 해소.

서버 aether-gitops (배포 SSOT, 라이브)

  • #8: Grafana no-data 라이브 수정(#413 대응) — container 메트릭 75 시리즈, 타겟 UP.
  • #9: Circuit Breaker 패널 stale 교정 + revisionHistoryLimit:5 — CB 0/1/2 반영, ReplicaSet 126→73.
  • #10: cloudflared-monitoring GitOps 편입(adopt) — tunnel 정상.
  • (직접) curl-test pod 정리.