Kubernetes 관측 도구 구조 정리: Prometheus, Grafana, Loki, Promtail

눅눅이·2026년 7월 4일
post-thumbnail

2편에서는 Spring-React-MSA 요청 흐름을 기준으로 Kubernetes Object들이 어떻게 연결되는지 정리했다.

Browser
-> Ingress
-> Service
-> Pod
-> 내부 Service
-> Redis / Postgres

이 흐름을 이해하면 Kubernetes 안에서 요청이 어떤 경로로 이동하는지 감을 잡을 수 있다.

하지만 흐름을 아는 것과, 실제로 문제가 생겼을 때 원인을 찾는 것은 또 다른 문제다.

문제가 생기면 대충 이런 식으로 확인할 수 있다.

docker ps
docker logs -f spring-member-bff
docker logs -f postgres

하지만 Kubernetes에서는 Pod가 계속 생성되고 사라질 수 있다.

Deployment가 Pod를 다시 띄울 수도 있고, Rolling Update 과정에서 새 Pod와 기존 Pod가 동시에 존재할 수도 있다.

즉 로그를 봐야 할 대상이 고정되어 있지 않다.

spring-member-bff-service-6d7c8f9c7b-abcd1
spring-member-bff-service-6d7c8f9c7b-efgh2
spring-member-bff-service-7f8d9c6b5a-ijkl3

Pod 이름도 매번 바뀔 수 있다.

그래서 Kubernetes에서는 특정 컨테이너 하나의 로그를 보는 것보다, Namespace나 Label 기준으로 로그를 모아서 보는 방식이 더 자연스럽다.

메트릭도 마찬가지다.

단순히 “서버가 떴다”가 아니라 다음 정보를 봐야 한다.

Pod가 재시작되고 있는가?
CPU와 Memory를 얼마나 쓰는가?
Ingress Controller에 요청이 들어오는가?
Gateway에서 4xx/5xx가 발생하는가?
Postgres PVC 용량은 괜찮은가?
Redis 연결 문제는 없는가?

이걸 보기 위해 Prometheus, Grafana, Loki, Promtail 같은 도구를 사용한다.


1. 현재 Namespace 구조

현재 구조는 크게 세 개의 Namespace로 나눌 수 있다.

Kubernetes Cluster
├─ spring-msa namespace
│  ├─ spring-member-web
│  ├─ spring-admin-web
│  ├─ spring-member-bff-service
│  ├─ spring-admin-bff-service
│  ├─ spring-member-gateway
│  ├─ spring-admin-gateway
│  ├─ spring-user-service
│  ├─ postgres
│  └─ redis
│
├─ ingress-nginx namespace
│  └─ ingress-nginx-controller
│
└─ observability namespace
   ├─ Prometheus
   ├─ Grafana
   ├─ Loki
   └─ Promtail

각 Namespace의 역할은 이렇다.

Namespace역할
spring-msa실제 Spring MSA 애플리케이션
ingress-nginx외부 요청을 받는 Ingress Controller
observability로그와 메트릭을 수집하고 조회하는 관측 도구

애플리케이션과 관측 도구를 같은 Namespace에 넣을 수도 있다.

하지만 역할이 다른 리소스는 분리해두는 편이 관리하기 쉽다.

spring-msa는 실제 서비스 영역이고, observability는 서비스 상태를 보는 영역이다.


2. 관측 도구 전체 흐름

먼저 전체 구조를 보면 이렇다.

이 그림에서 핵심은 두 갈래다.

로그 흐름
  -> Promtail
  -> Loki
  -> Grafana

메트릭 흐름
  -> Prometheus
  -> Grafana

Grafana는 최종적으로 사용자가 보는 화면이다.

하지만 Grafana가 로그와 메트릭을 직접 저장하는 것은 아니다.

로그는 Loki에 저장되고, 메트릭은 Prometheus에 저장된다.

Grafana는 Loki와 Prometheus를 DataSource로 연결해서 보여주는 UI 역할을 한다.


3. 로그 흐름

Kubernetes에서 애플리케이션 로그는 보통 파일에 직접 저장하지 않는다.

Spring Boot 애플리케이션은 일반적으로 stdout, stderr로 로그를 출력한다.

그러면 Kubernetes는 해당 로그를 Node의 컨테이너 로그 경로에 기록한다.

Promtail은 이 로그 파일을 읽어서 Loki로 보낸다.

