티스토리 뷰
쿠버네티스 실습: 테넌트별 실시간 관측(Observability) 대시보드 구축
Grafana + Prometheus + Loki + Redis Stream 기반 API 사용량/에러율/비용 모니터링
앞선 글에서는 테넌트별 인증·API Key·Gateway 라우팅으로 구성된
SaaS API 플랫폼 핵심 구조를 완성했습니다.
이제는 실제 운영 단계에서 반드시 필요한 기능인 Observability(관측성) 을 구축합니다.
이번 글의 목표는 다음과 같습니다.
“각 테넌트(Tenant A, Tenant B…)가 자신의 API 사용량, 에러율, 응답 속도, 비용을
실시간으로 시각화하여 확인할 수 있는 대시보드를 제공하는 것.”
즉, SaaS 고객 포털에서 제공하는 ‘Usage Dashboard’ 를 직접 만드는 단계입니다.
(API Gateway 사용량 분석, Rate Limit 추적, 비용 모니터링까지 포함)
1. 전체 아키텍처
[Istio Gateway Access Log]
│
▼
[Loki / Promtail] ───────▶ Grafana “Tenant Logs”
│
├────────────────────▶ Redis Stream Queue → 실시간 처리
│
└────────────────────▶ Prometheus (latency, RPS, error rate)
│
▼
Grafana Dashboards
또한 Kubecost 데이터를 함께 연동해
→ “테넌트별 비용” 까지 하나의 대시보드에서 보여주는 구조를 목표로 합니다.
2. Istio Access Log 활성화
Istio Gateway에서 API 호출 로그를 일관된 형식(JSON)으로 출력하도록 설정합니다.
istio-telemetry.yaml
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: access-logs
namespace: istio-system
spec:
accessLogging:
- providers:
- name: envoy
disabled: false
일반적으로 Istio는 Envoy Proxy를 사용하므로
Access Log는 다음 항목을 자동으로 포함합니다:
- requestPath
- responseCode
- responseDuration
- apiKey (x-api-key 값)
- tenant (커스텀 라벨링)
3. Promtail로 Istio 로그 수집 → Loki 저장
promtail-config.yaml
server:
http_listen_port: 9080
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki.monitoring.svc:3100/loki/api/v1/push
scrape_configs:
- job_name: istio-gateway-logs
static_configs:
- targets:
- localhost
labels:
job: istio-gateway
__path__: /var/log/containers/istio-ingressgateway-*.log
설치:
helm repo add grafana https://grafana.github.io/helm-charts
helm install promtail grafana/promtail -f promtail-config.yaml -n monitoring
Loki로 전송된 로그는 Grafana에서 실시간 쿼리 가능해집니다.
4. 로그 라벨링: 테넌트별 분리
Istio VirtualService에서 API Key와 테넌트 정보를 로그 라벨로 포함합니다.
envoyFilter.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: add-tenant-label
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_request(request_handle)
local apiKey = request_handle:headers():get("x-api-key") or "none"
request_handle:streamInfo():dynamicMetadata():set("envoy.filters.http.lua", "tenant", apiKey)
end
결과:
Loki 로그에서 tenant="apikey-xxx" 형식으로 필터링 가능.
5. Prometheus 메트릭 수집 (RPS / Latency / Error)
Istio 기본 메트릭:
Metric 의미
| istio_requests_total | 서비스별 요청 수 |
| istio_request_duration_milliseconds | 지연시간 |
| istio_requests_error_rate | 에러율 |
테넌트 라벨별로 분리하려면 EnvoyFilter에서 tenant 라벨을 추가합니다.
metrics-config.yaml
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: tenant-metrics
namespace: istio-system
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_COUNT
tagOverrides:
tenant:
operation: UPSERT
value: apiKey
이제 Prometheus 메트릭에 다음처럼 라벨이 추가됩니다:
istio_requests_total{tenant="tenant-a", response_code="200"}
6. Redis Stream으로 이벤트 스트리밍
API 호출 기록을 Redis Stream으로 흘려보내면
→ 실시간 API 사용량 분석이 가능합니다.
NestJS Gateway에서 Hook 적용:
middleware.ts
import { Injectable, NestMiddleware } from "@nestjs/common";
import { Redis } from "ioredis";
@Injectable()
export class ApiLogMiddleware implements NestMiddleware {
private redis = new Redis(process.env.REDIS_URL);
use(req: any, res: any, next: () => void) {
const start = Date.now();
res.on("finish", () => {
const log = {
method: req.method,
path: req.originalUrl,
tenant: req.headers["x-api-key"] || "none",
status: res.statusCode,
duration: Date.now() - start,
timestamp: Date.now()
};
this.redis.xadd("api_stream", "*",
"tenant", log.tenant,
"path", log.path,
"status", log.status,
"duration", log.duration
);
});
next();
}
}
Redis Stream 사용 목적:
- 초당 호출 수(RPS) 실시간 분석
- Top Endpoints 계산
- 테넌트별 Rate Limit 적용 관계형 데이터 저장 없이 가능
7. Grafana 대시보드 구성
다음과 같은 Panel을 구성합니다:
① 테넌트별 API 호출 수
PromQL:
sum by (tenant) (rate(istio_requests_total[1m]))
② 테넌트별 평균 응답시간
histogram_quantile(
0.95,
sum(rate(istio_request_duration_milliseconds_bucket[5m])) by (tenant, le)
)
③ 에러율
sum(rate(istio_requests_total{response_code=~"5.."}[5m]))
/
sum(rate(istio_requests_total[5m]))
④ API 별 Top Usage (Loki Query)
{job="istio-gateway"} | json | stats count() by (tenant, requestPath)
⑤ 테넌트별 비용 (Kubecost)
Kubecost Data Source 활용:
kubecost_namespace_cost{namespace="team-a"}
8. SaaS 포털에 ‘내 API 현황’ 기능 제공
테넌트는 자신의 API 사용 내역을 확인할 수 있어야 합니다.
NestJS에서 Redis Stream → GraphQL API 구현:
usage.resolver.ts
@Query(() => [Usage])
async apiUsage(@Args("tenantId") tenantId: string) {
const entries = await this.redis.xrange("api_stream", "-", "+");
return entries
.filter(([_, fields]) => fields.includes(tenantId))
.map(([id, fields]) => ({
id,
tenant: fields[1],
path: fields[3],
status: fields[5],
duration: Number(fields[7])
}));
}
9. 활용 시나리오
시나리오 처리
| Tenant A가 RPS 급증 | Grafana 알림 + 자동 Rate Limit 조정 |
| API Key 유실 | Loki 로그에서 추적 → 즉시 비활성화 |
| Tenant B 비용 급증 | Kubecost 알림 → AIOps가 Pod 규모 조정 |
| 특정 API 오류률 증가 | Prometheus Alert → DevOps Slack 알림 |
10. 정리
이번 글에서 구축한 것은 실제 SaaS 업체들이 반드시 제공하는 “Usage Dashboard” 입니다.
✔ 테넌트별 API 사용량
✔ 응답 속도 / 에러율
✔ API Gateway 라우팅 현황
✔ 실시간 스트림 기반 사용 분석
✔ 비용 통계(Kubecost)
✔ 로그 검색(Loki)
결과적으로 하나의 Kubernetes 클러스터에서
“각 고객에게 독립적인 관측/청구/보안 환경”을 제공할 수 있는
프로덕션급 SaaS Observability Platform이 완성되었습니다.
다음 글에서는 이 기반 위에 테넌트별 Rate Limiting & Quota Enforcement 시스템을 구축합니다.
(API Gateway + Redis + EnvoyFilter + AIOps 예측 기반 Rate Control)
쿠버네티스,Observability,Grafana,Prometheus,Loki,RedisStream,SaaS플랫폼,APIUsage,Kubecost,모니터링
✅ 참고할 최신 자료
- Grafana Cloud에서 싱글 스택 vs 멀티 스택 구조로 테넌시를 관리하는 방법론이 정리되어 있습니다. (Grafana Labs)
- “How to Achieve Multi-tenant Observability with Grafana” 글에서는 로그 / 메트릭을 테넌트별로 분리하고 접근 제어하는 구체적인 아키텍처가 설명되어 있습니다. (gepardec.com)
- Kubecost를 이용해 네임스페이스 기반 비용 분리 및 테넌트별 청구 구조를 운영하는 사례도 존재합니다. (InfraCloud)
⚠️ 보완/강화 제안
- 로그/메트릭 테넌시 분리: 단순히 네임스페이스를 분리하는 것 외에도, 테넌트별로 데이터 소스(예: Prometheus 데이터베이스, Loki 인스턴스), 라벨 필터링, 권한 제어(RBAC/Label-Based Access Control)를 고려하면 좋습니다. 예컨대, Grafana 내에서 각 테넌트가 “자신의 라벨 tenant=…만 조회 가능”하도록 설계하는 방식.
- 데이터 지연/카디널리티 문제: 테넌트가 많아지면 로그 및 메트릭 데이터가 급증하고 쿼리 성능 저하될 수 있습니다. 이를 대비해 라벨 압축, 기간 제한, 별도 인제스팅 인프라 설계 고려사항을 넣으면 좋습니다.
- 비용 + 사용량 연동: 단순히 비용만 보여주는 것이 아니라 “사용량 증가 → 비용 급증” 흐름을 시각화하고, 알림 트리거(예: 예산 초과)도 포함하면 운영가치가 올라갑니다.
- 테넌트 온보딩 자동화 흐름: 새로운 테넌트가 들어올 때 Namespace 생성, 리소스쿼터 설정, 관측 대시보드 자동 생성, 비용 청구 그룹 연동 등을 스크립트로 자동화하면 SaaS 플랫폼으로서 완성도가 높아집니다.
- 보안 및 접근 제어: 관측 대시보드에서도 테넌트간 데이터 노출이 없도록 “테넌트별 로그인 → 해당 데이터만 조회 가능” 구조를 설명하는 것이 좋습니다.
'project > 맥미니로 시작하는 쿠버네티스' 카테고리의 다른 글
| 쿠버네티스 실습: SaaS 청구·과금(Billing) 시스템 구축 (0) | 2025.11.19 |
|---|---|
| 쿠버네티스 실습: 테넌트별 Rate Limiting & Quota Enforcement (0) | 2025.11.17 |
| 쿠버네티스 실습: SaaS형 API 플랫폼 구축 — 테넌트별 인증, OIDC, Redis, Gateway 통합 (0) | 2025.11.12 |
| 쿠버네티스 실습: 멀티 테넌트 SaaS 아키텍처 — 팀별 리소스 격리, 청구, 정책기반 자동화 (0) | 2025.11.06 |
| 쿠버네티스 실습: AI 기반 자율 확장(Auto-Scaling)과 비용 최적화 — 예측형 인프라 운영 설계 (0) | 2025.11.04 |
- Total
- Today
- Yesterday
- 쿠버네티스
- 웹개발
- rag
- node.js
- LangChain
- 개발블로그
- ai철학
- llm
- 생성형AI
- 딥러닝
- PostgreSQL
- Redis
- kotlin
- seo 최적화 10개
- JWT
- Express
- 백엔드개발
- Python
- Docker
- DevOps
- NestJS
- Prisma
- flax
- JAX
- nextJS
- fastapi
- REACT
- SEO최적화
- CI/CD
- Next.js
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
