Управление правилами Prometheus с помощью Terraform

Правила Prometheus в Knowledge Graph позволяют определять пользовательские правила записи и алертинга, которые вычисляются по данным ваших метрик. Правила записи предварительно вычисляют часто используемые или ресурсоёмкие выражения и сохраняют результаты в виде новых временных рядов. Правила алертинга задают условия, при выполнении которых срабатывают алерты.

С помощью ресурса grafana_asserts_prom_rule_file вы можете управлять этими правилами как кодом, что обеспечивает версионирование, процессы review и согласованные развёртывания в разных средах.

Прежде чем начать

Чтобы управлять правилами Prometheus с помощью Terraform, вам потребуется:

Создание базового правила записи

Правила записи позволяют предварительно вычислять выражения PromQL и сохранять результаты в виде новых метрик. Это полезно для ресурсоёмких запросов, которые вы выполняете часто.

Создайте файл с именем prom-rules.tf и добавьте следующее:

terraform
# 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"
      }
    }
  }
}

Создание правил алертинга

Правила алертинга задают условия, при выполнении которых срабатывают алерты. Используйте поле alert вместо record, чтобы определить правило алертинга.

terraform
# 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"
      }
    }
  }
}

Создание нескольких групп правил

Объединяйте связанные правила в группы с собственными интервалами вычисления:

terraform
# 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 = "10m"

      labels = {
        severity = "warning"
      }

      annotations = {
        summary     = "Low throughput detected"
        description = "Request rate for {{ $labels.job }} is below 10 requests per second"
      }
    }
  }
}

Создание правил использования ресурсов

Определите правила для мониторинга использования ресурсов в вашей инфраструктуре:

terraform
# 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:

terraform
# 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:

terraform
# 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"
      }
    }
  }
}

Управление неактивными файлами правил

Временно отключите весь файл правил, не удаляя его:

terraform
# 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

Управляйте правилами записи и алертинга Prometheus через Knowledge Graph API. Этот ресурс позволяет создавать пользовательские правила Prometheus, которые вычисляются по данным ваших метрик, и управлять ими.

Аргументы

Имя Тип Обязательный Описание
name string Да Имя файла правил Prometheus. Это поле неизменяемо и вызывает пересоздание ресурса при изменении.
active bool Нет Активен ли файл правил. Неактивные правила не вычисляются. По умолчанию true.
group list(object) Да Список групп правил Prometheus. Подробнее см. блок group.

Блок group

Каждый блок group содержит набор связанных правил с общим интервалом вычисления:

Имя Тип Обязательный Описание
name string Да Имя группы правил (например, latency_monitoring).
interval string Нет Интервал вычисления для этой группы (например, 30s, 1m). Если не указан, используется глобальный интервал вычисления.
rule list(object) Да Список правил Prometheus в этой группе. Подробнее см. блок rule.

Блок rule

Каждый блок rule определяет правило записи или алертинга. Необходимо указать либо record, либо alert, но не оба одновременно:

Имя Тип Обязательный Описание
record string Условно Имя временного ряда, который выводится для правил записи. Обязательно, если не указан alert.
alert string Условно Имя алерта для правил алертинга. Обязательно, если не указан record.
expr string Да Выражение PromQL для вычисления.
duration string Нет Как долго условие должно быть истинным до срабатывания алерта (например, 5m). Только для правил алертинга. Соответствует for в Prometheus.
labels map(string) Нет Метки, добавляемые к результирующему временному ряду или алерту.
annotations map(string) Нет Аннотации, добавляемые к алертам (например, summary, description). Применимо только для правил алертинга.
disable_in_groups set(string) Нет Список имён групп, в которых это правило следует отключить. Полезно для условного включения правил.

Пример

terraform
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%"
      }
    }
  }
}

Рекомендации

При управлении правилами Prometheus с помощью Terraform учитывайте следующие рекомендации.

Организация правил

  • Объединяйте связанные правила в одну группу правил
  • Используйте описательные имена правил, отражающие их назначение
  • Разделяйте правила записи и правила алертинга на разные группы, если у них разные потребности в вычислении
  • Используйте согласованные соглашения об именовании записываемых метрик, например level:metric:operation

Правила записи

  • Используйте правила записи для ресурсоёмких запросов, которые выполняются часто
  • Предварительно вычисляйте агрегации, используемые несколькими дашбордами или алертами
  • Выбирайте подходящие интервалы вычисления в зависимости от частоты изменения данных
  • Следуйте соглашениям об именовании Prometheus, например job:metric:aggregation

Правила алертинга

  • Устанавливайте подходящие значения duration, чтобы избежать «дребезжащих» алертов
  • Включайте осмысленные метки, такие как severity и team, для маршрутизации
  • Предоставляйте подробные аннотации, включая summary, description и runbook_url
  • Используйте переменные шаблонов в аннотациях, такие как {{ $labels.job }}, чтобы передать контекст

Вопросы производительности

  • Избегайте чрезмерно сложных выражений PromQL, которые могут завершиться по тайм-ауту
  • Используйте подходящие интервалы вычисления; не вычисляйте чаще, чем необходимо
  • Тестируйте запросы PromQL в Grafana, прежде чем добавлять их в Terraform
  • Учитывайте влияние на кардинальность правил записи, создающих новые временные ряды

Тестирование и проверка

  • Тестируйте правила в среде, отличной от производственной, прежде чем развёртывать их в production
  • Используйте флаг active = false, чтобы подготовить правила без их вычисления
  • Отслеживайте влияние новых правил на производительность после развёртывания
  • Регулярно проверяйте и удаляйте неиспользуемые правила

Проверка

После применения конфигурации Terraform убедитесь, что:

  • Файлы правил созданы и видны в конфигурации правил Knowledge Graph
  • Правила записи создают ожидаемые временные ряды
  • Правила алертинга вычисляются корректно
  • Пороги алертов запускают уведомления как ожидается
  • Время вычисления правил находится в допустимых пределах
  • В журналах вычисления правил не появляется ошибок

Устранение неполадок

Правила не вычисляются

Если ваши правила не вычисляются:

  1. Убедитесь, что для файла правил установлено active = true
  2. Проверьте, что имя файла правил соответствует правилам валидации имён (буквенно-цифровые символы, дефисы, подчёркивания)
  3. Убедитесь, что выражение PromQL корректно, проверив его в Grafana

Правило записи не создаёт данные

Если правило записи не создаёт данные:

  1. Убедитесь, что исходные метрики существуют и содержат данные
  2. Проверьте, что выражение PromQL возвращает результаты
  3. Убедитесь, что интервал вычисления подходит
  4. Проверьте журналы вычисления правил на наличие ошибок

Алерты не срабатывают

Если правила алертинга не срабатывают:

  1. Убедитесь, что условие фактически выполнено, запросив выражение вручную
  2. Проверьте, что период duration истёк
  3. Убедитесь, что система алертинга правильно настроена для получения алертов
  4. Проверьте шаблоны аннотаций на синтаксические ошибки

Ошибка импорта при пересоздании правил

Если при пересоздании правил возникают ошибки:

  • Поле name неизменяемо и вызывает пересоздание ресурса при изменении
  • Убедитесь, что не существует конфликтующих файлов правил с тем же именем
  • При необходимости используйте terraform import для импорта существующих ресурсов

Связанная документация