전체 흐름은 다음과 같다.

조금 더 실제 요청 흐름에 붙여서 보면 이렇다.

사용자 요청
  -> Ingress
  -> Gateway
  -> BFF / Service
  -> 애플리케이션 로그 발생
  -> stdout / stderr 출력
  -> Node 로그 파일에 기록
  -> Promtail이 수집
  -> Loki에 저장
  -> Grafana에서 조회

여기서 중요한 점이 있다.

애플리케이션 컨테이너가 직접 Loki로 로그를 보내는 구조가 아니다.

Spring Boot 애플리케이션은 그냥 로그를 출력하면 된다.

Spring Boot
  -> 로그 출력만 함

Promtail
  -> Kubernetes 로그 파일을 읽어서 Loki로 전송

그래서 애플리케이션 코드에 Loki 전송 로직을 직접 넣을 필요가 없다.

관측 책임을 애플리케이션 코드에서 분리할 수 있다.


4. Prometheus가 로그를 수집하는 것은 아니다

처음 관측 도구를 붙이면 헷갈리는 부분이 있다.

Grafana 화면에서 로그도 보고, 메트릭도 보다 보니 Prometheus가 로그까지 수집하는 것처럼 느껴질 수 있다.

하지만 Prometheus는 로그 수집 도구가 아니다.

Prometheus는 CPU 사용량, 메모리 사용량, Pod 상태, 요청 수 같은 메트릭을 수집하고 저장한다.

로그는 다른 흐름을 탄다.

로그 흐름:
Spring Boot Pod
  -> stdout / stderr 로그 출력
  -> Kubernetes Node의 컨테이너 로그 파일
  -> Promtail이 수집
  -> Loki에 저장
  -> Grafana에서 조회

반면 메트릭 흐름은 이렇다.

메트릭 흐름:
Spring Boot / Kubernetes / Node
  -> Metrics Endpoint 노출
  -> Prometheus가 scrape
  -> Prometheus에 저장
  -> Grafana Dashboard에서 조회

즉 역할을 나누면 다음과 같다.

역할도구
로그 수집Promtail
로그 저장/검색Loki
메트릭 수집/저장Prometheus
화면 조회/시각화Grafana

정리하면 간단하다.

로그는 Promtail이 수집해서 Loki에 저장한다.
메트릭은 Prometheus가 수집해서 Prometheus에 저장한다.
Grafana는 Loki와 Prometheus를 조회해서 화면에 보여준다.

따라서 Spring-React-MSA 애플리케이션 로그를 보고 싶다면 Prometheus가 아니라 Loki를 봐야 한다.

CPU, Memory, Pod 상태, Restart Count 같은 숫자 지표를 보고 싶다면 Prometheus를 봐야 한다.


5. Loki는 로그를 저장하고 검색한다

Promtail이 수집한 로그는 Loki로 들어간다.

Loki는 로그를 저장하고 검색할 수 있게 해준다.

Grafana에서는 Loki를 DataSource로 연결한 뒤, Explore 화면에서 LogQL로 로그를 조회할 수 있다.

예를 들어 spring-msa Namespace의 전체 로그를 보고 싶다면 다음처럼 조회할 수 있다.

{namespace="spring-msa"}

특정 BFF 서비스 로그만 보고 싶다면 Pod 이름 패턴으로 필터링할 수 있다.

{namespace="spring-msa", pod=~"spring-member-bff-service.*"}

에러 로그만 보고 싶다면 문자열 필터를 붙이면 된다.

{namespace="spring-msa"} |= "ERROR"

Ingress Controller 로그를 보고 싶다면 Namespace를 바꾸면 된다.

{namespace="ingress-nginx"}

이렇게 하면 Pod 이름을 하나하나 찾아서 kubectl logs를 치지 않아도 된다.

Namespace, Pod, Container, Label 기준으로 로그를 모아서 볼 수 있다.


6. 메트릭 흐름

로그와 메트릭은 다르다.

로그는 문자열 기록이다.

ERROR 로그
INFO 로그
WebSocket 연결 로그
SQL 에러 로그
Gateway 인증 실패 로그

반면 메트릭은 숫자 데이터다.

CPU 사용량
Memory 사용량
Pod 재시작 횟수
HTTP 요청 수
응답 시간
PVC 사용량

메트릭은 Prometheus가 수집한다.

