Terraform으로 Prometheus 규칙 관리
Terraform으로 Prometheus 규칙 관리
Knowledge Graph의 Prometheus 규칙을 사용하면 메트릭 데이터에 대해 평가되는 사용자 지정 recording 및 alerting 규칙을 정의할 수 있어요. Recording 규칙은 자주 사용되거나 계산 비용이 높은 표현식을 미리 계산하고 결과를 새 시계열로 저장해요. Alerting 규칙은 조건이 충족되면 알림을 트리거하는 조건을 정의해요.
grafana_asserts_prom_rule_file 리소스를 사용하면 이러한 규칙을 코드로 관리하여 버전 관리, 검토 프로세스, 환경 간 일관된 배포를 가능하게 해요.
출처: 문서
본문
시작하기 전에
Terraform으로 Prometheus 규칙을 관리하려면 다음이 필요해요:
- Knowledge Graph가 활성화된 Grafana Cloud 스택
- Knowledge Graph용으로 구성된 Terraform
- PromQL 및 Prometheus 규칙 개념에 대한 이해
기본 recording 규칙 만들기
Recording 규칙을 사용하면 PromQL 표현식을 미리 계산하고 결과를 새 메트릭으로 저장할 수 있어요. 자주 실행하는 비용이 높은 쿼리에 유용해요.
prom-rules.tf라는 파일을 만들고 다음 내용을 추가하세요:
# Basic recording rule for request rate
resource "grafana_asserts_prom_rule_file" "request_rates" {
provider = grafana.asserts
name = "request-rates"
active = true
group {
name = "request_rate_rules"
interval = "30s"
rule {
record = "job:http_requests_total:rate5m"
expr = "sum(rate(http_requests_total[5m])) by (job)"
labels = {
aggregation = "job"
source = "custom"
}
}
}
}
alerting 규칙 만들기
Alerting 규칙은 충족 시 알림을 트리거하는 조건을 정의해요. record 대신 alert 필드를 사용해 alerting 규칙을 정의하세요.
# Alerting rules for service health
resource "grafana_asserts_prom_rule_file" "service_alerts" {
provider = grafana.asserts
name = "service-health-alerts"
active = true
group {
name = "service_health"
interval = "1m"
rule {
alert = "HighErrorRate"
expr = "sum(rate(http_requests_total{code=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m])) > 0.05"
duration = "5m"
labels = {
severity = "critical"
team = "platform"
}
annotations = {
summary = "High error rate detected"
description = "Error rate is above 5% for the last 5 minutes"
runbook_url = "https://docs.example.com/runbooks/high-error-rate"
}
}
rule {
alert = "ServiceDown"
expr = "up == 0"
duration = "2m"
labels = {
severity = "critical"
}
annotations = {
summary = "Service is down"
description = "{{ $labels.job }} has been down for more than 2 minutes"
}
}
}
}
여러 규칙 그룹 만들기
관련 규칙을 고유한 평가 간격을 가진 그룹으로 구성하세요:
# Multiple rule groups for comprehensive monitoring
resource "grafana_asserts_prom_rule_file" "comprehensive_rules" {
provider = grafana.asserts
name = "comprehensive-monitoring"
active = true
# Latency recording rules
group {
name = "latency_recording"
interval = "30s"
rule {
record = "job:http_request_duration_seconds:p99"
expr = "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le))"
labels = {
quantile = "0.99"
}
}
rule {
record = "job:http_request_duration_seconds:p95"
expr = "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le))"
labels = {
quantile = "0.95"
}
}
rule {
record = "job:http_request_duration_seconds:p50"
expr = "histogram_quantile(0.50, sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le))"
labels = {
quantile = "0.50"
}
}
}
# Latency alerting rules
group {
name = "latency_alerts"
interval = "1m"
rule {
alert = "HighP99Latency"
expr = "job:http_request_duration_seconds:p99 > 1"
duration = "5m"
labels = {
severity = "warning"
}
annotations = {
summary = "High P99 latency detected"
description = "P99 latency for {{ $labels.job }} is above 1 second"
}
}
rule {
alert = "CriticalLatency"
expr = "job:http_request_duration_seconds:p99 > 5"
duration = "2m"
labels = {
severity = "critical"
}
annotations = {
summary = "Critical latency detected"
description = "P99 latency for {{ $labels.job }} is above 5 seconds"
}
}
}
# Throughput rules
group {
name = "throughput_rules"
interval = "1m"
rule {
record = "job:http_requests:rate1m"
expr = "sum(rate(http_requests_total[1m])) by (job)"
}
rule {
alert = "LowThroughput"
expr = "job:http_requests:rate1m < 10"
duration = "5m"
labels = {
severity = "warning"
}
annotations = {
summary = "Low throughput detected"
description = "Request rate for {{ $labels.job }} is below 10 requests per minute"
}
}
}
}
리소스 사용률 규칙 만들기
인프라 전반의 리소스 사용률을 모니터링하는 규칙을 정의하세요:
# Resource utilization monitoring rules
resource "grafana_asserts_prom_rule_file" "resource_utilization" {
provider = grafana.asserts
name = "resource-utilization"
active = true
group {
name = "cpu_rules"
interval = "30s"
rule {
record = "instance:cpu_utilization:avg5m"
expr = "1 - avg(rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) by (instance)"
}
rule {
alert = "HighCPUUtilization"
expr = "instance:cpu_utilization:avg5m > 0.85"
duration = "10m"
labels = {
severity = "warning"
resource = "cpu"
}
annotations = {
summary = "High CPU utilization"
description = "CPU utilization on {{ $labels.instance }} is above 85%"
}
}
rule {
alert = "CriticalCPUUtilization"
expr = "instance:cpu_utilization:avg5m > 0.95"
duration = "5m"
labels = {
severity = "critical"
resource = "cpu"
}
annotations = {
summary = "Critical CPU utilization"
description = "CPU utilization on {{ $labels.instance }} is above 95%"
}
}
}
group {
name = "memory_rules"
interval = "30s"
rule {
record = "instance:memory_utilization:ratio"
expr = "1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)"
}
rule {
alert = "HighMemoryUtilization"
expr = "instance:memory_utilization:ratio > 0.85"
duration = "10m"
labels = {
severity = "warning"
resource = "memory"
}
annotations = {
summary = "High memory utilization"
description = "Memory utilization on {{ $labels.instance }} is above 85%"
}
}
}
group {
name = "disk_rules"
interval = "1m"
rule {
record = "instance:disk_utilization:ratio"
expr = "1 - (node_filesystem_avail_bytes{mountpoint=\"/\"} / node_filesystem_size_bytes{mountpoint=\"/\"})"
}
rule {
alert = "DiskSpaceLow"
expr = "instance:disk_utilization:ratio > 0.80"
duration = "15m"
labels = {
severity = "warning"
resource = "disk"
}
annotations = {
summary = "Disk space running low"
description = "Disk utilization on {{ $labels.instance }} is above 80%"
}
}
}
}
Kubernetes 특화 규칙 만들기
Kubernetes 워크로드 모니터링을 위한 규칙을 정의하세요:
# Kubernetes workload monitoring rules
resource "grafana_asserts_prom_rule_file" "kubernetes_rules" {
provider = grafana.asserts
name = "kubernetes-workloads"
active = true
group {
name = "kubernetes_pod_rules"
interval = "30s"
rule {
record = "namespace:pod_restarts:rate1h"
expr = "sum(increase(kube_pod_container_status_restarts_total[1h])) by (namespace)"
}
rule {
alert = "PodCrashLooping"
expr = "rate(kube_pod_container_status_restarts_total[15m]) * 60 * 15 > 3"
duration = "5m"
labels = {
severity = "warning"
}
annotations = {
summary = "Pod is crash looping"
description = "Pod {{ $labels.namespace }}/{{ $labels.pod }} is restarting frequently"
}
}
rule {
alert = "PodNotReady"
expr = "kube_pod_status_ready{condition=\"true\"} == 0"
duration = "10m"
labels = {
severity = "warning"
}
annotations = {
summary = "Pod not ready"
description = "Pod {{ $labels.namespace }}/{{ $labels.pod }} has been in a non-ready state for more than 10 minutes"
}
}
}
group {
name = "kubernetes_deployment_rules"
interval = "1m"
rule {
record = "deployment:replicas_unavailable:count"
expr = "kube_deployment_status_replicas_unavailable"
}
rule {
alert = "DeploymentReplicasMismatch"
expr = "kube_deployment_spec_replicas != kube_deployment_status_replicas_available"
duration = "10m"
labels = {
severity = "warning"
}
annotations = {
summary = "Deployment replicas mismatch"
description = "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} has not matched the expected number of replicas for more than 10 minutes"
}
}
}
group {
name = "kubernetes_node_rules"
interval = "1m"
rule {
alert = "NodeNotReady"
expr = "kube_node_status_condition{condition=\"Ready\",status=\"true\"} == 0"
duration = "5m"
labels = {
severity = "critical"
}
annotations = {
summary = "Kubernetes node not ready"
description = "Node {{ $labels.node }} has been unready for more than 5 minutes"
}
}
rule {
alert = "NodeMemoryPressure"
expr = "kube_node_status_condition{condition=\"MemoryPressure\",status=\"true\"} == 1"
duration = "5m"
labels = {
severity = "warning"
}
annotations = {
summary = "Node under memory pressure"
description = "Node {{ $labels.node }} is under memory pressure"
}
}
}
}
조건부 규칙 비활성화 사용
disable_in_groups 필드를 사용해 특정 그룹의 특정 규칙을 비활성화하세요:
# Rules with conditional disabling
resource "grafana_asserts_prom_rule_file" "conditional_rules" {
provider = grafana.asserts
name = "conditional-alerting"
active = true
group {
name = "production_alerts"
interval = "1m"
rule {
alert = "HighErrorRate"
expr = "sum(rate(http_requests_total{code=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m])) > 0.01"
duration = "5m"
labels = {
severity = "critical"
environment = "production"
}
annotations = {
summary = "High error rate in production"
description = "Error rate is above 1% for the last 5 minutes"
}
# Disable this rule in staging group
disable_in_groups = ["staging_alerts"]
}
}
group {
name = "staging_alerts"
interval = "1m"
rule {
alert = "HighErrorRate"
expr = "sum(rate(http_requests_total{code=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m])) > 0.10"
duration = "10m"
labels = {
severity = "warning"
environment = "staging"
}
annotations = {
summary = "High error rate in staging"
description = "Error rate is above 10% for the last 10 minutes"
}
}
}
}
비활성 규칙 파일 관리
규칙 파일 전체를 삭제하지 않고 일시적으로 비활성화하세요:
# Inactive rules file (not evaluated)
resource "grafana_asserts_prom_rule_file" "experimental_rules" {
provider = grafana.asserts
name = "experimental-rules"
active = false # Rules are not evaluated
group {
name = "experimental_alerts"
interval = "1m"
rule {
alert = "ExperimentalAlert"
expr = "some_experimental_metric > 100"
duration = "5m"
labels = {
severity = "info"
}
annotations = {
summary = "Experimental alert triggered"
}
}
}
}
리소스 참조
grafana_asserts_prom_rule_file
Knowledge Graph API를 통해 Prometheus recording 및 alerting 규칙을 관리해요. 이 리소스를 사용하면 메트릭 데이터에 대해 평가되는 사용자 지정 Prometheus 규칙을 만들고 관리할 수 있어요.
인자(Arguments)
| 이름 | 유형 | 필수 | 설명 |
|---|---|---|---|
| name | string | Yes | Prometheus 규칙 파일의 이름. 이 필드는 불변(immutable)이며 변경 시 재생성을 강제해요. |
| active | bool | No | 규칙 파일이 활성 상태인지 여부. 비활성 규칙은 평가되지 않아요. 기본값은 true. |
| group | list(object) | Yes | Prometheus 규칙 그룹 목록. 자세한 내용은 group 블록을 참고하세요. |
Group 블록
각 group 블록은 공유된 평가 간격을 가진 관련 규칙 집합을 포함해요:
| 이름 | 유형 | 필수 | 설명 |
|---|---|---|---|
| name | string | Yes | 규칙 그룹의 이름(예: latency_monitoring). |
| interval | string | No | 이 그룹의 평가 간격(예: 30s, 1m). 지정하지 않으면 전역 평가 간격을 사용해요. |
| rule | list(object) | Yes | 이 그룹의 Prometheus 규칙 목록. 자세한 내용은 rule 블록을 참고하세요. |
Rule 블록
각 rule 블록은 recording 또는 alerting 규칙을 정의해요. record 또는 alert 중 하나를 지정해야 하며, 둘 다는 안 돼요:
| 이름 | 유형 | 필수 | 설명 |
|---|---|---|---|
| record | string | Conditional | recording 규칙의 출력 시계열 이름. alert를 지정하지 않으면 필수예요. |
| alert | string | Conditional | alerting 규칙의 알림 이름. record를 지정하지 않으면 필수예요. |
| expr | string | Yes | 평가할 PromQL 표현식. |
| duration | string | No | alert가 발화(firing)되기 전에 조건이 유지되어야 하는 시간(예: 5m). alerting 규칙에만 해당. Prometheus의 for에 매핑돼요. |
| labels | map(string) | No | 결과 시계열 또는 알림에 첨부할 라벨. |
| annotations | map(string) | No | 알림에 추가할 주석(예: summary, description). alerting 규칙에만 적용 가능. |
| disable_in_groups | set(string) | No | 이 규칙을 비활성화할 그룹 이름 목록. 조건부 규칙 활성화에 유용해요. |
예시
resource "grafana_asserts_prom_rule_file" "example" {
provider = grafana.asserts
name = "example-rules"
active = true
group {
name = "example_group"
interval = "1m"
# Recording rule
rule {
record = "job:http_requests:rate5m"
expr = "sum(rate(http_requests_total[5m])) by (job)"
}
# Alerting rule
rule {
alert = "HighErrorRate"
expr = "job:http_errors:rate5m > 0.05"
duration = "5m"
labels = {
severity = "critical"
}
annotations = {
summary = "High error rate detected"
description = "Error rate for {{ $labels.job }} is above 5%"
}
}
}
}
모범 사례
Terraform으로 Prometheus 규칙을 관리할 때 다음 모범 사례를 고려하세요.
규칙 구성
- 관련 규칙을 같은 규칙 그룹으로 묶으세요.
- 목적을 나타내는 설명적인 이름을 규칙에 사용하세요.
- 평가 요구 사항이 다른 경우 recording 규칙과 alerting 규칙을 다른 그룹으로 분리하세요.
level:metric:operation같은 기록된 메트릭의 일관된 명명 규칙을 사용하세요.
Recording 규칙
- 자주 실행되는 비용이 높은 쿼리에 recording 규칙을 사용하세요.
- 여러 대시보드나 알림에서 사용되는 집계를 미리 계산하세요.
- 데이터가 변경되는 빈도에 따라 적절한 평가 간격을 선택하세요.
job:metric:aggregation같은 Prometheus 명명 규칙을 따르세요.
Alerting 규칙
- 알림 플래핑(flapping)을 피하려면 적절한
duration값을 설정하세요. - 라우팅을 위해
severity,team같은 의미 있는 라벨을 포함하세요. summary,description,runbook_url을 포함한 포괄적인 주석을 제공하세요.- 컨텍스트를 제공하려면
{{ $labels.job }}같은 주석의 템플릿 변수를 사용하세요.
성능 고려 사항
- 타임아웃될 수 있는 지나치게 복잡한 PromQL 표현식을 피하세요.
- 적절한 평가 간격을 사용하세요. 필요 이상으로 빠르게 평가하지 마세요.
- Terraform에 추가하기 전에 Grafana에서 PromQL 쿼리를 테스트하세요.
- 새 시계열을 만드는 recording 규칙의 카디널리티 영향에 주의하세요.
테스트 및 검증
- 프로덕션에 배포하기 전에 프로덕션 외 환경에서 규칙을 테스트하세요.
- 규칙을 평가하지 않고 스테이징하려면
active = false플래그를 사용하세요. - 배포 후 새 규칙의 성능 영향을 모니터링하세요.
- 사용하지 않는 규칙을 주기적으로 검토하고 제거하세요.
검증
Terraform 구성을 적용한 후 다음을 확인하세요:
- 규칙 파일이 Knowledge Graph 규칙 구성에 생성되고 보이는지.
- Recording 규칙이 예상 시계열을 생성하는지.
- Alerting 규칙이 올바르게 평가되는지.
- 알림 임계값이 예상대로 알림을 트리거하는지.
- 규칙 평가 시간이 허용 가능한 범위 내에 있는지.
- 규칙 평가 로그에 오류가 나타나지 않는지.
문제 해결
규칙이 평가되지 않음
규칙이 평가되지 않는 경우:
- 규칙 파일에
active = true가 설정되어 있는지 확인하세요. - 규칙 파일명이 명명 검증 규칙(영숫자, 하이픈, 밑줄)을 따르는지 확인하세요.
- Grafana에서 테스트해 PromQL 표현식이 유효한지 확인하세요.
Recording 규칙이 데이터를 생성하지 않음
recording 규칙이 데이터를 생성하지 않는 경우:
- 소스 메트릭이 존재하고 데이터가 있는지 확인하세요.
- PromQL 표현식이 결과를 반환하는지 확인하세요.
- 평가 간격이 적절한지 확인하세요.
- 오류가 있는지 규칙 평가 로그를 검토하세요.
알림이 발화되지 않음
alerting 규칙이 발화되지 않는 경우:
- 표현식을 수동으로 쿼리해 조건이 실제로 충족되었는지 확인하세요.
duration기간이 경과했는지 확인하세요.- 알림 시스템이 알림을 받도록 올바르게 구성되었는지 확인하세요.
- 구문 오류가 있는지 주석 템플릿을 검토하세요.
규칙 재생성 시 가져오기 오류
규칙을 재생성할 때 오류가 발생하면:
name필드는 불변이며 변경 시 재생성을 강제해요.- 같은 이름의 충돌하는 규칙 파일이 없는지 확인하세요.
- 필요하면
terraform import를 사용해 기존 리소스를 가져오세요.
관련 문서
- Knowledge Graph용 Terraform 시작하기
- Terraform으로 사용자 지정 모델 규칙 만들기
- Prometheus recording 규칙
- Prometheus alerting 규칙