OpenSLO: декларативный стандарт для SLO

В главе «SLO как код» мы говорили о том, что SLO должны жить в Git, проходить ревью и генерировать конфиги для мониторинга. Но в каком формате их хранить? Можно придумать свой YAML — и многие так делают. А можно использовать открытый стандарт.

Что такое OpenSLO?

OpenSLO — это спецификация для декларативного описания SLO в формате YAML. Не инструмент, не библиотека, а стандарт. Как OpenAPI для REST API или OpenTelemetry для observability.

Идея простая: если все SLO описаны в едином формате, инструменты могут работать с ними без адаптации под каждого вендора. Вы описываете SLO в OpenSLO, а скормить его можно хоть Sloth, хоть SLOzy, хоть собственной утилите.

Зачем это нужно

Без общего стандарта каждая команда изобретает свой велосипед:

# Команда А
slo:
  name: api-latency
  target: 99.9

# Команда Б
service: api
objective:
  latency: 99.9

Инструменты приходится перепиливать под каждый формат. OpenSLO решает эту проблему: один формат — много инструментов.

Версии

OpenSLO прошёл несколько итераций. На текущий момент:

Версия Статус
v1 Актуальная стабильная версия. Основной стандарт для продакшена.
v1alpha Историческая, deprecated. Ранняя версия, на которой базировались первые реализации.
v2 В разработке (enhancements/v2alpha). Экспериментальная версия с новыми возможностями.

В этой главе мы разбираем v1 — то, что нужно для работы сегодня. v1alpha упомянута лишь потому, что некоторые старые инструменты и примеры до сих пор используют её.

Структура OpenSLO (v1)

OpenSLO v1 определяет несколько типов объектов (kind):

  • Service — логическая группировка SLO (например, «платёжный сервис»)
  • SLI — описание метрики: что и как меряем
  • SLO — целевой показатель: какой уровень считаем приемлемым
  • DataSource — подключение к источнику метрик (Prometheus, Datadog и т.д.)
  • AlertPolicy — правила алертинга
  • AlertCondition — условия срабатывания алерта
  • AlertNotificationTarget — куда отправлять уведомления

У каждого объекта есть метаданные. Поле metadata.name — обязательный уникальный идентификатор. metadata.labels — опциональные теги для фильтрации и группировки SLO (например, по команде или критичности).

Базовый пример: Service + SLI + SLO

apiVersion: openslo/v1
kind: Service
metadata:
  name: payment-api
  labels:
    team: payments
    tier: critical
spec:
  description: "API платёжного шлюза"
---
apiVersion: openslo/v1
kind: SLI
metadata:
  name: payment-api-availability
  labels:
    team: payments
    sli-type: availability
spec:
  ratioMetric:
    counter: true
    good:
      metricSource:
        type: Prometheus
        spec:
          query: sum(rate(http_requests_total{status=~"2.."}[5m]))
    total:
      metricSource:
        type: Prometheus
        spec:
          query: sum(rate(http_requests_total[5m]))
---
apiVersion: openslo/v1
kind: SLO
metadata:
  name: payment-api-availability
  labels:
    team: payments
    service: payment-api
spec:
  service: payment-api
  indicatorRef: payment-api-availability
  timeWindow:
    - duration: 28d
      isRolling: true
  budgetingMethod: Occurrences
  objectives:
    - target: 0.999

Ключевые элементы SLO:

Поле Описание
service Имя сервиса (ссылка на объект Service)
indicatorRef Имя SLI (или indicator для встроенного описания)
timeWindow Окно расчёта: скользящее (isRolling: true) или календарное
budgetingMethod Occurrences (по событиям), Timeslices (по временным срезам) или RatioTimeslices
objectives Целевые значения. Массив — можно задать несколько порогов
target Цель в долях (0.999 = 99.9%). Альтернатива — targetPercent (99.9)

SLI: ratioMetric vs thresholdMetric

SLI описывает, как читать метрику из источника. Два подхода:

ratioMetric — отношение хороших событий к общему числу:

ratioMetric:
  counter: true
  good:
    metricSource:
      type: Prometheus
      spec:
        query: sum(rate(http_requests_total{status=~"2.."}[5m]))
  total:
    metricSource:
      type: Prometheus
      spec:
        query: sum(rate(http_requests_total[5m]))

thresholdMetric — сравнение сырого значения с порогом (для latency, например):

thresholdMetric:
  metricSource:
    type: Prometheus
    spec:
      query: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

DataSource

Если один и тот же Prometheus используется для множества SLO, удобно вынести подключение в отдельный объект:

apiVersion: openslo/v1
kind: DataSource
metadata:
  name: prod-prometheus
  labels:
    environment: production
    type: prometheus
spec:
  type: Prometheus
  connectionDetails:
    url: https://prometheus.example.com

А в SLI ссылаться через metricSourceRef:

ratioMetric:
  counter: true
  good:
    metricSource:
      metricSourceRef: prod-prometheus
      spec:
        query: sum(rate(http_requests_total{status=~"2.."}[5m]))

Алертинг

OpenSLO v1 позволяет описывать алертинг через отдельные объекты AlertPolicy, AlertCondition и AlertNotificationTarget:

apiVersion: openslo/v1
kind: AlertCondition
metadata:
  name: high-burn-rate
  labels:
    severity: page
spec:
  severity: page
  condition:
    kind: burnrate
    op: gte
    threshold: 2
    lookbackWindow: 1h
    alertAfter: 5m
---
apiVersion: openslo/v1
kind: AlertPolicy
metadata:
  name: payment-api-alerts
  labels:
    team: payments
spec:
  alertWhenBreaching: true
  conditions:
    - conditionRef: high-burn-rate
  notificationTargets:
    - targetRef: on-call-slack

v1alpha: историческая справка

Ранние реализации OpenSLO (и некоторые старые примеры в интернете) используют apiVersion: openslo/v1alpha. Основные отличия от v1:

  • вместо objectives — одно поле objective (число, не массив)
  • indicator встраивался прямо в SLO, отдельного kind SLI не было
  • не было объектов DataSource, AlertPolicy, AlertCondition
  • не поддерживались составные (composite) SLO с несколькими objectives
  • duration указывался как 28d вместо duration: 28d под timeWindow

Если вы встречаете в документации инструмента примеры с openslo/v1alpha, это не значит, что формат устарел для всех — просто инструмент ещё не обновился до v1. Для новых проектов используйте openslo/v1.

С чем использовать

Инструмент Что делает Версия OpenSLO
Sloth Генерирует Prometheus rules из SLO Свой формат prometheus/v1, OpenSLO через плагин
SLOzy Платформа управления SLO (дашборды, GitOps, алерты) v1
Oslo (CLI) Валидация, linting, конвертация OpenSLO v1
Pyrra CLI для генерации Prometheus rules v1alpha / v1

Как внедрить

  1. Начните с v1. Не пишите нового на v1alpha — это deprecated. v2 пока эксперимент, следите за развитием, но в продакшен пока рано.
  2. Создайте репозиторий. Service и DataSource — отдельные файлы, SLO — один файл на сервис (можно несколько objectives внутри).
  3. Подключите CI-валидацию. Oslo CLI (oslo validate) проверяет синтаксис и семантику.
  4. Генерируйте конфиги. Sloth или SLOzy превратят OpenSLO-файлы в Prometheus recording rules и alerting rules.
  5. Повторяйте. Каждый PR с изменением SLO проходит валидацию и регенерацию.

OpenSLO — это не обязательный, но очень удобный слой абстракции между вашими намерениями и инфраструктурой мониторинга. Он не привязан к конкретному инструменту — просто YAML-файлы в Git.