콘텐츠로 이동
Study Note관측

7. 마무리

관측은 도구 넷을 아는 일이 아니라 알림에서 원인까지 가는 길을 아는 일이다

이 장의 사용법4개
전체 지도
세 신호와 그 사이의 연결. 한 장으로 다시 보는 그림이다.
조사 흐름
알림 하나에서 원인까지, 질의 한 줄씩 밟아 가는 예. 덱 전체가 이걸 만들려고 있었다.
도입 체크리스트
처음 세울 때의 순서. 각 단계가 다음 단계의 전제다.
사고 대응 카드
급할 때 보는 첫 수 모음. 자세한 건 각 장의 점검 절에 있다.
수집(Alloy·Prometheus scrape) · 저장(Prometheus·Loki·Tempo) · 출구(Grafana·Alertmanager)로 묶은 덱 전체 지도와 세 신호를 잇는 점선

점선 셋이 이 덱의 결론이다 — 저장소 셋을 세우는 것보다 그 셋을 잇는 것이 어렵고 값지다.

장한 문장
0세 신호는 역할 분담이고, 값은 이동에서 나오며, 스택은 카디널리티로 죽는다
1메트릭으로 범위를, 로그로 문장을, 트레이스로 지점을 얻는다
2counter는 rate()로 본다. 알림은 RED(증상)에 걸고 USE는 조사용이다
3라벨만 인덱싱한다 — 그래서 라벨 설계가 전부이고, 라인 필터를 파서보다 앞에 둔다
4추적은 앱을 고쳐야 시작된다. 가장 싼 첫걸음은 로그에 trace_id
5값은 대시보드가 아니라 Explore 분할 화면에서 신호 사이를 오가는 것이다

새벽 3시 12분, OrdersHighErrorRate 알림. 질의 한 줄씩 밟으면 이렇게 간다.

  1. 얼마나·언제부터인가 — 메트릭으로 범위를 좁힌다 (2장)

    sum by (service) (rate(http_requests_total{status=~"5.."}[5m]))
    / sum by (service) (rate(http_requests_total[5m]))

    orders만 03:12부터 0.4로 뛰었다. 다른 서비스는 멀쩡하다 — 범위가 좁혀졌다

  2. 지연도 같이 튀었나 — 원인의 성격을 가른다

    histogram_quantile(0.99,
    sum by (le, service) (rate(http_request_duration_seconds_bucket{service="orders"}[5m])))

    p99가 0.3초 → 3초. 에러와 지연이 같이 튀면 다운스트림 대기를 의심한다 (그냥 에러만 튀면 배포·설정 쪽)

  3. 무슨 일이 있었나 — Explore 분할 화면에서 로그 (3장)

    {namespace="prod", app="orders"} |= "error" | json | line_format "{{.err}}"

    inventory: context deadline exceeded가 반복된다. 문장을 얻었다

  4. 어디서 시간을 먹었나 — 로그 한 줄의 TraceID 링크를 누른다 (4장)

    또는 ID를 모른다면 TraceQL로 직접:

    { resource.service.name = "orders" && duration > 2s } >> { span.db.system = "postgresql" }

    3.2초 중 2.8초가 inventory의 SELECT ... FOR UPDATE. 지점을 찍었다

  5. 그 서비스에서 무슨 일이 — 스팬에서 Logs for this span

    {namespace="prod", app="inventory"} | json | duration_ms > 1000

    잠금 대기. 원인은 그 시각에 돈 재고 정산 배치였다

  6. 끝나고 남기는 것 — Explore Share 링크를 사고 기록에, 그리고 inventory 잠금 대기 패널을 대시보드에 추가. 같은 알림이 또 오면 1번에서 5번으로 바로 간다

도입 체크리스트 — 처음 세울 때

