“다 잘 됐는데 Grafana만 비었다”: 쿠버네티스 통합세(Integration Tax)로 겪은 관측성 사고

도입부: 운영 환경에서 문제를 어렵게 만드는 건 종종 “컴포넌트의 버그”가 아니라 “통합 누락”입니다. 이 글에서는 Prometheus–Cilium–Grafana 조합에서 실제로 벌어질 수 있는 스크레이핑 누락 사례를 통해, 제가 생각하는 쿠버네티스 통합세(integration tax) 와 이를 줄이기 위한 정책 + 승인(사람 확인) 중심의 접근을 정리해봅니다.

쿠버네티스 통합세란 무엇인가요?

쿠버네티스에서 “통합세(integration tax)”는 특정 제품(Cilium, Prometheus, Grafana 등)이 각자 정상 동작해도, 연결 고리(라벨 셀렉터, ServiceMonitor, RBAC, 네트워크 정책, 네임스페이스 스코프 등) 가 하나라도 빠지면 운영 결과가 무너지는 비용을 말합니다.

특히 관측성(Observability) 스택에서 이 통합세가 무서운 이유는:

  • 장애가 났는데도 메트릭이 비어 원인 분석이 지연됩니다.
  • “무언가가 안 보인다”는 증상은 로그/트레이스/메트릭 어느 층에서든 발생할 수 있어 책임 소재가 흐려집니다.
  • 결국 단순 설정 누락이 운영 장애급 혼란으로 번집니다.

사례: Cilium/Hubble은 정상인데 Grafana 네트워크 메트릭이 비어있던 이유

요약 자료의 핵심은 이렇습니다.

  • Cilium/Hubble 자체는 정상 동작하고 있었습니다.
  • 그런데 Grafana에서 네트워크 메트릭이 비어 있었고, 이로 인해 분석이 지연됐습니다.
  • 원인은 “Cilium이 문제”가 아니라, Prometheus가 Cilium agent/operator를 스크레이핑하도록 ServiceMonitor가 제대로 연결되지 않아 스크레이핑이 누락된 것이었습니다.

즉, 구성요소 각각은 건강했지만, 쿠버네티스에서 흔한 “접착면(glue layer)”이 빠지면서 시스템 전체 관측성이 무너진 전형적인 통합세 사례입니다.

왜 ServiceMonitor 누락이 치명적인가요?

Prometheus Operator 기반 스택에서 ServiceMonitor는 “이 엔드포인트를 스크레이핑하라”는 선언입니다. 여기서 자주 터지는 실패 유형은 다음과 같습니다.

  • ServiceMonitor 자체가 없음: 가장 단순하지만 가장 치명적입니다.
  • 라벨 셀렉터 불일치: ServiceMonitor는 존재하지만 Prometheus가 선택하지 못합니다.
  • 네임스페이스 스코프 문제: Prometheus가 감시할 네임스페이스 설정과 어긋납니다.
  • RBAC/NetworkPolicy로 접근 차단: 타깃은 잡히는데 scrape가 실패하거나 아예 타깃으로 안 잡힙니다.
  • Prometheus 인스턴스 선택 문제: 클러스터에 Prometheus가 여러 개면 “어느 Prometheus가 이 ServiceMonitor를 가져가야 하는지”가 어긋날 수 있습니다.

겉으로는 “Grafana가 비었다”로 보이지만, 실제 원인은 “Prometheus 타깃이 아예 안 잡혔다/스크레이프가 누락됐다”로 내려가는 경우가 많습니다.

제가 선택한 우선순위: ‘정책’ + ‘승인(사람 확인)’

대화에서 제가 강조한 방향은 명확합니다.

  1. 개인의 주의력보다 규칙/가드레일(정책)로 통합 누락을 구조적으로 막고
  2. 정책에 벗어나는 변경(예외)은 고위험으로 간주
  3. 배포 리드타임이 늘더라도 사람의 확인(승인 절차) 을 거치게 한다