Prometheus는 대상의 Metrics Endpoint를 주기적으로 조회해서 시계열 데이터로 저장한다.

흐름을 풀어보면 다음과 같다.

Spring Application / Kubernetes Node / Pod
  -> 메트릭 노출
  -> Prometheus가 주기적으로 scrape
  -> Prometheus TSDB에 저장
  -> Grafana가 Prometheus를 조회
  -> Dashboard에서 시각화

여기서 scrape라는 말이 중요하다.

애플리케이션이 Prometheus로 데이터를 밀어 넣는 방식이 아니라, Prometheus가 주기적으로 메트릭을 가져가는 방식이다.

Push 방식
  -> 애플리케이션이 서버로 보냄

Prometheus 방식
  -> Prometheus가 주기적으로 가져감

그래서 Prometheus를 사용할 때는 메트릭을 노출하는 Endpoint가 필요하다.

Spring Boot에서는 Actuator와 Micrometer를 사용하면 Prometheus 형식의 메트릭을 노출할 수 있다.

예를 들면 이런 경로를 사용할 수 있다.

/actuator/prometheus

7. Prometheus와 Loki의 차이

처음에는 Grafana에서 다 보이기 때문에 Prometheus와 Loki가 헷갈릴 수 있다.

하지만 둘은 저장하는 데이터가 다르다.

구분PrometheusLoki
수집 대상메트릭로그
데이터 형태숫자 시계열 데이터로그 라인
쿼리 언어PromQLLogQL
저장 예시CPU, Memory, 요청 수, 응답 시간ERROR 로그, SQL 에러, 인증 실패 로그
Grafana 사용 위치DashboardExplore, Logs Panel

Prometheus는 숫자를 다룬다.

CPU가 몇 퍼센트인가?
Memory를 얼마나 쓰고 있는가?
Pod가 몇 번 재시작됐는가?
HTTP 요청이 초당 몇 건인가?

Loki는 로그를 다룬다.

어떤 ERROR가 발생했는가?
어떤 요청에서 인증 실패가 났는가?
WebSocket 연결이 끊긴 이유가 무엇인가?
Redis 연결 실패 로그가 있는가?

정리하면 이렇게 볼 수 있다.

Prometheus
  -> 숫자 기반 상태 확인

Loki
  -> 문자열 기반 원인 추적

둘 다 필요하다.

메트릭만 보면 “문제가 있다”는 것은 알 수 있지만, 구체적인 원인은 알기 어렵다.

로그만 보면 원인은 볼 수 있지만, 전체적인 리소스 상태나 추세를 파악하기 어렵다.


8. Grafana는 저장소가 아니다

Grafana는 로그나 메트릭을 직접 저장하는 도구가 아니다.

Grafana는 여러 DataSource를 연결해서 보여주는 UI에 가깝다.

Grafana
  ├─ Prometheus 조회
  └─ Loki 조회

그래서 Grafana에서 로그를 보고 있다고 해서 Grafana가 로그를 저장하는 것은 아니다.

실제 로그는 Loki에 있다.

Grafana는 Loki에 LogQL 쿼리를 날리고, 그 결과를 화면에 보여준다.

메트릭도 마찬가지다.

실제 메트릭은 Prometheus에 저장된다.

Grafana는 Prometheus에 PromQL 쿼리를 날리고, 그 결과를 Dashboard로 보여준다.

즉 역할을 이렇게 분리해서 이해하면 된다.

Promtail
  -> 로그 수집기

Loki
  -> 로그 저장소

Prometheus
  -> 메트릭 저장소

Grafana
  -> 조회/시각화 화면

9. 실제 장애 확인 흐름

예를 들어 사용자가 채팅 메시지를 보냈는데 문제가 발생했다고 해보자.

이때 바로 특정 Pod 로그만 보는 것보다, 흐름을 따라가면서 확인하는 게 좋다.

1. Grafana 접속

2. Loki DataSource 선택

3. spring-msa Namespace 로그 조회

4. spring-member-bff-service Pod 로그 확인

5. Redis 관련 로그 또는 WebSocket 로그 검색

6. 필요하면 ingress-nginx Namespace 로그 확인

7. Prometheus Dashboard에서 Pod 상태 확인

8. CPU / Memory / Restart Count 확인

예를 들어 BFF 쪽 에러를 보고 싶다면 다음처럼 조회한다.

