220 lines
9.4 KiB
Markdown
220 lines
9.4 KiB
Markdown
# 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 <ns> --for pod/<name>` — 특정 오브젝트.
|
||
- `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 금지.
|