Grafana 입문 7편. Grafana Cloud · Enterprise · IaC 깊이 — Grafana Cloud Free/Pro/Advanced 의 한도와 비용, Grafana Enterprise (SAML · LDAP · OAuth · Enterprise plugin · audit log · team sync · fine-grained access), Migration (OSS → Cloud · 반대), Provisioning (datasource · dashboard · alert 의 file-based), Dashboard as Code (Grafonnet · Terraform Provider · Helm chart), Multi-tenancy, CI/CD pipeline 의 통합. 운영 의 수동 클릭 제거 자리.
이 글은 Grafana 입문에서 운영까지 시리즈 7편이에요. 1~6편 = 기능 의 깊이. 7편 = production 의 자동화 + 의식.
이번 글의 범위
수동 클릭 운영 = 작은 환경 OK, 큰 환경 X. Grafana 의 IaC(Infrastructure as Code, 인프라를 코드로 관리) + Cloud 의 trade-off(맞바꿈) + Enterprise 의 보안 의식 = 큰 회사 의 표준.
| 자리 | 자산 |
|---|---|
| Hosting | Cloud (Free/Pro/Advanced) vs OSS self-host |
| Enterprise | SAML · LDAP · Audit · Fine-grained Access |
| IaC | Provisioning · Terraform · Grafonnet · Helm |
| Migration | OSS ↔ Cloud · Backup · Restore |
Grafana Cloud — Hosting
3 Tier
┌──────────────────────┬──────────────────────────────────┐
│ Tier │ 한도 / 비용 │
├──────────────────────┼──────────────────────────────────┤
│ Free │ 10k metrics · 50GB logs/traces │
│ │ 3 user · 14일 retention │
│ │ $0 / 월 │
├──────────────────────┼──────────────────────────────────┤
│ Pro (Cloud Pro) │ 더 큰 한도 (사용량 별 청구) │
│ │ SLA 99.95% │
│ │ SSO · Reporting │
│ │ ~$50 / 월 부터 │
├──────────────────────┼──────────────────────────────────┤
│ Advanced │ 무제한 한도 │
│ │ Multi-tenancy │
│ │ Dedicated support │
│ │ Custom pricing │
└──────────────────────┴──────────────────────────────────┘
Cloud 의 가치
1. 운영 부담 제거
- 인프라 관리 X (Grafana Labs 가 운영)
- upgrade 자동
- HA · 백업 자동
2. 통합 stack
- Mimir · Loki · Tempo · Pyroscope · OnCall 모두 통합
- 한 UI 의 모든 신호
3. 빠른 시작
- Free Tier 즉시 사용
- 회사 신용카드 없이도 시험 가능
Cloud 의 비용 함정
한도 초과 시:
- Free → Pro 자동 전환 (의도 안 한 청구)
- Pro 의 단가 × 사용량 = 큰 청구
예 — 1TB logs / 일 의 비용:
- Free Tier: 50GB → 즉시 초과
- Pro: $0.50 / GB → $500 / 일 → $15,000 / 월
해결:
- 한도 모니터 (자동 alert)
- Self-host 와 비용 비교
- Hybrid (UI Cloud + 데이터 self-host)
Hybrid 패턴
가장 흔한 운영:
- Grafana Cloud (UI · dashboard · alert)
- 회사 의 Prometheus (metric scrape · short-term)
- 회사 의 Loki (log aggregation)
- 회사 의 Tempo (trace)
- Remote write — 회사 → Cloud (선택적)
장점:
- 운영 부담 절감 (UI · alert 부분)
- 데이터 privacy (회사 안)
- 비용 효율 (Cloud 무료/저가 tier 가능)
여기서 시험 함정이 하나 있어요. Free Tier 만 사용 하려고 했지만 서서히 한도 초과 → 자동 Pro 청구. 매월 한도 의 모니터 + alert 필수.
Grafana Enterprise
Enterprise 의 추가 기능
1. SAML · LDAP · OAuth (SSO)
2. Team Sync (LDAP/SAML 의 그룹 동기화)
3. Fine-grained Access Control (RBAC)
4. Audit Log
5. Enterprise Plugins (Snowflake · Splunk · ServiceNow · Oracle · SAP · MongoDB · Datadog · New Relic · ...)
6. Reporting (PDF · scheduled)
7. White-labeling
8. Recorded Queries
9. Data source permissions
10. Query Caching
SAML SSO
SAML(Security Assertion Markup Language, 인증 정보 교환 표준)과 SSO(Single Sign-On, 통합 로그인) 조합이에요.
# /etc/grafana/grafana.ini
[auth.saml]
enabled = true
certificate_path = /etc/grafana/saml/certificate.crt
private_key_path = /etc/grafana/saml/private.key
idp_metadata_url = https://idp.company.com/saml/metadata
assertion_attribute_name = displayName
assertion_attribute_login = uid
assertion_attribute_email = email
assertion_attribute_groups = groups
→ 회사 SSO (Okta · OneLogin · Azure AD · Google Workspace) 결합.
Team Sync
[auth.saml]
# ... 위 의 SAML config
# Team mapping
# Mapping syntax: group → team
team_mapping = company-backend:Backend Team, company-frontend:Frontend Team
→ SAML 의 그룹 의 자동 team 등록. 새 직원 = onboarding(입사 초기 자동 권한 부여) 즉시 권한.
Fine-grained Access Control
RBAC(Role-Based Access Control, 역할 기반 권한 관리)의 세밀 버전이에요.
표준 Role:
- Viewer · Editor · Admin
Enterprise 의 세밀 control:
- dashboard:read
- dashboard:write
- alert.rules:read
- alert.rules:write
- datasource:query
- users:create
- ...
→ 각 사용자 · team 의 정밀 권한 부여
Audit Log
모든 변경 추적:
- 누가 (user)
- 언제 (timestamp)
- 무엇 (action — create/update/delete)
- 어디 (dashboard ID · alert ID)
- 결과 (success · failure)
외부 export:
- Syslog · File · Loki · DB
Enterprise Plugins
공식 vs Enterprise plugin:
공식 (무료): Prometheus · Loki · Tempo · 100+
Enterprise (유료):
- Snowflake
- Splunk
- ServiceNow
- Oracle
- SAP HANA
- MongoDB Atlas
- Datadog
- New Relic
- DynamoDB
- GitLab
- ...
Enterprise 의 직접 연결 — 기존 회사 시스템 통합 매우 단순.
Provisioning — File-based Setup
의도
수동 setup:
- UI 클릭 으로 datasource 추가
- UI 클릭 으로 dashboard import
- UI 클릭 으로 alert 추가
문제:
- 재현 X (재해 복구)
- 사람 마다 다른 setup
- staging vs production 의 drift
Provisioning Config
/etc/grafana/provisioning/
├─ datasources/
│ └─ datasources.yaml
├─ dashboards/
│ ├─ dashboards.yaml ← provider config
│ └─ json/
│ ├─ api-dashboard.json
│ ├─ kubernetes-dashboard.json
│ └─ ...
├─ alerting/
│ └─ rules.yaml
├─ notifiers/ ← deprecated · Contact Point
└─ plugins/
└─ plugins.yaml
Datasources Provisioning
# /etc/grafana/provisioning/datasources/datasources.yaml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false ← UI 에서 수정 X
- name: Loki
type: loki
access: proxy
url: http://loki:3100
editable: false
jsonData:
maxLines: 5000
derivedFields:
- datasourceUid: tempo-uid
matcherRegex: 'trace_id=(\w+)'
name: TraceID
url: '${__value.raw}'
- name: Tempo
type: tempo
uid: tempo-uid
access: proxy
url: http://tempo:3200
editable: false
jsonData:
tracesToLogsV2:
datasourceUid: loki-uid
tags: [{ key: 'service.name', value: 'service' }]
→ Grafana 재시작 = 자동 datasource 등록 · 업데이트.
Dashboards Provisioning
# /etc/grafana/provisioning/dashboards/dashboards.yaml
apiVersion: 1
providers:
- name: 'company-dashboards'
orgId: 1
folder: 'Company'
type: file
disableDeletion: true ← 자동 삭제 안 함
editable: false ← UI 에서 수정 X
updateIntervalSeconds: 10 ← 10초 마다 파일 변화 watching
options:
path: /etc/grafana/provisioning/dashboards/json
foldersFromFilesStructure: true ← 디렉토리 = folder
/etc/grafana/provisioning/dashboards/json/
├─ infrastructure/
│ ├─ kubernetes-cluster.json
│ └─ aws-billing.json
├─ applications/
│ ├─ api-service.json
│ └─ frontend-service.json
└─ business/
├─ revenue.json
└─ customer-funnel.json
→ 디렉토리 그대로 folder 자동 생성.
Alert Rules Provisioning
# /etc/grafana/provisioning/alerting/rules.yaml
apiVersion: 1
groups:
- orgId: 1
name: api_slo_alerts
folder: Production Alerts
interval: 1m
rules:
- uid: api-slo-burn-fast
title: ApiSloBurnFast
condition: B
data:
- refId: A
datasourceUid: prometheus-uid
model:
expr: |
(
sum(rate(http_requests_total{service="api",status=~"5.."}[1h])) /
sum(rate(http_requests_total{service="api"}[1h]))
) > (14.4 * 0.001)
intervalMs: 60000
for: 2m
labels:
severity: critical
team: backend
annotations:
summary: "API error budget burning 14.4x faster"
runbook_url: "https://wiki.company.com/runbooks/api-slo-burn"
Terraform Grafana Provider
Terraform(HashiCorp 의 IaC 도구) 의 Grafana provider.
Setup
terraform {
required_providers {
grafana = {
source = "grafana/grafana"
version = "~> 3.0"
}
}
}
provider "grafana" {
url = "https://grafana.company.com"
auth = var.grafana_admin_token # Service Account token
}
Datasource
resource "grafana_data_source" "prometheus" {
type = "prometheus"
name = "Prometheus"
url = "http://prometheus:9090"
json_data_encoded = jsonencode({
timeInterval = "30s"
})
}
resource "grafana_data_source" "loki" {
type = "loki"
name = "Loki"
url = "http://loki:3100"
json_data_encoded = jsonencode({
maxLines = 5000
derivedFields = [
{
datasourceUid = grafana_data_source.tempo.uid
matcherRegex = "trace_id=(\\w+)"
name = "TraceID"
url = "$${__value.raw}"
}
]
})
}
Folder · Dashboard
resource "grafana_folder" "infrastructure" {
title = "Infrastructure"
}
resource "grafana_dashboard" "kubernetes" {
folder = grafana_folder.infrastructure.uid
config_json = file("${path.module}/dashboards/kubernetes.json")
}
resource "grafana_folder_permission" "infrastructure_perm" {
folder_uid = grafana_folder.infrastructure.uid
permissions {
role = "Viewer"
permission = "View"
}
permissions {
team_id = grafana_team.infra.id
permission = "Edit"
}
}
Team
resource "grafana_team" "backend" {
name = "Backend Team"
email = "backend@company.com"
members = [
"alice@company.com",
"bob@company.com",
]
}
resource "grafana_team" "frontend" {
name = "Frontend Team"
email = "frontend@company.com"
}
Alert Rule
resource "grafana_rule_group" "api_alerts" {
name = "API Alerts"
folder_uid = grafana_folder.alerts.uid
interval_seconds = 60
rule {
name = "ApiSloBurnFast"
condition = "B"
data {
ref_id = "A"
datasource_uid = grafana_data_source.prometheus.uid
model = jsonencode({
expr = "sum(rate(http_requests_total{service=\"api\",status=~\"5..\"}[1h])) / sum(rate(http_requests_total{service=\"api\"}[1h])) > 0.0144"
})
}
for = "2m"
labels = {
severity = "critical"
team = "backend"
}
annotations = {
summary = "API error budget burning 14.4x faster"
runbook_url = "https://wiki.company.com/runbooks/api-slo-burn"
}
}
}
Contact Point · Notification Policy
resource "grafana_contact_point" "slack_backend_critical" {
name = "slack-backend-critical"
slack {
url = var.slack_webhook_backend
recipient = "#alerts-backend-critical"
}
}
resource "grafana_contact_point" "pagerduty_oncall" {
name = "pagerduty-oncall"
pagerduty {
integration_key = var.pagerduty_integration_key
severity = "critical"
}
}
resource "grafana_notification_policy" "policy" {
contact_point = grafana_contact_point.default.name
group_by = ["alertname", "cluster", "service"]
group_wait = "30s"
group_interval = "5m"
repeat_interval = "4h"
policy {
matcher {
label = "severity"
match = "="
value = "critical"
}
contact_point = grafana_contact_point.pagerduty_oncall.name
continue = true
policy {
matcher {
label = "team"
match = "="
value = "backend"
}
contact_point = grafana_contact_point.slack_backend_critical.name
}
}
}
Grafonnet — Jsonnet 의 Dashboard
의도
JSON 직접 작성 = 매우 verbose.
Grafonnet (Jsonnet 의 library) = 깔끔한 dashboard 정의.
Jsonnet(JSON 의 템플릿 확장 언어)으로 dashboard 를 정의해요.
예
local g = import 'github.com/grafana/grafonnet/main.libsonnet';
local service_var =
g.dashboard.variable.query.new('service', 'label_values(service)')
+ g.dashboard.variable.query.withDatasource('Prometheus')
+ g.dashboard.variable.query.withIncludeAll();
local rps_panel =
g.panel.timeSeries.new('RPS by service')
+ g.panel.timeSeries.queryOptions.withTargets([
g.query.prometheus.new(
'Prometheus',
'sum(rate(http_requests_total{service=~"$service"}[5m])) by (service)'
)
])
+ g.panel.timeSeries.gridPos.withW(12)
+ g.panel.timeSeries.gridPos.withH(8);
local error_panel =
g.panel.timeSeries.new('Error rate by service')
+ g.panel.timeSeries.queryOptions.withTargets([
g.query.prometheus.new(
'Prometheus',
'sum(rate(http_requests_total{service=~"$service",status=~"5.."}[5m])) by (service) / sum(rate(http_requests_total{service=~"$service"}[5m])) by (service)'
)
])
+ g.panel.timeSeries.gridPos.withW(12)
+ g.panel.timeSeries.gridPos.withH(8)
+ g.panel.timeSeries.gridPos.withX(12);
g.dashboard.new('Service Overview')
+ g.dashboard.withVariables([service_var])
+ g.dashboard.withPanels([rps_panel, error_panel])
빌드:
# Jsonnet → JSON
jsonnet -J vendor service-overview.libsonnet > service-overview.json
# Provisioning 의 디렉토리 에 복사
cp service-overview.json /etc/grafana/provisioning/dashboards/json/
Generator Pattern
local generateServiceDashboard(serviceName) =
g.dashboard.new('Service: ' + serviceName)
+ g.dashboard.withPanels([
generateRpsPanel(serviceName),
generateErrorPanel(serviceName),
generateLatencyPanel(serviceName),
]);
{
'api-dashboard.json': generateServiceDashboard('api'),
'frontend-dashboard.json': generateServiceDashboard('frontend'),
'worker-dashboard.json': generateServiceDashboard('worker'),
}
한 함수 = 여러 dashboard 자동 생성. DRY (Don't Repeat Yourself, 반복 제거 원칙).
Helm Chart
Helm(쿠버네티스 의 패키지 매니저) 의 chart 예시예요.
표준 chart
# 1. Grafana 의 OSS chart
helm install grafana grafana/grafana
# 2. LGTM stack 의 chart
helm install loki grafana/loki-stack \
--set grafana.enabled=true \
--set prometheus.enabled=true \
--set promtail.enabled=false \
--set alloy.enabled=true
# 3. Mimir 의 chart (대규모)
helm install mimir grafana/mimir-distributed
Values 의 IaC
# values.yaml
grafana:
enabled: true
adminPassword: "${GRAFANA_PASSWORD}"
persistence:
enabled: true
storageClassName: gp3
size: 10Gi
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus-server
isDefault: true
- name: Loki
type: loki
url: http://loki:3100
dashboards:
default:
kubernetes-cluster:
gnetId: 13332
revision: 12
datasource: Prometheus
alerting:
rules.yaml:
apiVersion: 1
groups:
- name: api_alerts
# ...
smtp:
enabled: true
host: smtp.company.com:587
user: alerts@company.com
password: "${SMTP_PASSWORD}"
ArgoCD 의 통합
ArgoCD(쿠버네티스 의 GitOps CD 도구) 결합 예예요.
# argocd/grafana-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: grafana
spec:
project: default
source:
repoURL: https://github.com/company/grafana-config
targetRevision: HEAD
path: charts/grafana
helm:
valueFiles:
- values.yaml
- values-prod.yaml
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true
GitOps(git 저장소를 단일 진실 소스로 운영) — git push = Grafana 자동 update.
Migration — OSS ↔ Cloud
OSS → Cloud
1. Dashboard export (JSON)
- Grafana UI > Settings > Export
- 또는 API: GET /api/dashboards/uid/<uid>
2. Data 의 backfill (필요 시)
- Mimir 의 remote write
- 회사 의 Prometheus → Cloud Mimir
3. Alert rule export
- YAML 또는 JSON
- Cloud 에 import
4. User · Team migration
- SAML/OAuth 의 통합
- 또는 manual user 등록
5. Datasource 재설정
- Cloud 의 datasource URL · 인증
Cloud → OSS (자체 운영 전환)
1. Cloud 의 backup
- Dashboard JSON export (모두)
- Alert rule export
- Data source 의 config 기록
2. OSS 의 cluster 구축
- Helm chart 의 Grafana + LGTM stack
- Provisioning 의 config
3. Data migration
- Mimir 의 historical data export
- 또는 retention 만 새 stack 으로
4. DNS · authentication 전환
함정 정리
사고 1: Free Tier 한도 초과 → Pro 자동 청구
원인 — 한도 모니터 안 함 + 점진 증가 → 자동 Pro 활성 → 큰 청구.
해결 — Cloud 의 usage alert 활성 + credit limit 설정.
사고 2: Provisioning + UI 의 drift
원인 — Provisioning 으로 박은 dashboard 를 UI 에서 수정 → 다음 reload 시 덮어쓰기 또는 conflict.
해결 — editable: false 의 강제. UI 수정 시도 = error.
사고 3: Terraform 의 state 손실
원인 — terraform.tfstate 파일 손실 + 백업 없음 → 모든 리소스 의 unknown → 재 설정.
해결 — Remote backend (S3 · Terraform Cloud) 의 state.
사고 4: Helm chart 의 secret 평문
원인 — values.yaml 에 admin password · API key 평문 + git commit.
해결 — External Secret · Vault · Sealed Secret 의 secret 관리.
사고 5: Audit Log 의 미사용
원인 — Enterprise 의 audit log 기능 있지만 export 안 함 → 사고 시 추적 X.
해결 — Loki 또는 syslog 의 export + 주기적 review.
사고 6: SAML 의 group mapping 잘못
원인 — SAML 의 group 이름과 Grafana 의 team mapping mismatch → 새 사용자 = no team.
해결 — test 사용자 의 검증 + mapping 의 정확한 매핑 syntax.
사고 7: Migration 시 dashboard URL 변경
원인 — Cloud → OSS 의 migration → URL 변경 → 모든 dashboard 의 외부 link · annotation 깨짐.
해결 — URL alias · redirect + migration 의 communication.
사고 8: Grafonnet 의 version 변화
원인 — Grafonnet의 major version up → API 변경 → 모든 dashboard 빌드 실패.
해결 — lock file 의 version 고정 + upgrade 시 의 test.
사고 9: Plugin 의 보안 CVE
CVE(Common Vulnerabilities and Exposures, 공개 보안 취약점 식별자) 추적이 빠질 때예요.
원인 — Enterprise plugin 의 CVE → 즉시 patch 안 함 → 보안 사고.
해결 — Plugin upgrade 의 자동 알림 + 주기적 CVE review.
사고 10: Helm upgrade 의 datasource 손실
원인 — Helm upgrade → PVC(쿠버네티스 의 영속 볼륨 클레임) 변경 → 의 datasource config 손실.
해결 — Provisioning 의 file-based config + PVC 의 안전 upgrade pattern.
운영 권장 패턴
Pattern 1: Production Stack 의 표준
# Helm + ArgoCD
monitoring/
├── grafana/
│ ├── values.yaml # 표준 values
│ ├── values-prod.yaml # production 의 override
│ ├── dashboards/ # provisioning
│ │ ├── infrastructure/
│ │ ├── applications/
│ │ └── business/
│ ├── alerting/
│ │ └── rules.yaml
│ └── datasources/
│ └── datasources.yaml
├── loki/
│ └── values.yaml
├── tempo/
│ └── values.yaml
└── prometheus/
└── values.yaml
ArgoCD 의 자동 sync.
Pattern 2: IaC 의 layer 분리
Terraform: 인프라 · 권한 · 통합 (외부 시스템)
Helm: 배포 · upgrade · scaling
Provisioning: 운영 config (datasource · dashboard · alert)
각 layer = 다른 lifecycle. 분리 = 변경 risk 최소.
Pattern 3: Dashboard as Code 의 표준 workflow
Developer:
1. Git branch 만들기
2. Grafonnet 또는 JSON 으로 dashboard 수정
3. Local 의 빌드 + preview
4. PR 만들기
CI:
1. Jsonnet → JSON 빌드
2. Schema validation
3. Preview environment 에 deploy
4. Visual diff 자동 (Grafana Preview)
Review:
1. PR review (코드 + preview screenshot)
2. Approve
CD:
1. Production 자동 deploy
2. ArgoCD 의 sync
Pattern 4: Cost 관리 자동
# Cloud usage 모니터
import requests
def check_grafana_cloud_usage():
response = requests.get(
"https://grafana.com/api/orgs/{org}/usage",
headers={"Authorization": f"Bearer {API_TOKEN}"}
)
usage = response.json()
# 한도 알림
if usage['metrics']['used'] / usage['metrics']['limit'] > 0.8:
slack_alert(f"⚠️ Metrics 한도 80% 도달")
if usage['logs']['used'] / usage['logs']['limit'] > 0.8:
slack_alert(f"⚠️ Logs 한도 80% 도달")
if usage['traces']['used'] / usage['traces']['limit'] > 0.8:
slack_alert(f"⚠️ Traces 한도 80% 도달")
# 비용 예측
monthly_estimate = calculate_monthly_estimate(usage)
if monthly_estimate > MONTHLY_BUDGET:
slack_alert(f"💰 월 예상 비용 {monthly_estimate} > budget {MONTHLY_BUDGET}")
매일 cron — Cost 의식 + 한도 도달 의 자동 인지.
Pattern 5: Disaster Recovery
주기적 backup:
매일 01:00 KST:
- 모든 dashboard JSON export
- 모든 alert rule export
- 모든 datasource config export
- S3 의 backup bucket 에 저장
retention:
- 7 daily backup
- 4 weekly backup
- 12 monthly backup
복원:
1. backup 의 download
2. Terraform · Provisioning 의 apply
3. 검증
Pattern 6: Multi-tenant 의 분리
환경:
- prod-tenant Production data + tighter access
- staging-tenant Pre-production
- dev-tenant Developer 자유
각 tenant:
- 독립 datasource
- 독립 dashboard folder
- 독립 alert
- 독립 권한
Grafana Cloud 의 multi-org 또는 OSS 의 multi-tenancy.
시험 직전 한 번 더 — Cloud · IaC 압축 노트
Grafana Cloud
- Free — 10k metrics · 50GB logs/traces · 3 user · 14일 retention
- Pro — 사용량 별 청구 · SLA · SSO
- Advanced — 무제한 · multi-tenancy · dedicated support
- Hybrid — UI Cloud + 데이터 self-host (가장 흔함)
- 비용 함정 (자동 Pro 전환) → usage alert 필수
Enterprise
- SAML · LDAP · OAuth (SSO)
- Team Sync (그룹 → team 자동)
- Fine-grained Access Control
- Audit Log (모든 변경 추적)
- Enterprise Plugin (Snowflake · Splunk · ServiceNow · Oracle · SAP · ...)
- Reporting · White-label · Recorded Queries
Provisioning
- /etc/grafana/provisioning/
- datasources/
- dashboards/ (json/)
- alerting/
- plugins/
editable: false강제- 파일 변화 watching (10s 마다)
Terraform Grafana Provider
- grafana_data_source · grafana_folder · grafana_dashboard
- grafana_team · grafana_folder_permission
- grafana_rule_group · grafana_contact_point · grafana_notification_policy
- Remote state (S3 · Terraform Cloud)
Grafonnet
- Jsonnet 의 library
- Generator pattern (한 함수 = 여러 dashboard)
- JSON 직접 작성 보다 깔끔
- CI 의 jsonnet → JSON 자동 빌드
Helm Chart
- grafana/grafana · grafana/loki-stack · grafana/mimir-distributed
- values.yaml 의 모든 setup
- ArgoCD GitOps
IaC 의 Layer 분리
- Terraform — 인프라 · 권한 · 외부 통합
- Helm — 배포 · upgrade · scaling
- Provisioning — 운영 config (datasource · dashboard · alert)
Migration
- OSS → Cloud: dashboard export · alert export · datasource 재설정
- Cloud → OSS: cluster 구축 · provisioning · data migration
- URL 변경 시 alias · redirect
사고
- Free Tier 한도 초과 (자동 Pro 청구)
- Provisioning + UI drift (
editable: false강제) - Terraform state 손실 (remote backend)
- Helm 의 secret 평문 (External Secret · Vault)
- Audit Log 미사용
- SAML group mapping 잘못
- Migration 의 URL 변경
- Grafonnet major version
- Plugin CVE
- Helm upgrade 의 datasource 손실
패턴
- Production Stack 표준 (Helm + ArgoCD + Provisioning)
- IaC 의 3 layer (Terraform · Helm · Provisioning)
- Dashboard as Code workflow (PR · preview · auto deploy)
- Cost 의 자동 monitor (한도 알림 · 월 예상)
- Disaster Recovery (daily backup · retention)
- Multi-tenant 분리 (prod · staging · dev)
공식 문서: Grafana Cloud · Terraform Grafana Provider · Grafonnet 에서 더 깊은 spec 을 확인할 수 있어요.
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
- 2편 — Prometheus + PromQL 깊이 (Pull · Exporter · Alertmanager)
- 3편 — Loki + LogQL 깊이 (Label Index · 비용 효율)
- 4편 — Tempo + TraceQL · 분산 Trace 깊이
- 5편 — Dashboard · Panel · Variable 깊이
- 6편 — Alerting · Notification · SLO 깊이
다음 글: