로그인 회원가입
모두인포
전체IT경제사회생활스포츠시사여행연애

OpenTelemetry + Tempo를 이용한 Kubernetes 분산 추적

lmkfox · 2026-09-15 · 조회 4
OpenTelemetry + Tempo를 이용한 Kubernetes 분산 추적
OpenTelemetry + Tempo를 이용한 Kubernetes 분산 추적 FastAPI → Redis → PostgreSQL 요청 흐름을 Trace ID 하나로 추적하는 실전 Kubernetes Observability Kubernetes 환경에서 Prometheus와 Loki를 구축하면 시스템 상태와 로그를 상당히 편리하게 확인할 수 있다. 하지만 한 가지 문제가 남는다. 예를 들어 사용자가 다음 API를 호출했다고 생각해보자. POST /api/orders 요청이 다음과 같은 구조로 처리된다. 사용자 | v Nginx / Ingress | v FastAPI | +------> Redis | +------> PostgreSQL 그런데 사용자가 500 오류를 받았다. Prometheus에서는: HTTP 500 증가 를 확인할 수 있고, Loki에서는: Database connection timeout 이라는 로그를 찾을 수 있다. 하지만 다음 질문에는 바로 답하기 어렵다. 이 요청이 정확히 어떤 Pod를 거쳤는가? Redis 요청에는 몇 ms가 걸렸는가? PostgreSQL 쿼리에 몇 ms가 걸렸는가? 전체 요청 시간 중 어디에서 가장 많은 시간이 발생했는가? Nginx → FastAPI → Redis → PostgreSQL의 호출 관계는 어떻게 되는가? 이 문제를 해결하는 기술이 **Distributed Tracing(분산 추적)**이다. 이번 실습에서는 다음 구조를 구축한다. Client | v Ingress/Nginx | v FastAPI / \ / \ v v Redis PostgreSQL \ / \ / \ / v v OpenTelemetry | v OpenTelemetry Collector | v Tempo | v Grafana 1. Distributed Tracing이란? Distributed Tracing은 하나의 요청이 여러 시스템을 거쳐 처리되는 과정을 추적하는 기술이다. 예를 들어 사용자가 다음 API를 호출한다고 하자. GET /api/users/100 실제 내부에서는 다음과 같은 작업이 수행될 수 있다. HTTP Request | v FastAPI | +---- Redis GET | +---- PostgreSQL SELECT | v Response 이때 전체 요청을 하나의 Trace라고 한다. Trace 내부에는 여러 개의 Span이 존재한다. Trace | +-- Span: HTTP Request | +-- Span: Redis GET | +-- Span: PostgreSQL SELECT | +-- Span: Response 즉: Trace = 하나의 요청 전체 Span = 요청을 처리하는 각각의 작업 이라고 이해하면 쉽다. 2. Trace와 Span의 관계 분산 추적의 기본 개념은 반드시 이해해야 한다. 예를 들어 요청 하나가 다음과 같이 처리되었다고 하자. Trace ID abc123 그리고 내부 작업이: FastAPI HTTP Redis GET PostgreSQL SELECT 로 구성된다. 그러면: Trace: abc123 | +-- Span A: FastAPI HTTP | +-- Span B: Redis GET | +-- Span C: PostgreSQL SELECT 형태가 된다. Span에는 다음과 같은 정보가 들어갈 수 있다. Span ID Trace ID Service Name Operation Start Time End Time Duration Status Attributes 예: Trace ID: abc123 Span: PostgreSQL SELECT Duration: 83ms Status: OK 이 정보를 이용하면 어느 구간에서 시간이 오래 걸렸는지 확인할 수 있다. 3. OpenTelemetry란? OpenTelemetry는 애플리케이션의 Metrics, Logs, Traces와 같은 Telemetry 데이터를 수집하고 전달하기 위한 오픈 표준 및 프로젝트다. 이번 실습에서는 특히 Trace에 집중한다. Application | v OpenTelemetry SDK | v OpenTelemetry Collector | v Tempo OpenTelemetry의 장점은 특정 백엔드에 종속되지 않는다는 것이다. 예를 들어: OpenTelemetry | +---- Tempo +---- Jaeger +---- 다른 Trace Backend 와 같이 구성할 수 있다. 따라서 애플리케이션에 OpenTelemetry를 적용해 놓으면 나중에 Trace 저장 시스템을 변경하기도 상대적으로 편하다. 4. Tempo란? Tempo는 Grafana 생태계의 Distributed Tracing Backend다. 기존에 구축한 시스템과 비교하면 이해하기 쉽다. 역할 기술 Metrics Prometheus Logs Loki Traces Tempo Visualization Grafana Alerts Alertmanager Telemetry Collection OpenTelemetry Collector / Alloy 전체 구조는 다음과 같다. Observability | +--------------+--------------+ | | | v v v Metrics Logs Traces | | | Prometheus Loki Tempo | | | +--------------+--------------+ | v Grafana 이제 Kubernetes 환경에서 세 가지 데이터를 함께 볼 수 있게 된다. 5. 왜 로그만으로 부족한가? 예를 들어 Loki에서 다음 로그를 발견했다고 하자. Database query timeout 로그만 보면 PostgreSQL 문제가 의심된다. 하지만 실제 요청을 Trace로 보면: HTTP Request 500ms | +-- Redis GET 10ms | +-- PostgreSQL 450ms | +-- Response 40ms PostgreSQL에서 대부분의 시간이 소요되고 있다는 사실을 바로 확인할 수 있다. 반대로: HTTP Request 500ms | +-- Redis GET 470ms | +-- PostgreSQL 20ms 라면 Redis가 병목이다. 따라서 Distributed Tracing은 성능 병목 구간을 찾는 데 매우 유용하다. 6. 전체 Kubernetes 구조 이번 실습에서는 다음 환경을 기준으로 한다. Kubernetes Cluster namespace: tax-prod Internet | v Ingress/Nginx | v FastAPI / \ / \ v v Redis PostgreSQL Observability FastAPI | v OpenTelemetry SDK | v OTel Collector | v Tempo | v Grafana 그리고 기존 로그 시스템은: FastAPI/Nginx | v Grafana Alloy | v Loki Metrics는: FastAPI/Node/Pod | v Prometheus | v Grafana 로 구성한다. 7. Tempo 설치 먼저 Grafana Helm Repository를 등록한다. helm repo add grafana https://grafana.github.io/helm-charts Repository를 업데이트한다. helm repo update Tracing용 Namespace를 만든다. kubectl create namespace tracing 환경에 맞는 Tempo values 파일을 작성한다. vi tempo-values.yaml 학습 환경에서는 단일 인스턴스 형태로 시작할 수 있다. 예: deploymentMode: SingleBinary tempo: reportingEnabled: false resources: requests: cpu: 100m memory: 256Mi limits: cpu: 500m memory: 1Gi persistence: enabled: true size: 20Gi 설치: helm upgrade --install tempo grafana/tempo \ -n tracing \ -f tempo-values.yaml 상태 확인: kubectl get pods -n tracing kubectl get svc -n tracing 정상적으로 설치되었다면 Tempo Pod가 Running 상태인지 확인한다. 8. 운영 환경에서는 Storage가 중요하다 Trace 데이터도 계속 증가한다. 예를 들어: 1초에 100 requests | v Trace 데이터 지속 증가 따라서 운영 환경에서는 Storage를 고려해야 한다. 개념적으로: OpenTelemetry | v Tempo | v Object Storage | +-- S3 +-- MinIO +-- Cloud Storage 개발 환경에서는 Persistent Volume으로 시작할 수 있지만 운영 환경에서는 Object Storage 기반 설계를 검토하는 것이 좋다. 9. OpenTelemetry Collector란? OpenTelemetry Collector는 Telemetry 데이터를 중간에서 수집하고 전달하는 역할을 한다. 구조는 다음과 같다. FastAPI | | OTLP v OpenTelemetry Collector | | OTLP v Tempo Collector를 사용하는 이유는 애플리케이션과 Backend를 직접 연결하지 않아도 되기 때문이다. 예를 들어: Application | v Collector | +---- Tempo +---- 다른 Trace Backend 형태로 확장할 수 있다. Collector는 다음과 같은 기능을 수행할 수 있다. Receive Process Filter Batch Export 10. OpenTelemetry Collector 설치 Collector도 Kubernetes 환경에서 Helm으로 구성할 수 있다. OpenTelemetry Helm Repository를 등록한다. helm repo add open-telemetry \ https://open-telemetry.github.io/opentelemetry-helm-charts 업데이트: helm repo update Collector용 Namespace: kubectl create namespace observability Collector values 파일: vi otel-values.yaml 예제: mode: deployment image: repository: otel/opentelemetry-collector-k8s config: receivers: otlp: protocols: grpc: http: processors: batch: exporters: otlp: endpoint: tempo.tracing.svc.cluster.local:4317 tls: insecure: true service: pipelines: traces: receivers: - otlp processors: - batch exporters: - otlp 설치: helm upgrade --install otel-collector \ open-telemetry/opentelemetry-collector \ -n observability \ -f otel-values.yaml 확인: kubectl get pods -n observability 11. OTLP란? OpenTelemetry에서 중요한 개념이 **OTLP(OpenTelemetry Protocol)**다. Application에서 Collector로: FastAPI | | OTLP v Collector Collector에서 Tempo로: Collector | | OTLP v Tempo 형태로 데이터를 전달한다. OTLP는 gRPC와 HTTP 방식으로 사용할 수 있다. 대표적인 포트는: 4317 = OTLP gRPC 4318 = OTLP HTTP 따라서 Kubernetes Service를 구성할 때 이 포트를 확인해야 한다. 12. FastAPI에 OpenTelemetry 적용 이제 실제 애플리케이션에 OpenTelemetry를 적용한다. Python 패키지를 설치한다. pip install \ opentelemetry-api \ opentelemetry-sdk \ opentelemetry-exporter-otlp \ opentelemetry-instrumentation-fastapi FastAPI 자동 계측을 사용할 수 있다. 예: from fastapi import FastAPI from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor app = FastAPI() FastAPIInstrumentor.instrument_app(app) 이렇게 하면 FastAPI 요청에 대한 Trace를 자동으로 생성할 수 있다. 13. OTLP Exporter 설정 Collector로 Trace를 보내도록 설정한다. 예: from opentelemetry import trace from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter resource = Resource.create({ "service.name": "fastapi-backend" }) provider = TracerProvider( resource=resource ) exporter = OTLPSpanExporter( endpoint="otel-collector.observability.svc.cluster.local:4317", insecure=True ) provider.add_span_processor( BatchSpanProcessor(exporter) ) trace.set_tracer_provider(provider) 그리고 FastAPI instrumentation: from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor FastAPIInstrumentor.instrument_app(app) 구조는 다음과 같다. FastAPI | v TracerProvider | v OTLP Exporter | v Collector | v Tempo 14. Kubernetes 환경에서는 환경변수로 관리 운영 환경에서는 Collector 주소를 코드에 직접 넣는 것보다 환경변수를 사용하는 것이 좋다. 예: env: - name: OTEL_SERVICE_NAME value: "fastapi-backend" - name: OTEL_EXPORTER_OTLP_ENDPOINT value: "http://otel-collector.observability.svc.cluster.local:4317" - name: OTEL_EXPORTER_OTLP_INSECURE value: "true" 그러면 환경별로 쉽게 변경할 수 있다. 개발: otel-collector-dev 운영: otel-collector-prod 와 같이 분리할 수 있다. 15. Redis Trace 계측 FastAPI에서 Redis를 사용하는 경우 Redis 작업도 Trace에 포함시키면 좋다. OpenTelemetry에서는 Redis와 같은 라이브러리에 대한 instrumentation을 사용할 수 있다. 개념적으로: FastAPI Span | +-- Redis GET Span | +-- Redis SET Span 이렇게 된다. 예: Trace ID: abc123 FastAPI GET /users | +-- Redis GET user:100 | +-- PostgreSQL SELECT 이제 Redis에서 지연이 발생하는지 쉽게 확인할 수 있다. 16. PostgreSQL Trace 계측 Database도 마찬가지다. PostgreSQL을 사용하는 Python 애플리케이션에 Database instrumentation을 적용하면 SQL 관련 Span을 확인할 수 있다. 구조: FastAPI | +-- Redis | +-- PostgreSQL | +-- SELECT +-- INSERT +-- UPDATE 예를 들어 PostgreSQL SELECT가: Duration = 850ms 라고 나타난다면 Database query가 병목일 가능성이 높다. 17. 중요한 점 — SQL 정보와 보안 Database Trace에는 SQL 관련 정보가 포함될 수 있다. 따라서 운영 환경에서는 개인정보나 비밀번호 등의 민감한 데이터가 Trace에 들어가지 않도록 주의해야 한다. 좋지 않은 예: SELECT * FROM users WHERE password='123456' Trace에 민감한 정보가 그대로 남으면 안 된다. 따라서 다음을 고려한다. 민감 데이터 제거 SQL parameter masking Trace retention 설정 접근 권한 제한 18. 직접 Span 생성하기 자동 instrumentation만으로 부족한 경우 직접 Span을 만들 수 있다. 예: from opentelemetry import trace tracer = trace.get_tracer(__name__) 그리고: with tracer.start_as_current_span("calculate-tax"): result = calculate_tax() 이렇게 하면 다음과 같은 Span이 생성된다. FastAPI Request | +-- calculate-tax | +-- DB Query 복잡한 비즈니스 로직을 추적할 때 매우 유용하다. 19. Trace ID란? Distributed Tracing에서 가장 중요한 정보 중 하나가 Trace ID다. 예: Trace ID: 4bf92f3577b34da6a3ce929d0e0e4736 하나의 요청에 동일한 Trace ID가 연결된다. Nginx | | Trace ID = ABC v FastAPI | | Trace ID = ABC +------> Redis | | Trace ID = ABC +------> PostgreSQL 따라서 로그에도 Trace ID를 기록하면 강력한 장애 분석이 가능해진다. 20. Logs와 Trace 연결 앞에서 구축한 Loki와 결합하면 더욱 강력해진다. 예: Trace ID ABC123 FastAPI 로그: ERROR Database timeout trace_id=ABC123 Grafana에서 해당 Trace를 클릭하면: Trace | +-- FastAPI | +-- PostgreSQL 그리고 관련 로그를 바로 확인할 수 있다. 개념적으로: Trace ID | +--------+--------+ | | v v Tempo Loki | | +--------+--------+ | v Grafana 이것이 **Logs와 Traces의 상관관계(Correlation)**다. 21. Metrics와 Trace까지 연결 이제 Prometheus까지 연결한다. Prometheus | | Metrics v Grafana | +------ Loki | +------ Tempo 예를 들어 Dashboard에서: HTTP Error Rate | v 500 증가 | v 해당 시간대 Trace 확인 | v PostgreSQL Span 확인 | v Query 1.2초 | v 관련 Loki 로그 확인 | v Database timeout 이런 분석이 가능해진다. 22. Grafana에 Tempo 연결 Grafana에서: Connections ↓ Data Sources ↓ Add data source ↓ Tempo 를 선택한다. Tempo Service 주소를 입력한다. 예: http://tempo.tracing.svc.cluster.local:3200 환경에 따라 Service 이름과 포트는 실제 설치 결과를 확인해야 한다. kubectl get svc -n tracing 정상 연결을 확인한다. 23. Grafana Explore에서 Trace 확인 Grafana: Explore ↓ Tempo 를 선택한다. Trace ID를 이용해 검색할 수 있다. 예: Trace ID 4bf92f3577b34da6a3ce929d0e0e4736 결과는 다음과 같은 구조로 나타날 수 있다. Trace | +-- GET /api/users | +-- Redis GET | +-- PostgreSQL SELECT 각 Span을 클릭하면: Duration Attributes Status Service Operation 등을 확인할 수 있다. 24. Trace Waterfall 이해하기 Distributed Tracing에서 가장 중요한 화면 중 하나가 Waterfall이다. 예: 0ms 1000ms FastAPI |-----------------------------| | Redis |----| | PostgreSQL | |---------------| | Response |------------------------------| 이 화면을 보면 어느 작업이 오래 걸렸는지 바로 알 수 있다. 예를 들어: FastAPI 1000ms Redis 20ms PostgreSQL 850ms 라면 PostgreSQL이 병목이다. 반면: FastAPI 1000ms Redis 900ms PostgreSQL 30ms 라면 Redis가 병목이다. 25. 장애 상황 분석 실습 이제 실제 장애를 만들어보자. API: GET /api/users/100 를 호출한다. 정상 상태: FastAPI 100ms Redis 10ms PostgreSQL 30ms 그런데 PostgreSQL에 의도적으로 느린 Query를 발생시킨다. 결과: FastAPI 1200ms Redis 10ms PostgreSQL 1100ms Grafana Tempo에서 다음처럼 확인할 수 있다. GET /api/users/100 | +-- Redis GET 10ms | +-- PostgreSQL SELECT 1100ms 이것만으로도 Database가 병목이라는 것을 확인할 수 있다. 26. Loki와 함께 장애 분석 Tempo에서 느린 PostgreSQL Span을 찾았다. Trace ID: ABC123 이제 Loki에서 Trace ID를 검색한다. {app="backend"} |= "ABC123" 결과: Database connection timeout 그리고 PostgreSQL 로그: {app="postgres"} |= "timeout" 결과: connection pool exhausted 최종적으로: HTTP 500 | v FastAPI | v PostgreSQL Span 1100ms | v Loki | v connection pool exhausted 라는 장애 분석이 가능해진다. 27. 장애 테스트 — Redis 지연 이번에는 Redis를 느리게 만들어본다. FastAPI | v Redis | X 느린 응답 Trace: FastAPI 1000ms Redis 950ms PostgreSQL 20ms Waterfall에서 Redis Span이 길게 나타난다. 이런 방식으로 성능 병목을 빠르게 찾을 수 있다. 28. 장애 테스트 — PostgreSQL 장애 PostgreSQL Pod를 삭제한다. kubectl delete pod <postgres-pod> -n tax-prod FastAPI에서 DB API를 호출한다. Trace에서는: FastAPI | +-- PostgreSQL | +-- ERROR +-- Timeout 가 나타날 수 있다. 동시에 Loki에서는: Database connection refused 를 확인할 수 있다. Kubernetes에서는: kubectl get pods -n tax-prod 로 PostgreSQL Pod 상태를 확인한다. 이렇게 세 가지 정보를 연결한다. Tempo ↓ 어디에서 실패했는가? Loki ↓ 무슨 오류가 발생했는가? Kubernetes ↓ Pod/서비스 상태는 어떠한가? 29. Kubernetes에서 Trace Context 전달 Distributed Tracing에서 매우 중요한 개념이 Trace Context Propagation이다. 요청이: Client ↓ Nginx ↓ FastAPI ↓ Redis ↓ PostgreSQL 로 이동할 때 Trace Context가 전달되어야 한다. 대표적으로 W3C Trace Context가 사용된다. HTTP Header 예: traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01 이 정보를 기반으로 하나의 요청을 하나의 Trace로 연결할 수 있다. 30. Trace ID를 로그에 남기는 이유 운영 환경에서 다음과 같은 로그가 있다고 하자. ERROR Database timeout 이것만으로는 어떤 요청인지 알기 어렵다. 하지만: ERROR Database timeout trace_id=ABC123 라면 바로 Tempo에서 찾을 수 있다. 따라서 이상적인 구조는: Application Log | +-- timestamp +-- level +-- service +-- trace_id +-- span_id +-- message 이다. 31. Grafana에서 완성되는 Observability 이제 지금까지 구축한 모든 시스템을 연결해보자. Kubernetes | +----------------+----------------+ | | | v v v Metrics Logs Traces | | | Prometheus Loki Tempo | | | +----------------+----------------+ | v Grafana | +-------------+-------------+ | | | v v v Dashboard Logs Traces Alertmanager까지 연결하면: Prometheus | v Alertmanager | +-- Email +-- Slack +-- Webhook 구조가 된다. 32. 실제 장애 대응 흐름 운영 중 다음 알림이 발생했다고 가정하자. CRITICAL FastAPI HTTP 500 rate > 5% 운영자는 다음 순서로 확인한다. 1단계 — Metrics Prometheus에서: HTTP 500 증가 확인. 2단계 — Logs Loki에서: {app="backend"} |= "ERROR" 검색. 결과: Database timeout 3단계 — Trace Tempo에서 해당 요청 Trace를 확인. FastAPI | +-- Redis 10ms | +-- PostgreSQL 2.8s 4단계 — Kubernetes kubectl get pods -n tax-prod PostgreSQL 상태 확인. 5단계 — Database PostgreSQL 로그에서: connection pool exhausted 확인. 이제 단순히 "FastAPI 500 오류"가 아니라: PostgreSQL Connection Pool 부족 이라는 근본 원인까지 좁혀갈 수 있다. 33. Metrics + Logs + Traces의 역할 세 가지 기술의 역할을 명확히 구분하면 이해하기 쉽다. 데이터 질문 Metrics 문제가 발생하고 있는가? Logs 무슨 오류가 발생했는가? Traces 요청이 어디에서 느려지거나 실패했는가? 예: Metrics HTTP 500 증가 ↓ Logs Database timeout ↓ Trace PostgreSQL 2.8초 ↓ Kubernetes PostgreSQL Pod 상태 확인 ↓ Root Cause Connection Pool 문제 이것이 현대적인 Observability의 기본적인 장애 분석 방법이다. 34. Production 환경에서 주의할 점 Distributed Tracing을 운영 환경에 적용할 때는 몇 가지를 반드시 고려해야 한다. 34.1 모든 요청을 무조건 저장하지 않기 트래픽이 매우 많다면 모든 Trace를 저장하면 데이터 양이 증가한다. 따라서 Sampling을 사용할 수 있다. 예: 전체 요청 = 100% Trace 저장 = 10% 또는: 정상 요청 = 일부 Sampling 오류 요청 = 높은 우선순위 와 같은 전략을 고려할 수 있다. 35. Trace Sampling Sampling은 Trace 데이터의 양을 조절하는 방법이다. 예를 들어 초당: 10,000 requests 가 발생한다면 모든 Trace를 저장하는 것은 부담이 될 수 있다. 따라서: 10,000 requests | v Sampling | v 1,000 traces 처럼 줄일 수 있다. 다만 장애 분석을 위해 오류 Trace는 최대한 보존하는 전략을 고려할 수 있다. 36. Trace 데이터 보존 기간 Trace도 로그와 마찬가지로 보존 기간이 필요하다. 예: Hot Trace 7일 Archive 30일 Delete 90일 실제 보존 기간은 시스템 규모와 장애 분석 요구사항에 따라 결정한다. 37. Resource 제한 OpenTelemetry Collector도 Kubernetes Pod이므로 Resource 제한을 설정해야 한다. 예: resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi Trace가 증가하면 Collector 자체의 CPU와 Memory 사용량도 증가할 수 있다. 따라서 Prometheus에서 Collector를 모니터링하는 것이 좋다. Collector CPU Collector Memory Dropped Spans Export Errors Queue Size 등을 확인해야 한다. 38. Collector 장애도 모니터링해야 한다 다음 상황을 생각해보자. FastAPI | v Collector X | v Tempo Collector가 장애가 발생하면 Trace가 유실될 수 있다. 따라서: Application | v Collector | v Tempo 각 구간을 모니터링해야 한다. 특히 운영 환경에서는: Collector replicas Queue Retry Batch Resource 등을 고려해야 한다. 39. 개발/운영 환경 분리 앞서 Kubernetes 애플리케이션에서 개발과 운영 환경을 분리했듯이 Observability 환경도 분리할 수 있다. 예: Namespace | +-- tax-dev | +-- tax-prod | +-- observability | +-- tracing | +-- logging 또는: dev └── Trace prod └── Trace 환경을 구분할 수 있다. Trace에 다음 정보를 넣는 것도 좋다. deployment.environment=production 그러면 Grafana에서 개발/운영 데이터를 구분할 수 있다. 40. 최종 Kubernetes Observability Architecture 지금까지 작성한 Prometheus, Loki, Tempo를 모두 연결하면 다음과 같은 구조가 된다. Internet | v Ingress / Nginx | v FastAPI / | \ / | \ v v v Redis PostgreSQL Other Service Kubernetes Observability | +----------------+----------------+ | | | v v v Metrics Logs Traces | | | Prometheus Loki Tempo | | | +----------------+----------------+ | v Grafana | v Unified Observability | +----------+----------+ | | | v v v Dashboard Logs Trace | v Root Cause 여기에: Prometheus | v Alertmanager | +-- Email +-- Slack +-- Webhook 까지 추가하면 운영 환경에서 필요한 기본적인 Observability 구성이 완성된다. 41. 시스템 엔지니어가 반드시 기억해야 할 구조 전체 내용을 가장 간단하게 정리하면 다음과 같다. Prometheus | +-- CPU +-- Memory +-- Request +-- Error Rate +-- Latency Loki | +-- Application Log +-- Nginx Log +-- Kubernetes Log +-- Error Log Tempo | +-- Request Trace +-- Service Span +-- Redis Span +-- Database Span Grafana | +-- Metrics +-- Logs +-- Traces 그리고 장애가 발생하면: 1. Metrics "문제가 있는가?" 2. Logs "무슨 오류인가?" 3. Trace "어디에서 문제가 발생했는가?" 4. Kubernetes "Pod/Service/Node 상태는 정상인가?" 5. Root Cause "왜 문제가 발생했는가?" 순서로 접근하면 된다. 42. 최종 정리 Kubernetes 환경에서 애플리케이션이 복잡해질수록 단순한 kubectl logs만으로는 장애 원인을 찾기 어려워진다. 특히 다음과 같은 구조에서는 더욱 그렇다. Ingress ↓ Nginx ↓ FastAPI ↓ Redis ↓ PostgreSQL 하나의 사용자 요청이 여러 서비스를 통과하기 때문이다. 이때 Distributed Tracing을 사용하면: 사용자 요청 | v Trace ID | +-- Nginx | +-- FastAPI | +-- Redis | +-- PostgreSQL 전체 요청 흐름을 하나의 Trace로 확인할 수 있다. 이번 실습에서 구축한 핵심 구조는 다음과 같다. FastAPI | v OpenTelemetry SDK | v OpenTelemetry Collector | v Tempo | v Grafana 그리고 기존 시스템과 결합하면: Kubernetes | +-----------+-----------+ | | | v v v Metrics Logs Traces | | | Prometheus Loki Tempo | | | +-----------+-----------+ | v Grafana | v 장애 원인 분석 이제 Kubernetes Observability의 핵심 세 가지인 Metrics + Logs + Traces가 모두 연결되었다. 가장 중요한 것은 각각의 기술을 별도로 사용하는 것이 아니라 서로 연결하는 것이다. Prometheus "500 오류가 증가했다" ↓ Loki "Database timeout 로그가 발생했다" ↓ Tempo "PostgreSQL Span에서 2.8초가 소요되었다" ↓ Kubernetes "PostgreSQL Pod와 연결 상태를 확인한다" ↓ Root Cause "Database Connection Pool 부족" 이렇게 Metrics → Logs → Traces → Kubernetes → Root Cause로 연결해서 장애를 분석할 수 있다면 Kubernetes 운영에 필요한 Observability의 핵심 개념을 제대로 이해한 것이다.

댓글

아직 댓글이 없습니다.

로그인 후 댓글을 남길 수 있습니다.