섹션 제목: “도입 체크리스트 — 처음 세울 때”
  1. 전제 확인 (1장)

    • 오브젝트 스토리지가 있는가 — 없으면 Loki도 Tempo도 못 뜬다 (온프렘 덱 6장)
    • 관측 스택을 감시 대상과 다른 노드에 둘 수 있는가 (온프렘 덱 8장)
    • 리텐션 · 보존 · 샘플링 · 스크랩 간격 네 값을 먼저 적는다
  2. 메트릭 (2장)

    • kube-prometheus-stack 설치 → /targets에서 노드·kube-state가 다 UP인가
    • retention과 retentionSize를 둘 다 준다 (후자는 PVC의 80~90%)
    • 앱은 ServiceMonitor로 추가. 안 긁히면 release 라벨 · 포트 이름 · NS 셀렉터
    • 앱 팀에 RED 세 지표를 요청한다 — 지연은 반드시 histogram으로
  3. 알림 (2장) — 여기를 건너뛰지 않는다

    • 필수 목록부터 열 개: up == 0 · 노드 NotReady · 디스크 소진 예측 · PVC 사용률 · 인증서 만료 · etcd · 파드 재시작 반복 · 오브젝트 스토리지 용량 · 서비스 에러율(RED) · 관측 스택 자체
    • 알림마다 runbook 링크를 단다
    • inhibit_rules로 노드 하나 죽을 때 알림 40개가 오는 걸 막는다
    • Watchdog을 외부 채널로 라우팅 — 알림이 안 오는 것을 알아채는 유일한 방법
    • 테스트 알림을 실제로 쏴서 사람 손까지 도착하는지 확인한다
  4. 로그 (3장)

    • 버킷 + 전용 사용자, compactor.retention_enabled: true. 버킷 라이프사이클과 겹치지 않게 한쪽으로 통일한다
    • Loki는 monolithic으로 시작. Alloy는 DaemonSet
    • 라벨은 최소로 — namespace · app · container까지. pod는 넣지 않는다
    • 앱 로그를 JSON으로 바꾼다 — 라벨을 절제할 수 있게 되는 전제다
    • ingestion_rate_mb · max_global_streams_per_user로 폭주 앱 방어선을 친다
  5. 연결 (5장) — 대시보드보다 먼저

    • 데이터소스 셋을 프로비저닝 파일로 (UI에서 만들지 않는다)
    • 앱 로그에 trace_id를 찍게 한다
    • derivedFields → 로그에서 트레이스 링크가 실제로 뜨는지 눈으로 확인
    • Grafana DB를 PostgreSQL로, SSO 연결, 로컬 admin은 남긴다
  6. 대시보드 (5장)

    • 계층 셋 고정 — 개요 → 층별 → 서비스별
    • 서비스별은 $service 변수 하나로 돌려 쓴다. 서비스마다 만들지 않는다
    • 단위(percentunit · s · bytes)와 threshold 색을 넣는다
    • ConfigMap 또는 Operator로 코드에서 들어오게
  7. 추적 (4장) — 서비스 간 호출이 늘어난 뒤에

    • 자동 계측부터. traceparent가 프록시·클라이언트 래퍼를 통과하는지 먼저 확인
    • OTEL_SERVICE_NAME을 안 넣으면 전부 unknown_service가 된다
    • tail 샘플링 — 에러·느린 요청은 100%, 나머지는 1%. 컬렉터를 늘릴 때는 trace ID 기반 라우팅을 잊지 않는다
    • trace to logs · serviceMap 연결까지 해야 값이 난다
  8. 운영으로 넘기기

    • 관측 스택 자신에 대한 알림 (TSDB 용량 · Loki 인입 실패 · Tempo S3 오류)
    • 분기마다 조회수 0인 대시보드와 울린 적 없는 알림을 정리한다
    • 카디널리티 상위 10개를 주기적으로 본다

급할 때 순서대로. 자세한 건 각 장의 점검 절에 있다.

관측이 안 보인다

  1. 스택 자체가 살아 있나 — 그래프가 평평한 것과 정상은 다르다

  2. Prometheus /targets — DOWN 급증 (2장)

  3. 오브젝트 스토리지가 찼나 — 차면 로그와 트레이스가 동시에 멈춘다

  4. Alloy 파드 상태 · Loki 인입 429

로그가 안 들어온다

  1. api/v1/labels에 라벨이 나오나 — 나오면 인입은 되는 중 (3장)

  2. Alloy UI(/graph)에서 대상을 찾았나 — 특정 앱만 없으면 relabel 규칙

  3. too many streams면 카디널리티 폭발 — 라벨에 pod·ID가 없는지

  4. chunk가 버킷에 쌓이나 — 안 쌓이면 S3 자격증명·path-style·CA

알림이 안 온다

  1. Watchdog이 외부에 도착하고 있었나 — 여기가 첫 질문이다

  2. /rules에 규칙이 로드됐나 — PrometheusRule 라벨이 틀리면 조용히 무시된다

  3. 대상이 아예 사라진 것은 up == 0으로 안 잡힌다 — absent()를 걸었나

  4. Alertmanager에 테스트 알림을 직접 쏴 본다. inhibit·silence에 묻히고 있지 않나

그래프가 이상하다

  1. 계단처럼 올라가면 counter를 그냥 그린 것 — rate() (2장)

  2. 분위수가 비면 by에서 le가 빠진 것

  3. 나눗셈이 비면 양쪽 라벨 집합이 다른 것

  4. 값이 요동치면 [범위]가 스크랩 간격의 4배 미만

검색이 느리다

  1. 라인 필터가 파서보다 뒤에 있지 않나 — 이게 1번 원인 (3장)

  2. 시간 범위가 며칠치인가 — 먼저 좁힌다

  3. 스트림 선택이 헐거운가 — {namespace=…}만이면 라벨을 더 준다

  4. unwrap 집계는 원래 비싸다 — 상시 패널이 아니라 조사용으로

트레이스가 조각나거나 없다

  1. traceparent 전파 — 프록시·클라이언트 래퍼·큐 구간을 의심한다 (4장)

  2. 아예 없으면 OTLP 엔드포인트 오설정 · 샘플링 0%

  3. “그 요청”만 없으면 head 샘플링만 쓰는 것 — tail에 에러·지연 정책 추가

  4. 반쪽짜리가 많으면 tail 컬렉터에 스팬이 흩어진 것

처음 인수인계 받았다면 — 30분 파악

섹션 제목: “처음 인수인계 받았다면 — 30분 파악”
터미널 창
# 무엇이 깔려 있나
kubectl -n observability get pods
helm list -n observability
# 무엇이 감시되고 있나 (규칙이 0개인 클러스터가 생각보다 흔하다)
kubectl -n observability get prometheusrule -o name | wc -l
kubectl 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가 구조를 갈아엎었다. 바뀌지 않는 건 세 신호의 역할 분담과 셋을 잇는 장치 셋이다. 새 도구가 나오면 “이건 어느 질문에 답하나, 옆 신호로 어떻게 건너가나”를 물으면 된다.