관측이 안 보인다
-
스택 자체가 살아 있나 — 그래프가 평평한 것과 정상은 다르다
-
Prometheus
/targets— DOWN 급증 (2장) -
오브젝트 스토리지가 찼나 — 차면 로그와 트레이스가 동시에 멈춘다
-
Alloy 파드 상태 · Loki 인입 429
관측은 도구 넷을 아는 일이 아니라 알림에서 원인까지 가는 길을 아는 일이다
전체 지도조사 흐름도입 체크리스트사고 대응 카드점선 셋이 이 덱의 결론이다 — 저장소 셋을 세우는 것보다 그 셋을 잇는 것이 어렵고 값지다.
| 장 | 한 문장 |
|---|---|
| 0 | 세 신호는 역할 분담이고, 값은 이동에서 나오며, 스택은 카디널리티로 죽는다 |
| 1 | 메트릭으로 범위를, 로그로 문장을, 트레이스로 지점을 얻는다 |
| 2 | counter는 rate()로 본다. 알림은 RED(증상)에 걸고 USE는 조사용이다 |
| 3 | 라벨만 인덱싱한다 — 그래서 라벨 설계가 전부이고, 라인 필터를 파서보다 앞에 둔다 |
| 4 | 추적은 앱을 고쳐야 시작된다. 가장 싼 첫걸음은 로그에 trace_id |
| 5 | 값은 대시보드가 아니라 Explore 분할 화면에서 신호 사이를 오가는 것이다 |
새벽 3시 12분, OrdersHighErrorRate 알림. 질의 한 줄씩 밟으면 이렇게 간다.
얼마나·언제부터인가 — 메트릭으로 범위를 좁힌다 (2장)
sum by (service) (rate(http_requests_total{status=~"5.."}[5m])) / sum by (service) (rate(http_requests_total[5m]))orders만 03:12부터 0.4로 뛰었다. 다른 서비스는 멀쩡하다 — 범위가 좁혀졌다
지연도 같이 튀었나 — 원인의 성격을 가른다
histogram_quantile(0.99, sum by (le, service) (rate(http_request_duration_seconds_bucket{service="orders"}[5m])))p99가 0.3초 → 3초. 에러와 지연이 같이 튀면 다운스트림 대기를 의심한다 (그냥 에러만 튀면 배포·설정 쪽)
무슨 일이 있었나 — Explore 분할 화면에서 로그 (3장)
{namespace="prod", app="orders"} |= "error" | json | line_format "{{.err}}"inventory: context deadline exceeded가 반복된다. 문장을 얻었다
어디서 시간을 먹었나 — 로그 한 줄의 TraceID 링크를 누른다 (4장)
또는 ID를 모른다면 TraceQL로 직접:
{ resource.service.name = "orders" && duration > 2s } >> { span.db.system = "postgresql" }3.2초 중 2.8초가 inventory의 SELECT ... FOR UPDATE. 지점을 찍었다
그 서비스에서 무슨 일이 — 스팬에서 Logs for this span
{namespace="prod", app="inventory"} | json | duration_ms > 1000잠금 대기. 원인은 그 시각에 돈 재고 정산 배치였다
끝나고 남기는 것 — Explore Share 링크를 사고 기록에,
그리고 inventory 잠금 대기 패널을 대시보드에 추가.
같은 알림이 또 오면 1번에서 5번으로 바로 간다
전제 확인 (1장)
메트릭 (2장)
/targets에서 노드·kube-state가 다 UP인가retention과 retentionSize를 둘 다 준다 (후자는 PVC의 80~90%)ServiceMonitor로 추가. 안 긁히면 release 라벨 · 포트 이름 · NS 셀렉터알림 (2장) — 여기를 건너뛰지 않는다
up == 0 · 노드 NotReady · 디스크 소진 예측 · PVC 사용률 ·
인증서 만료 · etcd · 파드 재시작 반복 · 오브젝트 스토리지 용량 ·
서비스 에러율(RED) · 관측 스택 자체inhibit_rules로 노드 하나 죽을 때 알림 40개가 오는 걸 막는다로그 (3장)
compactor.retention_enabled: true.
버킷 라이프사이클과 겹치지 않게 한쪽으로 통일한다namespace · app · container까지. pod는 넣지 않는다ingestion_rate_mb · max_global_streams_per_user로 폭주 앱 방어선을 친다연결 (5장) — 대시보드보다 먼저
trace_id를 찍게 한다derivedFields → 로그에서 트레이스 링크가 실제로 뜨는지 눈으로 확인대시보드 (5장)
$service 변수 하나로 돌려 쓴다. 서비스마다 만들지 않는다percentunit · s · bytes)와 threshold 색을 넣는다추적 (4장) — 서비스 간 호출이 늘어난 뒤에
traceparent가 프록시·클라이언트 래퍼를 통과하는지 먼저 확인OTEL_SERVICE_NAME을 안 넣으면 전부 unknown_service가 된다trace to logs · serviceMap 연결까지 해야 값이 난다운영으로 넘기기
급할 때 순서대로. 자세한 건 각 장의 점검 절에 있다.
관측이 안 보인다
스택 자체가 살아 있나 — 그래프가 평평한 것과 정상은 다르다
Prometheus /targets — DOWN 급증 (2장)
오브젝트 스토리지가 찼나 — 차면 로그와 트레이스가 동시에 멈춘다
Alloy 파드 상태 · Loki 인입 429
로그가 안 들어온다
api/v1/labels에 라벨이 나오나 — 나오면 인입은 되는 중 (3장)
Alloy UI(/graph)에서 대상을 찾았나 — 특정 앱만 없으면 relabel 규칙
too many streams면 카디널리티 폭발 — 라벨에 pod·ID가 없는지
chunk가 버킷에 쌓이나 — 안 쌓이면 S3 자격증명·path-style·CA
알림이 안 온다
Watchdog이 외부에 도착하고 있었나 — 여기가 첫 질문이다
/rules에 규칙이 로드됐나 — PrometheusRule 라벨이 틀리면 조용히 무시된다
대상이 아예 사라진 것은 up == 0으로 안 잡힌다 — absent()를 걸었나
Alertmanager에 테스트 알림을 직접 쏴 본다. inhibit·silence에 묻히고 있지 않나
그래프가 이상하다
계단처럼 올라가면 counter를 그냥 그린 것 — rate() (2장)
분위수가 비면 by에서 le가 빠진 것
나눗셈이 비면 양쪽 라벨 집합이 다른 것
값이 요동치면 [범위]가 스크랩 간격의 4배 미만
검색이 느리다
라인 필터가 파서보다 뒤에 있지 않나 — 이게 1번 원인 (3장)
시간 범위가 며칠치인가 — 먼저 좁힌다
스트림 선택이 헐거운가 — {namespace=…}만이면 라벨을 더 준다
unwrap 집계는 원래 비싸다 — 상시 패널이 아니라 조사용으로
트레이스가 조각나거나 없다
traceparent 전파 — 프록시·클라이언트 래퍼·큐 구간을 의심한다 (4장)
아예 없으면 OTLP 엔드포인트 오설정 · 샘플링 0%
“그 요청”만 없으면 head 샘플링만 쓰는 것 — tail에 에러·지연 정책 추가
반쪽짜리가 많으면 tail 컬렉터에 스팬이 흩어진 것
# 무엇이 깔려 있나kubectl -n observability get podshelm list -n observability
# 무엇이 감시되고 있나 (규칙이 0개인 클러스터가 생각보다 흔하다)kubectl -n observability get prometheusrule -o name | wc -lkubectl get servicemonitor -A -o name | wc -l
# 알림이 실제로 어디로 가나 — 여기가 제일 중요하다kubectl -n observability get secret alertmanager-kube-prometheus-stack-alertmanager \ -o jsonpath='{.data.alertmanager\.yaml}' | base64 -d | grep -A3 'receiver\|webhook\|email'
# 얼마나 들고 있나kubectl -n observability get prometheus -o jsonpath='{.items[*].spec.retention}{"\n"}'kubectl -n observability get cm -o name | grep -i loki # limits_config의 retention_period
# 저장소는 어디에kubectl -n observability get secret | grep -i 's3\|loki\|tempo'
# 지금 안 좋은 것kubectl -n observability get pods --field-selector=status.phase!=Running# Prometheus UI /targets 의 DOWN, /tsdb-status 의 카디널리티 상위이어서 눈으로 확인할 것 셋 — 이게 되면 스택이 실제로 굴러가는 것이다.
| 확인 | 안 되면 |
|---|---|
로그 한 줄에 trace_id가 있고 링크가 뜨나 | 5장 derived field · 앱 로그 형식 |
| Watchdog이 외부 채널에 도착하고 있나 | 2장 — 알림 경로가 죽어 있을 수 있다 |
| 개요 대시보드가 하나로 정해져 있나 | 200개 중 아무도 어느 걸 볼지 모르는 상태 |
| 방향 | 무엇 | 이 덱과의 관계 |
|---|---|---|
| 밑에 깔리는 인프라 | 온프렘 덱 | 오브젝트 스토리지 · DB · SSO · 배치 판단 |
| 쿠버네티스 자체 | CKA 덱 | 이 덱이 전제한 기초 |
| 리눅스 로그 | 서버 관리 덱 | 노드 안에서 벌어지는 일 |
| 메시징 | Kafka 덱 | Tempo 3.0의 인입 경로에 등장한다 |
| 규모 확장 | Thanos · Mimir · 멀티 클러스터 조회 | 로컬 TSDB로 부족해진 다음 |
| 프로파일링 | Pyroscope · continuous profiling | 트레이스가 함수 단위까지 못 갈 때 |
| 신뢰성 공학 | SLO · 에러 버짓 · 번 레이트 알림 | RED 알림의 다음 단계 |
| 이벤트 | 쿠버네티스 이벤트 수집 · 감사 로그 파이프라인 | 이 덱이 다루지 않은 네 번째 신호 |
개념을 읽었지만 아직 손에 잡히지 않는다면 8장 실습 준비에서 공식 로컬 스택을 띄우고 9장 공식 앱 조사로 오류를 따라간 뒤, 10장 첫 대시보드에서 검증한 query를 반복해서 볼 화면으로 남긴다. 마지막으로 11장 내 앱 계측에서 자체 앱에 계측을 직접 붙여 같은 스택에 연결한다 — “내 서비스는 어떻게 연결하나”의 답이 거기 있다.
잘 굴러가는 관측 스택과 그렇지 않은 스택의 차이는 도구 선택이 아니다. 알림이 사람 손까지 도착하는가, 그래프에서 로그로 두 번의 클릭에 가는가, 그리고 라벨에 무엇을 넣지 않기로 했는가 — 이 셋이다.
도구는 바뀐다. 이 덱을 쓰는 동안에도 Promtail이 EOL됐고 Tempo가 구조를 갈아엎었다. 바뀌지 않는 건 세 신호의 역할 분담과 셋을 잇는 장치 셋이다. 새 도구가 나오면 “이건 어느 질문에 답하나, 옆 신호로 어떻게 건너가나”를 물으면 된다.