# observability / health 기준 ## 목적 이 문서는 1000+ 서비스가 공통으로 따르는 observability 기준선이다. metrics 수집 경로, golden signal 정의, 로그 포맷 / 수집 stack, trace 수집(OTel), health endpoint 외부 비공개 원칙, cardinality 가드를 한 파일에 고정한다. ## 공식 / 업계 근거 - **Google SRE Book (Ch.6)**: Four Golden Signals = **Latency, Traffic, Errors, Saturation**. 운영 대시보드의 기본 구성 원칙. - **RED method (Tom Wilkie, Weaveworks)**: request-driven service에 대해 **Rate, Errors, Duration**. - **USE method (Brendan Gregg)**: resource에 대해 **Utilization, Saturation, Errors**. - **kube-prometheus-stack**: Prometheus Operator를 통한 `ServiceMonitor` / `PodMonitor` CRD가 primary scrape path. - **Prometheus annotation fallback**: `prometheus.io/scrape: "true"` 등은 Operator가 없을 때만 사용. - **OpenTelemetry**: OTLP protocol + OTel Collector (Deployment gateway + DaemonSet agent) 가 표준. - **Log shipping canonical stacks**: Loki + Grafana Alloy (또는 Promtail) / Fluent Bit → OpenSearch. 한 플랫폼에서 둘 이상 섞지 않는다. - `kubectl events` (1.27+ stable) — 기존 `kubectl get events`보다 sort/watch 기본 제공. - metrics-server: HPA/VPA와 `kubectl top` 을 위한 최소 resource metric. full metrics와 분리. ## 기본 규칙 ### 1. Four Golden Signals를 모든 서비스 대시보드의 골격으로 각 traffic-facing service는 최소 4개 signal을 노출한다. - **Latency**: `request_duration_seconds` histogram (p50/p95/p99). - **Traffic**: `requests_per_second` by method/status. - **Errors**: `error_rate` (5xx / 전체). - **Saturation**: resource utilization (CPU / memory / connection pool / queue depth). SLO / alert / dashboard가 이 4개에서 시작한다. ### 2. RED는 request-driven, USE는 resource에 쓴다 - HTTP / gRPC 서비스 → **RED**. - Node / disk / CPU / DB pool → **USE**. - 두 방법론을 동시에 활용 가능 (golden signal은 양쪽 합집합). ### 3. ServiceMonitor / PodMonitor 를 primary scrape path로 kube-prometheus-stack을 운영하는 플랫폼에서는 `ServiceMonitor` CRD가 표준이다. - `selector.matchLabels` 로 대상 Service 매칭. - `namespaceSelector` 명시 (암묵적 전체 허용 금지). - `endpoints[].port` 는 **named port**, 숫자 port 금지. - `interval` (기본 30s), `scrapeTimeout` (interval < interval) 명시. - `scheme` (http/https) 명시. - `bearerTokenSecret` / `tlsConfig` 로 인증 scrape. - `relabelings` 로 label 위생 (pod_template_hash drop 등). Pod에 직접 연결되는 경우 (Service가 없는 워크로드) `PodMonitor` 사용. ### 4. Annotation-based scrape 는 fallback `prometheus.io/scrape: "true"` 계열 annotation은 Prometheus가 Operator 없이 kubernetes_sd_configs로 직접 discover하는 방식이다. ServiceMonitor 대비 label relabel / auth / tls 제어가 약하다. - kube-prometheus-stack이 있는 환경: **사용 금지**, ServiceMonitor 통일. - legacy / 교체 진행 중인 플랫폼: 전환 기간 동안만 사용. 지원 annotation: - `prometheus.io/scrape: "true"` - `prometheus.io/port: "8081"` - `prometheus.io/path: "/metrics"` - `prometheus.io/scheme: "http"` ### 5. metrics port는 외부 비공개, NetworkPolicy로 scraper만 허용 - `/metrics` 는 절대 Ingress 경로에 노출하지 않는다. - metrics port는 별도 containerPort (ex: 8081, 9000). - NetworkPolicy로 **monitoring namespace의 prometheus pod만** 해당 port에 ingress 허용. ### 6. Cardinality는 label 설계 단계에서 가드 Prometheus TSDB에서 **각 label value 조합 = 새 time series**. cardinality 폭발은 쿼리 OOM / storage 폭증의 가장 흔한 원인. 금지 label: - `user_id`, `tenant_id` (높은 기수) — 대신 top-N aggregation 또는 별도 logging. - `path` (path에 UUID / numeric ID 포함) — template된 route로 바꾼다 (`/users/:id`). - `url` 전체, `request_id`, `trace_id`, `session_id`. - timestamp, epoch value. 허용 label 예: - `method` (GET/POST/…), `status_code` (bucketed 2xx/4xx/5xx가 더 안전), `route` (template). 규칙: **한 metric당 series 수 ≤ 10,000** 목표. 10만 넘어가면 review. ### 7. Histogram 을 p99 표현 기본값으로 - summary는 aggregatable 하지 않다 (서비스 간 p99 합산 불가). - `histogram_quantile()` 를 위한 `_bucket` + `_count` + `_sum` 를 쓴다. - bucket boundary는 SLO에 맞춰 튜닝 (`le: 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10`). ### 8. 로그는 JSON structured, stdout/stderr 로만 application log는 **JSON one-line per record**, stdout/stderr로 출력. PVC / hostPath / 컨테이너 내부 file 금지. 필수 field: - `timestamp` (ISO 8601 RFC3339, UTC). - `level` (`DEBUG`/`INFO`/`WARN`/`ERROR`). - `service` (= `app.kubernetes.io/name`). - `trace_id`, `span_id` (OTel에서 주입). - `message`. - `error` (object with `type`, `message`, `stacktrace` when level=ERROR). - optional: `user_id` (hashed), `request_id`, `http_status`. ### 9. 로그 수집 stack은 한 플랫폼당 하나 canonical choice: - **Loki + Grafana Alloy (권장)**: 낮은 storage cost, Grafana 통합. - **Fluent Bit → OpenSearch/Elasticsearch**: full-text search 중심, 높은 storage cost. 플랫폼 하나에서 둘 다 운영하지 않는다. AI agent가 매니페스트 생성할 때 플랫폼 선택을 context에서 받아 일관되게 적용한다. node-level: DaemonSet으로 agent 배포 → tail `/var/log/containers/*.log`. ### 10. 민감정보는 로그 금지 + 자동 masking 금지: - access/refresh token, bearer, API key. - DB password, connection string의 password 부분. - Vault secret value. - full Authorization header. - PII (email, phone, SSN 등) 원문. 구현: - logging framework의 structured field 에서만 쓰고 `toString()` 흐름 차단. - 중앙 수집 파이프라인에 redaction filter 추가. - 의심스러운 pattern은 debug 로그에서도 masking. ### 11. OpenTelemetry / OTLP를 trace / metrics 통로로 - 애플리케이션: OTel SDK로 계측, OTLP (gRPC 4317 또는 HTTP 4318) 로 export. - 수집: **OTel Collector DaemonSet (agent)** → **OTel Collector Deployment (gateway)** → backend (Tempo / Jaeger / New Relic / Datadog). - gateway에서 sampling / tail-based sampling / PII scrubbing 적용. - app은 cluster 내부 agent endpoint만 알면 됨 (localhost:4317 → DaemonSet). ### 12. health / metrics / admin endpoint 는 외부 비공개 기본값 외부 비공개 대상: - `/health`, `/health/*`, `/actuator/*`. - `/metrics`. - `/admin`, `/internal`, `/debug`. - Keycloak management port 9000. - Vault `/sys/*` endpoint. 외부 공개는 명시적 review 필요. ### 13. probe는 health endpoint 와 목적을 구분 - probe용 endpoint는 shallow, 빠른 응답. - 운영자 점검용 deep health는 별도 endpoint (ex: `/ops/deep-health`), 인증 필요. - Prometheus 가 `/metrics` 를 스크레이프하더라도 probe가 `/metrics` 를 쓰지 않는다 (cost 문제). ### 14. `kubectl events` 를 기본 event 조회 수단으로 (1.27+) Kubernetes 1.27+ 부터 `kubectl events` 가 stable. - `kubectl events -A --watch` — cluster-wide live view. - `kubectl events -n --for pod/` — 특정 오브젝트. - `kubectl events --types=Warning` — 경고만. `kubectl get events` 대비 sort-by-timestamp 기본, watch 안정적. ### 15. 알림 기준: Golden Signal 에 SLO 를 먼저 정의 - availability SLO: 99.9% / 99.95% 등. - latency SLO: p99 < 500ms. - error budget: (1 - SLO) × 기간. - alert는 **burn rate** 기준 (1h/6h fast burn + 6h/3d slow burn 이중 창). 단순 "CPU > 80%" alert 는 actionable 하지 않다 (saturation은 dashboard용, 알림은 SLO 기반). ### 16. 워크로드별 기본 권장안 #### auth-server (Spring Boot) - metrics: micrometer + prometheus registry, `/actuator/prometheus`. - ServiceMonitor with named port `metrics` (8081). - tracing: OTel Java agent, OTLP to DaemonSet. - logging: logback JSON encoder → stdout. #### keycloak - metrics: management port 9000 `/metrics`. - ServiceMonitor 대상, `/admin` 과 `9000` 외부 비공개. - event metric cardinality는 `event_type` level 까지만, user / session ID 금지. #### vault - `/sys/metrics?format=prometheus` (token 필요) → ServiceMonitor with `bearerTokenSecret`. - `/sys/health` 는 sealed/standby 구분해서 alert 룰 따로. #### minio - `/minio/v2/metrics/cluster` + `/node` + `/bucket`. - bucket metric은 bucket 수 폭증 시 cardinality 주의. #### db (PostgreSQL / MySQL) - postgres_exporter / mysqld_exporter sidecar 또는 별도 Deployment. - USE method (connection pool saturation, lock wait). #### ingress-controller - RED + upstream response time. - path label은 반드시 template 화. ## 프로젝트 기준 요약 - Four Golden Signals를 dashboard 골격으로, RED/USE를 세부 방법론으로. - ServiceMonitor / PodMonitor 를 primary scrape, annotation은 fallback. - metrics port는 NetworkPolicy로 monitoring namespace만 허용. - Cardinality는 label 설계에서 가드 (user_id / raw path / timestamp 금지). - 로그는 JSON structured stdout, trace_id/span_id 포함. - log shipping stack은 플랫폼당 하나 (Loki+Alloy 또는 Fluent Bit→OpenSearch). - 로그에 민감정보 금지, 중앙 파이프라인 redaction. - OpenTelemetry DaemonSet agent + Deployment gateway. - health / metrics / admin endpoint 외부 비공개. - `kubectl events` 를 기본 event 조회 수단으로 (1.27+). - alert는 SLO burn rate 기반, CPU% 같은 단순 threshold 금지.