{namespace="spring-msa", pod=~"spring-member-bff-service.*"} |= "ERROR"

Redis 연결 문제를 보고 싶다면 다음처럼 검색할 수 있다.

{namespace="spring-msa"} |= "Redis"

WebSocket 관련 로그를 보고 싶다면 다음처럼 볼 수 있다.

{namespace="spring-msa"} |= "WebSocket"

Ingress 요청 자체가 들어오는지 확인하려면 Ingress Controller 로그를 본다.

{namespace="ingress-nginx"}

그리고 메트릭 쪽에서는 다음을 확인한다.

Pod Ready 상태
Pod Restart Count
CPU 사용량
Memory 사용량
Network I/O
PVC 사용량

이렇게 로그와 메트릭을 같이 봐야 한다.

로그는 원인을 찾는 데 좋고, 메트릭은 상태와 추세를 보는 데 좋다.


10. 왜 기능보다 관측 도구를 먼저 붙였나

Redis Stream 실시간 채팅이나 Kafka 이벤트 파이프라인을 만들기 전에 관측 도구를 먼저 붙인 이유가 있다.

기능을 먼저 만들 수도 있다.

하지만 문제가 생겼을 때 볼 수 있는 도구가 없으면 원인 분석이 어렵다.

특히 MSA에서는 요청이 여러 서비스를 지나간다.

Browser
  -> Ingress
  -> Gateway
  -> BFF
  -> Redis / DB
  -> 다른 Microservice

이 흐름 중 어디에서 문제가 생겼는지 확인하려면 로그와 메트릭이 필요하다.

그래서 다음 작업으로 넘어가기 전에 관측 기반을 먼저 잡았다.

0. 관측 도구 구성
1. Redis Stream 실시간 채팅
2. Spring + Kafka 이벤트 파이프라인
3. Kafka 기반 대량 처리/배치
4. Keycloak + Spring 보상 트랜잭션

관측 도구는 기능 자체는 아니다.

하지만 기능을 안정적으로 만들기 위한 기반이다.

문제가 생겼을 때 볼 수 있는 눈을 먼저 붙이는 작업에 가깝다.


11. 정리

Kubernetes에서 관측 도구를 붙인다는 것은 단순히 Grafana 화면을 띄우는 것이 아니다.

애플리케이션이 어떤 로그를 남기고, 어떤 리소스를 사용하고, 어디에서 문제가 발생하는지 추적할 수 있는 기반을 만드는 것이다.

핵심 흐름은 두 가지다.

로그 흐름:
Application Pod
  -> stdout / stderr
  -> Promtail
  -> Loki
  -> Grafana

메트릭 흐름:
Pod / Node / Kubernetes
  -> Prometheus
  -> Grafana

각 도구의 역할은 명확하다.

도구역할
PromtailPod 로그 수집
Loki로그 저장 및 검색
Prometheus메트릭 수집 및 저장
Grafana로그와 메트릭 조회/시각화

정리하면 이렇게 볼 수 있다.

Promtail은 로그를 모은다.
Loki는 로그를 저장한다.
Prometheus는 메트릭을 모은다.
Grafana는 그것들을 보여준다.

여기서 가장 헷갈리기 쉬운 부분은 다시 한 번 정리해야 한다.

Prometheus는 로그 수집기가 아니다.
Prometheus는 메트릭 수집기다.

로그는 Promtail이 수집한다.
수집된 로그는 Loki에 저장된다.
Grafana는 Loki를 조회해서 로그를 보여준다.

Kubernetes 환경에서는 서비스가 여러 Pod와 Namespace에 흩어져 있다.

그래서 장애가 발생했을 때 kubectl logs만으로는 부족할 수 있다.

Spring-React-MSA처럼 Gateway, BFF, User Service, Redis, Postgres, Ingress Controller가 함께 동작하는 구조에서는 로그와 메트릭을 한 곳에서 볼 수 있어야 한다.

결국 관측 도구를 구성한다는 것은 Kubernetes 안에서 실행 중인 서비스를 운영 가능한 상태로 만드는 과정이다.

컨테이너를 띄우는 것에서 끝나는 게 아니라, 그 컨테이너들이 지금 어떤 상태인지 볼 수 있어야 한다.

그게 Kubernetes에서 Prometheus, Grafana, Loki, Promtail을 붙이는 이유다.

profile
개발자가 아닌 탐구자

0개의 댓글