여기서 중요한 전제는 다음 문장으로 요약됩니다.

  • “정책에 벗어나는 것은 중요한 것(고위험)으로 가정해야 한다.”
  • “중요한 것은 사람의 확인이 필요하다.”
  • “중요한 것에 대한 예외 처리는 항상 필요하다(다만 통제돼야 한다).”

다만 이 접근에는 함정도 있습니다. 정책이 현실을 따라가지 못해 예외가 폭증하면, 정말 위험한 예외와 단순 형식 위반이 섞여 리뷰 품질이 떨어질 수 있습니다. 그래서 “정책 위반 = 모두 동일한 중요도”로 뭉치기보다는, 위반 유형을 분류하고 승인 기준/체크 항목을 다르게 두는 설계가 필요합니다.

정책으로 막을 것 vs 사람 승인으로 볼 것: 경계선 제안

관측성 통합 누락을 줄이려면, 저는 다음처럼 역할을 나누는 게 실전적이라고 봅니다.

1) 정책(Policy)로 ‘기본선을 강제’합니다

정책은 “누락되면 거의 100% 사고로 이어지는 것”을 막는 데 써야 효과가 큽니다.

  • (예) 특정 워크로드/애드온(Cilium agent/operator 등)은 반드시 ServiceMonitor/PodMonitor를 가져야 한다
  • (예) Prometheus가 가져간 ServiceMonitor에서 scrape target이 0이면 배포 실패(“타깃 0 금지”)
  • (예) 레이블 규약 강제(팀/서비스/환경 라벨 등)로 selector 실수를 줄임

Kyverno나 OPA Gatekeeper 같은 도구로 “배포 게이트”를 만들면, 통합 누락을 사람 실수 영역에서 시스템 영역으로 끌어올릴 수 있습니다.

2) 예외(Exception)는 사람 승인을 통해 ‘의식적으로’ 처리합니다

예외는 항상 생깁니다. 다만 예외는 “편의”가 아니라 “위험”의 다른 이름이기 때문에, 저는 이렇게 보수적으로 보는 편입니다.

  • 정책 위반이 발생하면 → 기본적으로 고위험 변경으로 분류
  • 승인자는 “정말 예외가 필요한지”와 “대체 관측성 경로가 있는지”를 확인
  • (가능하면) 예외는 만료 시간을 두고, 사후에 정식 정책/구성으로 흡수

핵심은 예외를 없애는 게 아니라, 예외를 비용이 드는 선택으로 만들어 남발을 막는 것입니다.

(간단 예시) ServiceMonitor 기본 형태와 흔한 함정

아래는 전형적인 ServiceMonitor 형태입니다. (환경에 따라 label/namespace 설정은 달라질 수 있습니다.)

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: cilium-agent
  namespace: kube-system
  labels:
    release: prometheus
spec:
  namespaceSelector:
    matchNames:
      - kube-system
  selector:
    matchLabels:
      k8s-app: cilium
  endpoints:
    - port: metrics
      interval: 30s

여기서 “통합세”가 발생하는 지점은 대개 이런 것들입니다.

  • metadata.labels.release: prometheus 같은 Prometheus 선택 라벨이 실제 Prometheus 설정과 다름
  • selector.matchLabels가 Service의 라벨과 안 맞음
  • namespaceSelector가 빠져서 다른 네임스페이스의 Service를 못 봄(또는 반대)
  • Service에 port: metrics가 실제로 존재하지 않음

즉, YAML은 존재하지만 실제로는 Prometheus의 타깃으로 들어가지 않는 “허수 리소스”가 생깁니다.

마무리: “컴포넌트는 정상인데 관측이 실패”하는 게 운영에서 제일 비쌉니다

쿠버네티스의 관측성 문제는 종종 제품 결함이 아니라 통합 누락에서 시작합니다. 저는 이를 줄이기 위해 “정책으로 기본선을 강제하고, 정책 위반은 고위험 예외로 보고 사람 승인을 거치게 하는 것”이 가장 현실적인 우선순위라고 생각합니다. 결국 운영에서 비싼 건 장애 자체보다, 장애를 설명할 데이터가 비어 있는 시간이기 때문입니다.

참고 자료

1개의 좋아요