Grafana 입문 7편 — Cloud · Enterprise · IaC 깊이

2026-05-18Grafana 입문에서 운영까지

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편 — Cloud · Enterprise · IaC 깊이

이 글은 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 을 확인할 수 있어요.

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!