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

Loki + Promtail/Grafana Alloy + Grafana로 FastAPI, Nginx, Kubernetes 로그를 한곳에서 검색하고 장애 원인을 분석

lmkfox · 2026-09-11 · 조회 3
Loki + Promtail/Grafana Alloy + Grafana로 FastAPI, Nginx, Kubernetes 로그를 한곳에서 검색하고 장애 원인을 분석
Kubernetes 로그 중앙화 실습 Loki + Promtail/Grafana Alloy + Grafana로 FastAPI, Nginx, Kubernetes 로그를 한곳에서 검색하고 장애 원인을 분석하기 Kubernetes 환경에서 애플리케이션이 하나뿐일 때는 kubectl logs만으로도 충분할 수 있다. 하지만 실제 운영 환경에서는 상황이 달라진다. FastAPI Pod가 여러 개 실행되고 있고, Nginx Ingress가 요청을 처리하며, PostgreSQL과 Redis 같은 인프라도 함께 운영된다면 장애가 발생했을 때 여러 Pod의 로그를 각각 확인해야 한다. 예를 들어 FastAPI Pod가 다음과 같이 3개 실행되고 있다고 가정해보자. backend-7d8f6c9f5-abcde backend-7d8f6c9f5-fghij backend-7d8f6c9f5-klmno 사용자 요청이 어느 Pod로 전달되었는지 모르는 상황에서 특정 요청의 오류를 찾으려면 각각의 로그를 확인해야 한다. kubectl logs backend-7d8f6c9f5-abcde kubectl logs backend-7d8f6c9f5-fghij kubectl logs backend-7d8f6c9f5-klmno Pod가 수십 개, 수백 개로 증가하면 이런 방식은 사실상 불가능하다. 이 문제를 해결하기 위해 사용하는 대표적인 기술이 **로그 중앙화(Log Centralization)**다. 이번 실습에서는 다음 구조를 구축한다. Kubernetes Cluster | +------------------+------------------+ | | | FastAPI Pod Nginx Pod Other Pods | | | +------------------+------------------+ | Container Logs | Node Log Collector | Grafana Alloy | v +-------------+ | Loki | | Log Storage | +-------------+ | v +-------------+ | Grafana | | Log Search | +-------------+ | v 장애 원인 분석 1. Kubernetes 로그는 어디에 저장되는가? 먼저 Kubernetes 로그 구조를 이해해야 한다. 컨테이너가 stdout 또는 stderr로 로그를 출력하면 Kubernetes가 해당 로그를 관리한다. 예를 들어 FastAPI에서 다음과 같이 로그를 출력한다고 하자. print("API request received") 또는 Python logging을 사용한다. import logging logger = logging.getLogger(__name__) logger.info("API request received") logger.error("Database connection failed") 컨테이너에서 출력된 로그는 일반적으로 Node의 컨테이너 로그 파일로 저장된다. 대표적으로 다음과 같은 형태를 생각할 수 있다. /var/log/containers/ 그리고 Kubernetes의 Pod 로그는 다음 명령으로 확인할 수 있다. kubectl logs <pod-name> 예: kubectl logs backend-7d8f6c9f5-abcde 실시간 로그는 다음과 같이 확인한다. kubectl logs -f backend-7d8f6c9f5-abcde 문제는 이 로그가 기본적으로 중앙 로그 시스템이 아니라 해당 Kubernetes 환경의 Node와 컨테이너 로그 구조에 의존한다는 것이다. 따라서 운영 환경에서는 별도의 로그 수집 시스템을 구축하는 것이 좋다. 2. 로그 중앙화가 필요한 이유 운영 서버에서 장애가 발생했다고 생각해보자. 사용자가 다음과 같은 오류를 보고한다. 로그인 버튼을 눌렀는데 500 오류가 발생합니다. 운영자는 다음을 확인해야 한다. Nginx ↓ Ingress ↓ FastAPI ↓ Redis ↓ PostgreSQL 문제가 어디에서 발생했는지 확인해야 한다. 기존 방식이라면 다음처럼 각각 확인해야 한다. kubectl logs nginx-pod kubectl logs backend-pod-1 kubectl logs backend-pod-2 kubectl logs backend-pod-3 kubectl logs redis-pod 로그 중앙화 환경에서는 Grafana에서 한 번에 검색할 수 있다. namespace="tax-prod" app="backend" level="error" 결과: 07:21:31 Database connection failed 07:21:31 sqlalchemy.exc.OperationalError 07:21:32 POST /api/login 500 즉, 문제 발생 ↓ 로그 검색 ↓ 오류 로그 확인 ↓ 관련 Pod 확인 ↓ 원인 분석 과정을 하나의 화면에서 수행할 수 있다. 3. Loki란 무엇인가? Loki는 Grafana 생태계에서 사용하는 로그 집계 시스템이다. Prometheus와 비교하면 이해하기 쉽다. 시스템 목적 Prometheus Metrics 저장 Loki Logs 저장 Grafana Metrics/Logs 시각화 Alertmanager Alert 전달 구조적으로 보면 다음과 같다. Metrics Application | v Prometheus | v Grafana Logs Application | v Alloy | v Loki | v Grafana Loki의 중요한 특징은 로그 전체를 무겁게 인덱싱하기보다는 라벨(label)을 중심으로 로그를 찾는 구조라는 점이다. 예를 들어 다음과 같은 라벨을 사용할 수 있다. namespace="tax-prod" app="backend" container="backend" pod="backend-xxx" 그리고 실제 로그 내용은 Loki에서 조회한다. 4. Loki와 Elasticsearch의 차이 로그 중앙화라고 하면 Elasticsearch도 많이 사용한다. 대표적인 구성은 다음과 같다. Fluent Bit ↓ Elasticsearch ↓ Kibana 또 다른 대표적인 구성은 다음과 같다. Grafana Alloy ↓ Loki ↓ Grafana 간단하게 비교하면 다음과 같다. 항목 Loki Elasticsearch Grafana 연동 매우 좋음 가능 구조 Label 중심 검색/인덱스 중심 운영 난이도 상대적으로 낮음 상대적으로 높음 Kubernetes 로그 적합 적합 Metrics 연계 Prometheus와 매우 자연스러움 별도 구성 리소스 사용 비교적 가벼움 상대적으로 큼 소규모 또는 중간 규모 Kubernetes 환경에서 Prometheus + Grafana를 이미 사용하고 있다면 Loki를 추가하는 방식이 매우 자연스럽다. 5. Promtail과 Grafana Alloy Loki에 로그를 보내기 위해 로그 수집기가 필요하다. 과거에는 Promtail이 대표적인 선택이었다. 구조는 다음과 같다. Node | +-- /var/log/containers | v Promtail | v Loki 하지만 현재 Grafana 생태계에서는 Grafana Alloy를 새로운 텔레메트리 수집기로 사용하는 방향이 중요하다. 따라서 새로운 환경을 구축한다면 Alloy 중심으로 설계하는 것을 권장할 수 있다. 개념적으로는 다음과 같다. Kubernetes Node | | Container Logs v Grafana Alloy | | Push v Loki | v Grafana 기존 환경에서 Promtail을 이미 사용하고 있다면 당장 모두 변경해야 한다는 의미는 아니다. 다만 신규 구축에서는 Alloy를 우선 검토하는 것이 좋다. 6. 전체 아키텍처 이번 실습에서는 다음과 같은 환경을 가정한다. Kubernetes Cluster namespace: tax-prod Internet | v Ingress | v Nginx | v FastAPI Service | +------+------+ | | v v FastAPI-1 FastAPI-2 | | +------+------+ | PostgreSQL | Redis Logging FastAPI/Nginx/PostgreSQL/Redis | v Container stdout | v Kubernetes Node | v Grafana Alloy | v Loki | v Grafana 7. Helm으로 Loki 설치 Kubernetes 환경에서는 Helm을 사용하는 것이 편리하다. 먼저 Grafana Helm Repository를 등록한다. helm repo add grafana https://grafana.github.io/helm-charts Repository 정보를 업데이트한다. helm repo update Loki용 Namespace를 생성한다. kubectl create namespace logging Namespace를 확인한다. kubectl get namespace 8. Loki 설치 실제 운영 환경에서는 Loki의 저장 방식과 복제 구조를 충분히 검토해야 한다. 학습 및 테스트 환경에서는 비교적 간단한 구성으로 시작할 수 있다. 예를 들어 Helm values 파일을 만든다. vi loki-values.yaml 예제: deploymentMode: SingleBinary loki: auth_enabled: false singleBinary: replicas: 1 persistence: enabled: true size: 20Gi resources: requests: cpu: 100m memory: 256Mi limits: cpu: 500m memory: 1Gi read: replicas: 0 write: replicas: 0 backend: replicas: 0 설치한다. helm upgrade --install loki grafana/loki \ -n logging \ -f loki-values.yaml 설치 상태를 확인한다. kubectl get pods -n logging 예: NAME READY STATUS loki-0 1/1 Running Service도 확인한다. kubectl get svc -n logging 9. Loki 로그 저장 구조 Loki는 로그를 저장해야 하기 때문에 운영 환경에서는 Storage 설계가 중요하다. 개념적으로 다음과 같다. Loki | +-- Index | +-- Chunks | +-- Object Storage 개발 환경에서는 로컬 Persistent Volume을 사용할 수 있지만 운영 환경에서는 Object Storage 기반 구성을 고려하는 것이 일반적이다. 예: Loki | +---- Object Storage | +-- S3 +-- MinIO +-- Cloud Storage 따라서 운영 환경에서는 다음을 고려해야 한다. 로그 보존 기간 로그 용량 스토리지 비용 복제 백업 장애 복구 10. Grafana에 Loki 연결 앞서 Prometheus + Grafana를 구축했다면 Grafana에 Loki Data Source를 추가한다. Grafana에서: Connections ↓ Data Sources ↓ Add data source ↓ Loki Loki Service 주소를 입력한다. 예: http://loki.logging.svc.cluster.local:3100 Kubernetes DNS 구조는 다음과 같다. loki | +-- logging namespace | +-- port 3100 따라서 클러스터 내부에서는 다음 주소로 접근할 수 있다. http://loki.logging.svc.cluster.local:3100 연결 테스트 후 정상적으로 연결되면 Grafana에서 Loki 로그를 조회할 수 있다. 11. Grafana Alloy 설치 이제 로그 수집기를 구성한다. Alloy는 Kubernetes Node의 컨테이너 로그를 읽어서 Loki로 전달하는 역할을 한다. 구조는 다음과 같다. /var/log/containers/*.log | v Grafana Alloy | v Loki Alloy는 모든 Node에서 로그를 수집해야 하기 때문에 일반적으로 DaemonSet 형태로 실행한다. Node 1 └── Alloy Node 2 └── Alloy Node 3 └── Alloy Helm을 이용하여 설치할 수 있다. helm repo add grafana https://grafana.github.io/helm-charts helm repo update Namespace를 준비한다. kubectl create namespace logging 환경에 맞는 Alloy Helm values를 구성한 뒤 설치한다. helm upgrade --install alloy grafana/alloy \ -n logging \ -f alloy-values.yaml 확인한다. kubectl get pods -n logging -o wide 정상이라면 각 Node에 Alloy Pod가 실행된다. NAME NODE alloy-abc node-01 alloy-def node-02 alloy-ghi node-03 12. Alloy가 해야 하는 일 Alloy가 수행하는 역할을 단계별로 보면 다음과 같다. 1. Node 로그 파일 탐색 ↓ 2. Kubernetes metadata 확인 ↓ 3. namespace 확인 ↓ 4. pod 확인 ↓ 5. container 확인 ↓ 6. label 생성 ↓ 7. Loki로 전송 예를 들어 실제 로그가 다음과 같다고 하자. 2026-09-10 07:20:31 Database connection failed Alloy가 Kubernetes metadata를 붙인다. namespace=tax-prod pod=backend-7d8f6c9f5-abcde container=backend app=backend 그러면 Grafana에서 다음처럼 검색할 수 있다. namespace="tax-prod" app="backend" 13. FastAPI 로그 만들기 FastAPI는 로그를 stdout으로 출력하는 구조로 만드는 것이 중요하다. 예: import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s" ) logger = logging.getLogger(__name__) API에서 로그를 출력한다. @app.get("/health") def health(): logger.info("health check") return {"status": "ok"} 오류 발생 시: logger.error("Database connection failed") 중요한 점은 로그를 컨테이너 내부 파일에만 저장하지 않는 것이다. 좋은 Kubernetes 애플리케이션 구조는 다음과 같다. FastAPI | +-- stdout | v Kubernetes | v Alloy | v Loki 14. Nginx 로그 Nginx에서도 access log와 error log를 확인할 수 있다. 예: 10.0.0.15 - - [10/Sep/2026:07:21:31 +0900] "GET /api/users HTTP/1.1" 200 오류가 발생하면: "GET /api/users HTTP/1.1" 502 이런 로그는 장애 분석에서 매우 중요하다. 예를 들어: Nginx | +-- 502 Bad Gateway 라면 다음 단계로 FastAPI Pod 상태를 확인해야 한다. 15. Grafana에서 Loki 로그 검색 Grafana에서: Explore ↓ Loki 를 선택한다. 가장 기본적인 검색은 다음과 같다. {namespace="tax-prod"} 특정 애플리케이션: {namespace="tax-prod", app="backend"} 특정 Pod: {pod="backend-7d8f6c9f5-abcde"} Nginx: {app="nginx"} 16. Error 로그 검색 로그 내용에 error가 포함된 로그를 검색할 수도 있다. {namespace="tax-prod"} |= "error" 대소문자를 고려하여 애플리케이션 로그 구조에 맞게 검색하는 것이 좋다. 예: {app="backend"} |= "ERROR" Database 오류: {app="backend"} |= "Database" HTTP 500: {app="backend"} |= "500" 17. Nginx 5xx 오류 찾기 Nginx 로그를 검색한다고 하자. {app="nginx"} |= "500" 또는: {app="nginx"} |= "502" 다음과 같이 장애 상황을 빠르게 확인할 수 있다. Nginx | +-- 200 +-- 200 +-- 200 +-- 502 +-- 502 +-- 502 502가 갑자기 증가했다면 Backend 문제일 가능성이 높다. 18. FastAPI 500 오류 분석 FastAPI에서 다음과 같은 로그가 발생했다고 가정한다. ERROR Database connection failed ERROR sqlalchemy.exc.OperationalError ERROR POST /api/users 500 Grafana에서: {app="backend"} |= "500" 으로 검색한다. 그다음 같은 시간대의 로그를 확인한다. 07:21:31 Database connection failed 07:21:31 OperationalError 07:21:31 POST /api/users 500 여기에서 단순히 HTTP 500이라는 결과만 보는 것이 아니라 그 앞에서 발생한 데이터베이스 오류까지 추적할 수 있다. 19. Kubernetes 로그와 애플리케이션 로그 연결 로그 중앙화의 핵심은 Kubernetes metadata다. 예를 들어 다음과 같은 정보가 있다고 하자. namespace = tax-prod deployment = backend pod = backend-xxx container = backend node = worker-01 장애가 발생했을 때: Grafana | +-- namespace +-- deployment +-- pod +-- container +-- node 를 기준으로 로그를 좁혀갈 수 있다. 예: {namespace="tax-prod", container="backend"} 특정 Node: {node="worker-01"} 특정 Pod: {pod="backend-xxx"} 20. 로그 검색과 Prometheus Metrics를 같이 사용하기 이 부분이 Kubernetes 모니터링에서 매우 중요하다. Prometheus는 숫자를 본다. CPU Memory Request Error Rate Pod Count Loki는 로그를 본다. ERROR Exception Connection failed Timeout Grafana에서는 이 둘을 함께 사용할 수 있다. 예를 들어 Prometheus에서: FastAPI HTTP 500 증가 가 확인되었다고 하자. 그렇다면 Loki에서 같은 시간대를 검색한다. {app="backend"} |= "500" 결과: Database connection timeout 다시 PostgreSQL 로그를 검색한다. {app="postgres"} |= "connection" 결과: too many connections 장애 원인이 연결 수 부족이라는 것을 확인할 수 있다. 즉, Prometheus | | "500 오류 증가" v Grafana | v Loki | | "Database timeout" v PostgreSQL 로그 | v 장애 원인 확인 이것이 Observability의 핵심이다. 21. 장애 테스트 1 — FastAPI Pod 삭제 실제 장애 상황을 만들어보자. 먼저 Pod를 확인한다. kubectl get pods -n tax-prod 예: backend-abc Running backend-def Running Pod 하나를 삭제한다. kubectl delete pod backend-abc -n tax-prod Deployment가 새로운 Pod를 생성한다. kubectl get pods -n tax-prod -w 이때 Loki에서 해당 Pod 로그를 확인한다. {namespace="tax-prod", app="backend"} 기존 Pod와 새 Pod의 로그를 비교할 수 있다. 22. 장애 테스트 2 — FastAPI CrashLoopBackOff 의도적으로 애플리케이션을 종료하도록 만들어보자. 예: raise Exception("Intentional failure") Pod 상태가 다음과 같이 변경될 수 있다. CrashLoopBackOff 확인: kubectl get pods -n tax-prod 그리고: kubectl logs <pod-name> -n tax-prod Grafana Loki에서도 오류 로그를 확인한다. {app="backend"} |= "Intentional failure" 이렇게 Kubernetes 상태와 실제 애플리케이션 로그를 연결할 수 있다. 23. 장애 테스트 3 — Nginx 502 Backend가 정상적으로 응답하지 않는 상황을 만들어보자. 구조: Client | v Nginx | X FastAPI Nginx에서는: 502 Bad Gateway 가 발생할 수 있다. Grafana에서: {app="nginx"} |= "502" 검색한다. 그리고 Backend 로그: {app="backend"} 를 같은 시간대에 확인한다. 이렇게 하면: Nginx 502 ↓ Backend connection failure ↓ FastAPI Pod 장애 와 같은 흐름을 확인할 수 있다. 24. 장애 테스트 4 — PostgreSQL 연결 장애 PostgreSQL Pod를 삭제해본다. kubectl delete pod <postgres-pod> -n tax-prod PostgreSQL이 재기동되는 동안 FastAPI에서 DB 요청을 발생시킨다. FastAPI 로그: Database connection failed connection refused timeout Grafana에서: {app="backend"} |= "connection" 을 검색한다. PostgreSQL 로그도 확인한다. {app="postgres"} 이렇게 하면 하나의 장애를 여러 컴포넌트의 로그를 통해 추적할 수 있다. 25. 장애 분석의 실제 순서 운영자가 가장 많이 사용하는 방식으로 정리하면 다음과 같다. ① 사용자 장애 신고 | v ② Grafana Dashboard | v ③ Prometheus Metrics 확인 | v ④ Error Rate 증가 확인 | v ⑤ Loki 로그 검색 | v ⑥ 오류 발생 Pod 확인 | v ⑦ Kubernetes 상태 확인 | v ⑧ 관련 서비스 로그 확인 | v ⑨ 근본 원인 분석 예를 들어: 500 증가 ↓ FastAPI 로그 검색 ↓ DB Timeout ↓ PostgreSQL 로그 확인 ↓ Connection Limit 초과 ↓ DB 연결 관리 설정 확인 이런 방식으로 장애를 좁혀간다. 26. 로그에 무엇을 남겨야 하는가? 로그 중앙화 시스템을 구축하는 것만으로 좋은 운영 환경이 만들어지는 것은 아니다. 애플리케이션 로그 자체가 잘 설계되어야 한다. 좋은 로그는 최소한 다음 정보를 포함하는 것이 좋다. 시간 로그 레벨 서비스 요청 정보 사용자 요청 처리 결과 오류 정보 Trace ID 예: 2026-09-10T07:21:31 ERROR backend POST /api/users request_id=abc123 Database connection failed 가능하다면 JSON 로그가 더 좋다. { "timestamp": "2026-09-10T07:21:31+09:00", "level": "ERROR", "service": "backend", "method": "POST", "path": "/api/users", "request_id": "abc123", "message": "Database connection failed" } 이렇게 하면 로그 검색과 분석이 훨씬 쉬워진다. 27. 로그 레벨 설계 대표적인 로그 레벨은 다음과 같다. Level 의미 DEBUG 상세 디버깅 INFO 정상적인 주요 동작 WARNING 주의가 필요한 상황 ERROR 오류 발생 CRITICAL 심각한 장애 운영 환경에서 모든 로그를 DEBUG로 남기면 로그 양이 지나치게 증가할 수 있다. 일반적으로: 개발 DEBUG 운영 INFO / WARNING / ERROR 와 같이 환경별로 로그 레벨을 조절하는 방법을 고려할 수 있다. 28. 로그 보존 기간 로그는 계속 쌓인다. 예를 들어 하루에 10GB의 로그가 발생한다면: 1일 = 10GB 7일 = 70GB 30일 = 300GB 따라서 반드시 보존 정책을 정해야 한다. 예: Application Log ↓ 7일 Hot Log ↓ 30일 Archive ↓ 90일 삭제 운영 환경에서는 업무와 보안 요구사항에 따라 보존 기간을 결정해야 한다. 29. 로그 비용을 줄이는 방법 로그 중앙화 시스템에서는 불필요한 로그를 줄이는 것도 중요하다. 예를 들어 다음과 같은 로그가 하루 수백만 건 발생한다고 하자. GET /health 200 Kubernetes readiness/liveness probe 때문에 발생하는 로그라면 실제 장애 분석에는 큰 도움이 되지 않을 수 있다. 따라서 다음과 같은 방법을 고려할 수 있다. 불필요한 DEBUG 로그 제거 Health Check 로그 제외 로그 레벨 조정 Label 개수 최소화 보존 기간 설정 특히 Loki에서는 label을 지나치게 많이 생성하지 않는 것이 중요하다. 30. Loki Label 설계에서 주의할 점 예를 들어 다음처럼 사용자 ID를 Label로 사용하는 것은 좋지 않다. user_id=123456 user_id=123457 user_id=123458 ... 값의 종류가 무한히 증가하는 Label을 사용하면 문제가 발생할 수 있다. 이런 값을 흔히 High Cardinality 문제라고 한다. 따라서 Label은 비교적 제한된 값을 사용하는 것이 좋다. 좋은 예: namespace app container node environment 주의해야 할 예: user_id request_id order_id session_id 이런 정보는 로그 본문에 넣고 필요할 때 검색하는 방식을 고려한다. 31. Prometheus + Loki + Grafana 통합 이제 지금까지 구축한 모니터링 시스템을 하나로 합쳐보자. Kubernetes | +-------------+-------------+ | | v v Application Kubernetes | Metrics | | v v stdout Prometheus | v Alloy | v Loki | | +-------------+-------------+ | v Grafana | +----------+----------+ | | | v v v Metrics Logs Alerts 여기에 Alertmanager까지 연결한다. Prometheus | v Alertmanager | +-- Email +-- Slack +-- Webhook +-- 기타 알림 이렇게 구성하면 Kubernetes의 관측성이 크게 향상된다. 32. Grafana Dashboard 구성 운영 환경에서는 Grafana Dashboard를 다음처럼 구성할 수 있다. +------------------------------------------------+ | Kubernetes Overview | +------------------------------------------------+ | CPU | Memory | Pod Status | | 62% | 71% | 20/20 | +------------------------------------------------+ | Request Rate | Error Rate | Latency | | 320 req/s | 0.8% | 120ms | +------------------------------------------------+ | Recent Errors | | Database timeout | | Redis connection refused | | HTTP 500 | +------------------------------------------------+ | Logs | | 07:21:31 ERROR Database connection failed | | 07:21:32 ERROR POST /api/users 500 | +------------------------------------------------+ 운영자는 Dashboard 하나에서 다음을 확인할 수 있다. 서버 상태 Pod 상태 CPU Memory Request Error Latency Logs 33. Metrics와 Logs를 함께 봐야 하는 이유 예를 들어 CPU가 95%라고 하자. Metrics만 보면: CPU = 95% 까지만 알 수 있다. 하지만 Loki에서 로그를 확인하면: ERROR Worker timeout Request processing delayed 를 확인할 수 있다. 반대로 로그에 다음이 있다고 하자. Database connection timeout Metrics를 보면: PostgreSQL Connection 95% 일 수 있다. 즉, Metrics = 무슨 문제가 발생했는가? Logs = 왜 문제가 발생했는가? 라는 관점으로 생각하면 이해하기 쉽다. 실제 운영에서는 둘을 함께 사용하는 것이 중요하다. 34. Kubernetes Observability의 3가지 축 지금까지 배운 내용을 정리하면 Kubernetes Observability는 크게 세 가지로 볼 수 있다. Observability | +----------+----------+ | | | v v v Metrics Logs Traces | | | Prometheus Loki Tempo | | | +----------+----------+ | Grafana Metrics CPU Memory Request Error Rate Latency Pod Count Logs ERROR Exception Timeout Connection refused Traces Request ↓ Nginx ↓ FastAPI ↓ Redis ↓ PostgreSQL 이번 실습에서는 Metrics와 Logs를 구축했다. 다음 단계에서는 Distributed Tracing을 추가할 수 있다. 35. 최종 아키텍처 이번 실습의 최종적인 Kubernetes 운영 구조를 정리하면 다음과 같다. Internet | v Kubernetes | +-------------+-------------+ | | v v Ingress Applications | | v +------+------+ Nginx | | | FastAPI Redis v FastAPI | v PostgreSQL Metrics -------- Node / Pod / Application | v Prometheus | v Grafana Logs -------- Containers | v Grafana Alloy | v Loki | v Grafana Alerts -------- Prometheus | v Alertmanager | +---- Email +---- Slack +---- Webhook 이제 단순히 Kubernetes에 애플리케이션을 배포하는 단계에서 벗어나 운영 상태를 관측하고 장애를 분석할 수 있는 환경이 만들어진다. 36. 시스템 엔지니어 관점에서 반드시 확인할 항목 Kubernetes 로그 중앙화를 구축했다면 다음 항목을 확인해야 한다. 로그 수집 kubectl get pods -n logging Alloy가 모든 Node에서 실행되는지 확인한다. Loki kubectl get pods -n logging kubectl get svc -n logging Grafana Loki Data Source가 정상인지 확인한다. 로그 검색 {namespace="tax-prod"} 오류 검색 {namespace="tax-prod"} |= "ERROR" Pod별 검색 {pod="backend-xxx"} 장애 테스트 kubectl delete pod <backend-pod> -n tax-prod 로그 유입 확인 Pod 재생성 이후 Grafana에서 새로운 Pod 로그가 정상적으로 나타나는지 확인한다. 37. 최종 정리 이번 실습에서는 Kubernetes 로그 중앙화의 기본 구조를 살펴봤다. 핵심 구성 요소는 다음과 같다. Grafana Alloy ↓ Loki ↓ Grafana 각각의 역할은 명확하다. Alloy = 로그 수집 Loki = 로그 저장 및 조회 Grafana = 로그 시각화 및 검색 그리고 이전에 구축한 시스템과 연결하면: Prometheus = Metrics Loki = Logs Alertmanager = Alerts Grafana = 통합 Dashboard 구조가 된다. 가장 중요한 것은 단순히 로그를 저장하는 것이 아니다. 실제 운영에서 중요한 것은 다음과 같은 장애 분석 과정이다. 사용자 오류 발생 ↓ Grafana 확인 ↓ Error Rate 증가 ↓ Loki 로그 검색 ↓ FastAPI 오류 확인 ↓ PostgreSQL 로그 확인 ↓ DB Connection 문제 발견 ↓ Kubernetes 상태 확인 ↓ 근본 원인 해결 이 과정을 자동화하고 체계화하면 Kubernetes 환경에서 장애가 발생했을 때 단순히 "Pod가 죽었습니다"라고 확인하는 수준을 넘어 언제, 어떤 서비스에서, 어떤 요청이, 어떤 이유로 실패했는지 추적할 수 있게 된다. 특히 시스템 엔지니어에게 중요한 것은 다음 세 가지를 연결해서 보는 능력이다. Metrics | v 이상 현상 발견 | v Logs | v 오류 원인 확인 | v Kubernetes | v 실제 장애 조치 여기에 다음 단계로 Distributed Tracing을 추가하면 다음과 같은 완성된 Observability 구조를 만들 수 있다. Kubernetes | +------------+------------+ | | | v v v Metrics Logs Traces | | | Prometheus Loki Tempo | | | +------------+------------+ | v Grafana | v 장애 원인 분석

댓글

아직 댓글이 없습니다.

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