Профессиональная разработка шаблонов Zabbix: от SNMP до автоматизации через API

Комплексный курс для системных инженеров по созданию отказоустойчивых шаблонов мониторинга. Вы научитесь работать с SNMP-устройствами, использовать низкоуровневое обнаружение (LLD) и автоматизировать управление инфраструктурой через Zabbix API.

Концепция шаблонов в Zabbix

Концепция шаблонов в Zabbix

Представьте, что вы приходите к новому клиенту, у которого в инфраструктуре работает 100 серверов на Linux. Чтобы настроить базовый мониторинг (процессор, память, диски, сеть), на каждый сервер нужно добавить около 50 метрик. Если делать это вручную, вам придется создать 100×50=5000100 \times 50 = 5000 отдельных сущностей в системе. А если завтра клиент попросит добавить мониторинг температуры процессора на всех серверах? Вам придется руками вносить изменения 100 раз.

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

Что такое шаблон?

В терминологии Zabbix узел сети (Host) — это конкретное физическое или виртуальное устройство, за которым мы наблюдаем. Элемент данных (Item) — это конкретная метрика, которую мы собираем (например, загрузка CPU).

Шаблон (Template) — это чертеж. Это набор элементов данных, триггеров, графиков и правил обнаружения, который сам по себе ничего не мониторит. Он существует в вакууме до тех пор, пока вы не привяжете его к конкретному узлу сети.

Шаблон в Zabbix работает по принципам объектно-ориентированного программирования: шаблон — это класс, а узел сети — это объект (экземпляр этого класса).

Когда вы привязываете шаблон к узлу сети, Zabbix автоматически создает на этом узле все сущности, описанные в чертеже.

Принцип централизованного управления

Главная сила шаблонов раскрывается при внесении изменений. Если 100 серверов привязаны к одному шаблону «Linux OS», они наследуют все его настройки.

Если вы решите, что порог срабатывания триггера о нехватке свободного места на диске нужно изменить с 10% на 5%, вы не правите 100 серверов. Вы открываете шаблон, меняете цифру один раз, и Zabbix мгновенно применяет это изменение ко всем 100 узлам сети.

Этот принцип диктует золотое правило профессиональной разработки в Zabbix: никогда не создавайте элементы данных напрямую на узле сети, если их можно вынести в шаблон. Даже если сейчас у клиента всего один специфический сервер баз данных, создайте для него шаблон. Завтра серверов станет два, и вы сэкономите себе часы работы.

Архитектура «Лего»: принцип модульности

Новички часто совершают ошибку: создают монолитные шаблоны. Например, шаблон «Web-сервер клиента X», в который напихивают метрики операционной системы, метрики веб-сервера Nginx и метрики базы данных MySQL.

Проблема такого подхода возникает, когда появляется второй сервер, на котором стоит Linux и MySQL, но вместо Nginx используется Apache. Монолитный шаблон уже не подходит, и новичок копирует его, создавая дубликат с небольшими изменениями. Через год система превращается в свалку из десятков почти одинаковых шаблонов, которые невозможно поддерживать.

Профессиональный подход — это модульность. Шаблоны должны быть атомарными.

Один узел сети в Zabbix может быть привязан к неограниченному количеству шаблонов одновременно. Поэтому правильная архитектура выглядит так:

  1. Вы создаете базовый шаблон Template OS Linux.
  2. Вы создаете отдельный шаблон Template DB MySQL.
  3. Вы создаете отдельный шаблон Template Web Nginx.

Теперь, чтобы поставить на мониторинг первый сервер, вы просто привязываете к нему три этих шаблона, как кубики Лего. Для второго сервера (с Apache) вы используете тот же самый Template OS Linux, тот же Template DB MySQL и новый Template Web Apache. Вы переиспользуете код, а не дублируете его.

Ловушка отсоединения: Unlink vs Unlink and clear

Когда вы привязываете шаблон, метрики начинают собираться. Но что происходит, когда вы решаете убрать шаблон с узла сети? Здесь кроется самая частая ошибка начинающих инженеров.

В интерфейсе Zabbix при редактировании узла сети есть две разные кнопки для удаления шаблона:

  • Отсоединить (Unlink) — разрывает связь между чертежом и сервером. Шаблон отвязывается, но все элементы данных, триггеры и собранная история остаются на узле сети. Они просто превращаются в самостоятельные, ручные элементы. Вы больше не сможете управлять ими централизованно.
  • Отсоединить и очистить (Unlink and clear) — удаляет шаблон, а вместе с ним удаляет с узла сети все элементы данных, которые были созданы этим шаблоном, включая всю накопленную по ним историческую статистику.

Если вы случайно нажмете просто «Отсоединить», а затем привяжете обновленную версию шаблона, Zabbix выдаст ошибку: он попытается создать элементы данных, а они уже существуют на узле сети как самостоятельные сущности. Всегда используйте «Отсоединить и очистить», если хотите полностью удалить влияние шаблона на хост.

Шаблоны — это фундамент, на котором строится весь современный мониторинг. Понимание того, как они наследуются и комбинируются, отличает профессионала от любителя. Теперь, когда мы понимаем архитектурную идею, мы готовы перейти к практике и собрать наш первый собственный шаблон.

Создание первого простого шаблона вручную

Создание первого простого шаблона вручную

Чертеж не возникает из воздуха — для него нужна чертежная доска. В Zabbix такой доской выступает раздел конфигурации, где мы создаем пустую оболочку будущего шаблона. Если вы внедряете мониторинг у клиента, количество шаблонов быстро перевалит за сотню. Поэтому профессиональная разработка начинается не с добавления метрик, а с правильной организации и именования.

Оболочка: Имя и Группы шаблонов

Создание шаблона начинается с трех базовых параметров: Имя шаблона (Template name), Видимое имя (Visible name) и Группа шаблонов (Template group).

Имя шаблона — это уникальный технический идентификатор в базе данных Zabbix. Профессионалы используют строгие соглашения об именовании (Naming Conventions), чтобы в списке из сотен позиций нужная находилась мгновенно. Общепринятый стандарт выглядит так: Объект_мониторинга by Метод_сбора.

Примеры правильного именования:

  • Linux by Zabbix agent
  • Cisco IOS by SNMP
  • MySQL by Zabbix agent 2

Видимое имя используется только для удобства отображения в интерфейсе. Если его не заполнить, Zabbix будет показывать техническое Имя шаблона. На практике Видимое имя часто оставляют пустым, чтобы избежать путаницы между тем, что видит администратор, и тем, как шаблон называется на уровне API.

Группы шаблонов — это логические папки. Шаблон не может существовать вне группы. Если вы создаете мониторинг для сетевого оборудования, логично поместить шаблон в группу Templates/Network devices. Это не влияет на процесс сбора данных, но критически важно для выдачи прав доступа: в Zabbix права назначаются именно на группы, а не на отдельные шаблоны.

Наполнение: Создание элемента данных (Item)

Пустой шаблон бесполезен. Чтобы он начал приносить пользу, в него нужно добавить инструкции по сбору метрик — Элементы данных (Items).

Допустим, базовая потребность клиента — знать, доступен ли сервер по сети и каково время отклика. Для этого мы создадим элемент данных, измеряющий пинг.

Внутри созданного шаблона мы переходим в раздел Items и нажимаем «Создать». Перед нами открывается форма, где ключевыми являются четыре поля:

1. Тип (Type)

Определяет, кто и как будет собирать метрику.

  • Если мы опрашиваем устройство по SNMP, тип будет SNMP agent.
  • Если метрику отдает установленный на сервере агент Zabbix, тип — Zabbix agent.
  • Для проверки пинга нам не нужен агент на целевом узле, проверку выполняет сам сервер Zabbix. Такой тип называется Simple check (Простая проверка).

2. Ключ (Key)

Это сердце элемента данных. Ключ — это конкретная команда или идентификатор метрики, которую Zabbix должен запросить. В нашем случае для измерения времени отклика пинга используется встроенный ключ icmppingsec.

Ключ может принимать параметры в квадратных скобках. Например, icmppingsec[8.8.8.8,5,1000,,10000] указывает конкретный IP, количество пакетов, интервал и таймаут. Но в шаблонах мы избегаем жесткого кодирования IP-адресов. Если оставить скобки пустыми или вообще их не писать (icmppingsec), Zabbix автоматически подставит IP-адрес того узла сети, к которому будет привязан шаблон.

3. Тип информации (Type of information)

Zabbix должен знать, как хранить полученный результат в базе данных. Неправильный выбор приведет к тому, что данные будут отбрасываться.

  • Numeric (unsigned) — целые положительные числа (например, количество пакетов, объем оперативной памяти в байтах).
  • Numeric (float) — числа с плавающей точкой. Время отклика пинга измеряется в долях секунды (например, 0.015 с), поэтому для icmppingsec мы обязаны выбрать именно этот тип.
  • Character / Text — для строковых значений (например, версия прошивки роутера).

4. Интервал обновления (Update interval)

Как часто Zabbix будет запрашивать эту метрику. Для критичных параметров доступности (как пинг) обычно ставят 1m (1 минута). Для редко меняющихся данных, таких как серийный номер шасси, интервал может составлять 1h (1 час) или даже 1d (1 день), чтобы не создавать лишнюю нагрузку на сеть и базу данных.

Организация метрик: Теги (Tags)

В старых версиях Zabbix для группировки элементов данных использовались «Группы элементов данных» (Applications). В современных версиях их полностью заменили Теги.

Теги — это метки в формате Имя: Значение, которые прикрепляются к элементу данных. Они решают две глобальные задачи:

  1. Фильтрация: когда у вас на сервере 5000 метрик, теги позволяют мгновенно вывести на экран только те, что относятся к дисковой подсистеме или конкретному приложению.
  2. Маршрутизация проблем: на основе тегов Zabbix понимает, кому отправлять уведомление об аварии (например, проблемы с тегом component: database отправляются DBA-инженерам, а component: network — сетевикам).

Для нашего элемента данных icmppingsec хорошим тоном будет добавить теги (согласно официальным рекомендациям Zabbix использовать нижний регистр):

  • component: network
  • target: icmp

Теперь наш шаблон содержит одну, но полностью рабочую инструкцию. Он правильно назван, лежит в нужной группе, знает, как собирать время отклика, в каком формате его хранить и как маркировать эти данные тегами.

Шаблон готов, но пока он существует только в базе данных вашего конкретного сервера Zabbix. Чтобы передать его клиенту или сохранить в систему контроля версий, этот чертеж нужно экспортировать в универсальный текстовый формат.

Экспорт и импорт шаблонов в формате YAML

Экспорт и импорт шаблонов в формате YAML

Вы создали свой первый шаблон с элементом данных и тегами через веб-интерфейс Zabbix. Теперь представьте, что этот мониторинг нужно внедрить на серверах пяти разных клиентов. Повторять десятки кликов в интерфейсе для каждого клиента — путь к неизбежным опечаткам и пустой трате времени. Профессиональная разработка требует, чтобы инфраструктура описывалась кодом, который можно скопировать, отправить коллеге или сохранить в системе контроля версий (например, Git).

Для этого Zabbix позволяет выгрузить любую конфигурацию в текстовый файл. Исторически для этого использовался формат XML, но начиная с версии 6.0 стандартом де-факто стал YAML. Он компактен, легко читается человеком и не перегружен лишними закрывающими тегами.

Анатомия экспортированного шаблона

Когда вы нажимаете кнопку «Экспорт» в списке шаблонов, Zabbix формирует текстовый файл, в котором строго соблюдена иерархия всех вложенных сущностей.

Давайте посмотрим, как выглядит наш шаблон с простой проверкой внутри YAML-файла.

zabbix_export:
  version: '6.4'
  template_groups:
    - uuid: 7df96b18c230490a9a0a9e2307226338
      name: 'Templates/Network'
  templates:
    - uuid: a1b2c3d4e5f67890
      template: 'Network connectivity by Simple check'
      name: 'Network connectivity'
      groups:
        - name: 'Templates/Network'
      items:
        - uuid: b2c3d4e5f6a78901
          name: 'ICMP ping'
          type: SIMPLE
          key: 'icmpping'
          delay: '1m'
          tags:
            - tag: component
              value: network

Каждый отступ в YAML имеет значение — он показывает уровень вложенности.

Корневой ключ zabbix_export сообщает системе, что перед ней корректный файл выгрузки, а version защищает от попыток импортировать новые функции в старые версии сервера.

Далее идут два главных блока:

  1. template_groups — объявляет группы, которые должны существовать в системе.
  2. templates — массив самих шаблонов. Внутри него мы видим наше техническое имя (template), видимое имя (name) и привязку к группе (groups).

Внутри шаблона раскрывается блок items. Здесь каждый элемент данных описан набором пар «ключ-значение». Поле type: SIMPLE соответствует выбранному нами типу «Simple check», key содержит ключ метрики, а delay — интервал обновления. В самом низу вложен блок tags, где лежат наши метки для фильтрации.

Разработка через код

Понимание этой структуры полностью меняет подход к созданию мониторинга. YAML-файл — это не просто резервная копия, это ваша среда разработки.

Допустим, вам нужно добавить еще пять метрик, похожих на icmpping (например, время отклика, процент потерь пакетов). В интерфейсе вам пришлось бы пять раз нажимать «Создать элемент данных», заново выбирать тип, вписывать теги. В текстовом редакторе вы просто копируете блок items нужное количество раз, меняете значения name и key за пару секунд, сохраняете файл и загружаете его обратно.

Более того, массовая замена (Find & Replace) позволяет в один клик изменить интервал опроса delay: '1m' на delay: '30s' сразу для сотен метрик в шаблоне.

Правила импорта и разрешение конфликтов

При загрузке YAML-файла обратно в Zabbix (кнопка «Импорт» в правом верхнем углу) система не применяет файл вслепую. Она сравнивает содержимое файла с тем, что уже есть в базе данных, ориентируясь на уникальные идентификаторы — UUID (uuid для шаблонов и их элементов), а также технические имена (template, key).

Перед импортом Zabbix предлагает матрицу правил, состоящую из трех основных действий для каждого типа сущностей:

  • Create new (Создавать новые) — если в файле есть элемент данных, которого нет в базе, он будет создан.
  • Update existing (Обновлять существующие) — если элемент данных есть и в файле, и в базе, Zabbix перезапишет настройки в базе теми, что указаны в файле (например, обновит изменившийся интервал опроса).
  • Delete missing (Удалять отсутствующие) — самое опасное правило. Если в базе есть элемент данных, привязанный к этому шаблону, но в загружаемом YAML-файле его нет, Zabbix безвозвратно удалит его из системы вместе со всей накопленной историей.

По умолчанию правило «Delete missing» отключено, чтобы защитить вас от случайной потери данных при частичном импорте.

Умение читать и править YAML-файлы делает шаблон отчуждаемым продуктом. Вы можете скачать готовые шаблоны от вендоров оборудования, открыть их в редакторе, вычистить ненужные метрики, изменить структуру тегов под стандарты вашей компании и только после этого импортировать в свой Zabbix.

Теперь у нас есть готовый, переносимый шаблон с метрикой доступности. Следующий шаг — применить эту теорию на практике: привязать наш шаблон к реальному узлу сети и убедиться, что данные начали поступать.

Привязка шаблонов к узлам сети и проверка работы

Привязка шаблонов к узлам сети и проверка работы

В прошлой главе мы успешно импортировали YAML-файл, и теперь в системе есть готовый шаблон с настроенным элементом данных для проверки пинга. Но если вы сейчас заглянете в базу данных Zabbix, то не найдете там ни одной новой метрики. Идеально написанный код инфраструктуры абсолютно бесполезен, пока он не применен к реальному объекту. Шаблон — это лишь чертеж. Чтобы чертеж ожил и начал генерировать данные, его нужно привязать к конкретному узлу сети.

Процесс привязки: соединяем чертеж с объектом

Привязка (Linking) — это момент, когда Zabbix берет все инструкции из шаблона и создает их рабочие копии внутри конкретного узла сети (Host).

Чтобы выполнить привязку, необходимо зайти в настройки целевого узла сети и перейти на вкладку Templates. В поле поиска достаточно начать вводить видимое имя нашего шаблона, выбрать его из выпадающего списка и нажать кнопку обновления узла.

В этот момент происходит магия наследования:

  1. Zabbix копирует структуру элемента данных из шаблона в узел сети.
  2. В интерфейсе настройки узла сети этот элемент данных появится с серым префиксом — именем шаблона. Это визуальный маркер того, что метрика унаследована, и ее ключевые параметры (например, ключ или интервал опроса) нельзя изменить прямо здесь. Измените в шаблоне — обновится на всех привязанных узлах.

Если вы привязываете шаблон к устройству, которое уже мониторится другими шаблонами (например, базовым шаблоном Linux), новый шаблон просто добавит свои метрики к существующим. Это и есть та самая модульность в действии.

Latest data: пульс вашего мониторинга

Профессиональный инженер никогда не завершает работу фразой «я привязал шаблон, всё готово». Работа считается выполненной только тогда, когда получены первые достоверные данные.

Единственное место, где следует проверять поступление сырых метрик — это раздел Latest data (Последние данные) в меню Monitoring. Это диагностический пульт Zabbix.

Зайдя в Latest data, нужно отфильтровать вывод по имени вашего узла сети. Вы увидите список всех элементов данных, привязанных к этому узлу. Напротив нашего ключа icmpping будут колонки с последним полученным значением и временем его получения.

Но часто новички сталкиваются с ситуацией: шаблон привязан, фильтр настроен, а колонка со значением пуста.

Жизненный цикл метрики: Supported и Not supported

Когда наступает время опроса, сервер Zabbix отправляет запрос к устройству. У этого действия может быть только два исхода, которые определяют внутреннее состояние элемента данных.

Если опрос прошел успешно, Zabbix записывает значение в базу. Элемент данных считается поддерживаемым (Supported). В интерфейсе списка элементов данных (раздел Configuration -> Hosts -> Items) он подсвечивается зеленым цветом.

Если же в процессе сбора произошла ошибка, Zabbix переводит элемент данных в состояние Not supported (Не поддерживается) и подсвечивает его красным.

Переход в Not supported — это защитный механизм. Zabbix понимает, что метрика сломана, и чтобы не тратить ресурсы на постоянные безуспешные попытки (например, если устройство выключено или ключ написан с опечаткой), он временно приостанавливает ее опрос. По умолчанию Zabbix будет проверять «сломанные» элементы данных значительно реже, пока они снова не начнут отвечать.

При наведении на красный значок ошибки Zabbix всегда показывает причину. Для нашей простой проверки (Simple check) типичные причины перевода в Not supported:

  • Узел сети недоступен по сети (отключен, закрыт файрволом).
  • Неверно указан IP-адрес или DNS-имя в настройках узла сети.
  • Опечатка в самом ключе icmpping (например, переданы неверные параметры).

Execute now: инструмент для нетерпеливых

Ждать 5 или 10 минут, пока сработает регулярный интервал опроса, чтобы проверить, починили ли вы ошибку — непозволительная роскошь при отладке.

Для мгновенной проверки существует кнопка Execute now (Выполнить сейчас). Она находится в списке элементов данных конкретного узла сети. Выделив нужный элемент галочкой и нажав эту кнопку, вы принудительно отправляете метрику в очередь на немедленный опрос, игнорируя заданный Update interval. После этого можно сразу переходить в Latest data и смотреть результат.

Однако у этой функции есть критически важное ограничение, о котором часто забывают. Execute now работает только для пассивных проверок. Пассивная проверка — это когда инициатором связи выступает сам сервер Zabbix (он «идет» к устройству и просит данные). Наша простая проверка icmpping — пассивная. Опросы по протоколу SNMP, к которым мы скоро перейдем, — тоже пассивные. Для них кнопка сработает идеально.

Но если вы используете активные проверки (например, тип Zabbix agent active, когда агент сам собирает данные и пушит их на сервер), сервер физически не может принудительно запросить данные сию минуту. В таких случаях кнопка Execute now просто не даст никакого эффекта.

Убедившись, что наша базовая метрика собирается и данные отображаются корректно, мы завершаем цикл создания простейшего шаблона. Механика привязки и проверки универсальна. Теперь, когда база заложена, мы готовы перейти к настоящему сетевому мониторингу и начать извлекать сотни метрик из маршрутизаторов и коммутаторов с помощью протокола SNMP.

Основы протокола SNMP и MIB-файлы

Основы протокола SNMP и MIB-файлы

В прошлых главах мы научились проверять доступность узлов с помощью простых проверок, таких как icmpping. Zabbix отправлял сетевой пакет и фиксировал ответ. Но что делать, если нам нужно узнать загрузку процессора на маршрутизаторе Cisco, уровень тонера в принтере HP или температуру батарей в ИБП?

Мы не можем установить Zabbix-агент на принтер или коммутатор — их операционные системы закрыты. Нам нужен универсальный язык общения, который понимают все аппаратные устройства "из коробки". В мире сетевого мониторинга таким языком является SNMP (Simple Network Management Protocol).

Архитектура: Менеджер и Агент

SNMP работает по клиент-серверной модели, но терминология здесь своя:

  1. SNMP Manager (Менеджер) — это наш сервер Zabbix. Он инициирует запросы, спрашивая: «Какая у тебя температура?», «Сколько трафика прошло через первый порт?».
  2. SNMP Agent (Агент) — это встроенная программа на самом устройстве (коммутаторе, принтере). Агент слушает запросы от Менеджера на стандартном UDP-порту 161, извлекает нужные данные из памяти устройства и отправляет их обратно.

В отличие от Zabbix-агента, который может сам активно пушить данные на сервер (активные проверки), при стандартном опросе (polling) SNMP работает в пассивном режиме: пока Zabbix не спросит, устройство будет молчать. Исключением является механизм SNMP Traps, который позволяет устройству самому асинхронно отправлять уведомления о событиях на UDP-порт 162 менеджера.

OID: Координаты метрик

Главный вопрос: как именно Zabbix формулирует свой запрос? Он не может отправить текстовую строку «дай мне загрузку CPU». Сетевые устройства хранят свои метрики в строгой иерархической базе данных. Каждая метрика имеет свой уникальный числовой адрес, который называется OID (Object Identifier — идентификатор объекта).

OID представляет собой последовательность чисел, разделенных точками. Структура OID напоминает дерево каталогов в файловой системе или структуру доменных имен, только читается она слева направо — от корня к конкретному листу.

Например, OID 1.3.6.1.2.1.2.2.1.10.1 означает счетчик входящего трафика на первом сетевом интерфейсе. Давайте разберем этот путь:

  • 1 — ISO (Международная организация по стандартизации, корень дерева).
  • 3 — ORG (Организации).
  • 6 — DOD (Министерство обороны США).
  • 1 — Internet.
  • 2 — Management (Управление).
  • 1 — MIB-2 (Стандартный набор сетевых метрик).
  • 2.2.1.10 — Входящий трафик (ifInOctets).
  • .1 — Индекс конкретного интерфейса (в данном случае, первого).

Первые цифры (1.3.6.1...) одинаковы почти для всех сетевых устройств в мире. Дальше дерево ветвится: есть стандартные ветки (одинаковые для всех вендоров) и приватные ветки (где Cisco, MikroTik или APC хранят свои уникальные метрики).

MIB: Телефонная книга протокола

Смотреть на числа вида 1.3.6.1.2.1.2.2.1.10.1 человеку крайне неудобно. Чтобы мы могли понимать, что скрывается за OID, были придуманы MIB-файлы (Management Information Base).

MIB — это просто текстовый файл-словарь. Он не содержит никаких данных с устройства. Его единственная задача — переводить нечитаемые числовые OID в понятные текстовые названия и обратно.

Используя MIB-файл, система мониторинга может показать вам текстовый эквивалент: IF-MIB::ifInOctets.1 вместо 1.3.6.1.2.1.2.2.1.10.1.

  • IF-MIB — это название конкретного словаря (модуля).
  • ifInOctets — текстовое имя метрики.
  • .1 — индекс интерфейса.

Золотое правило разработчика шаблонов

В Zabbix, при создании элемента данных типа "SNMP agent", вы можете указать OID в двух форматах: числовом (1.3.6.1.2.1.2.2.1.10.1) или текстовом (IF-MIB::ifInOctets.1).

Если вы укажете текстовый формат, Zabbix-сервер обратится к своим локальным MIB-файлам (обычно лежат в ОС сервера в /usr/share/snmp/mibs), найдет там перевод и отправит устройству числовой запрос. Устройство всегда общается только числами.

Здесь кроется главная ловушка для новичков. Профессиональные шаблоны Zabbix всегда используют числовые OID.

Если вы создадите шаблон, используя текстовые OID (например, MIKROTIK-MIB::mtxrWlStatTxRate), и отдадите этот шаблон клиенту, он у него не заработает. Шаблон перейдет в состояние Not supported. Почему? Потому что у клиента на его сервере Zabbix не установлен файл MIKROTIK-MIB.txt.

Используя числовые OID, вы делаете шаблон полностью автономным. Zabbix серверу не нужны никакие MIB-файлы, чтобы опрашивать устройство по числовому OID. MIB-файлы нужны только вам, разработчику, на этапе создания шаблона, чтобы понять, какой OID за что отвечает.

В следующей главе мы научимся использовать консольные утилиты, чтобы сканировать устройства, читать их MIB-деревья и находить нужные нам числовые OID для добавления в шаблон.

Инструменты snmpwalk и snmpget для исследования устройств

Инструменты snmpwalk и snmpget для исследования устройств

Вы знаете, что метрики в SNMP скрываются за числовыми адресами вроде 1.3.6.1.2.1.1.3.0. Но когда клиент дает вам IP-адрес нового коммутатора или источника бесперебойного питания, у вас нет готового списка этих адресов. Устройство представляет собой черный ящик. Чтобы превратить его в прозрачную структуру и найти нужные OID для шаблона Zabbix, используются консольные утилиты из пакета net-snmp.

Два главных инструмента в арсенале разработчика шаблонов — это snmpget и snmpwalk.

snmpget: точечный выстрел

Утилита snmpget запрашивает у устройства значение одного конкретного OID. Она используется, когда вы точно знаете адрес метрики и хотите проверить, отдает ли устройство данные.

Базовый синтаксис выглядит так: snmpget -v2c -c public 192.168.1.100 sysUpTime.0

Разберем параметры:

  • -v2c — версия протокола. В 90% случаев внутри локальных сетей используется версия 2c.
  • -c public — Community string. Это своеобразный пароль для доступа к данным по SNMPv1 и v2c. По умолчанию на многих устройствах на чтение установлен пароль public.
  • 192.168.1.100 — IP-адрес целевого устройства.
  • sysUpTime.0 — запрашиваемый OID (в данном случае текстовый, который утилита сама переведет в числовой благодаря локальным MIB-файлам).

Community string — строка-пароль, передаваемая в открытом виде в протоколах SNMPv1 и SNMPv2c. Служит единственным механизмом авторизации при запросе метрик.

Обратите внимание на .0 в конце OID. Метрика времени работы системы (sysUpTime) существует в устройстве в единственном экземпляре. Такие метрики называются скалярными объектами. В архитектуре SNMP, чтобы получить значение скалярного объекта, к его базовому OID всегда нужно добавлять индекс .0. Если вы запросите просто sysUpTime, устройство вернет ошибку, так как вы указали на папку, а не на конкретный файл внутри нее.

snmpwalk: сканирование радаром

Если snmpget — это снайперская винтовка, то snmpwalk — это радар, сканирующий целые секторы. Вы указываете начальный OID (ветку дерева), и утилита последовательно опрашивает все вложенные метрики, пока ветка не закончится.

Механика snmpwalk основана на SNMP-команде GetNext. Утилита запрашивает узел, получает ответ, затем берет OID из ответа и запрашивает следующий за ним, спускаясь по дереву. Это незаменимо, когда нужно исследовать таблицы — например, список всех сетевых интерфейсов коммутатора.

Выполним обход ветки ifDescr (описания интерфейсов): snmpwalk -v2c -c public 192.168.1.100 ifDescr

Вывод будет выглядеть примерно так:

IF-MIB::ifDescr.1 = STRING: GigabitEthernet0/1
IF-MIB::ifDescr.2 = STRING: GigabitEthernet0/2
IF-MIB::ifDescr.3 = STRING: GigabitEthernet0/3

Здесь цифры 1, 2, 3 после точки — это индексы. В отличие от скалярных объектов с их нулем, табличные объекты имеют уникальные индексы для каждой строки (в данном случае — для каждого порта).

Подготовка OID для Zabbix: флаг -On

Обе утилиты по умолчанию стараются сделать вывод максимально понятным для человека, подставляя текстовые имена из MIB-файлов операционной системы. Но для создания профессиональных шаблонов Zabbix нам нужны сырые числовые OID.

Чтобы заставить snmpget и snmpwalk выводить полные числовые значения, используется флаг форматирования вывода -On (Output numeric).

Сравните два запроса: Без флага: snmpget -v2c -c public 10.0.0.5 sysName.0 Результат: SNMPv2-MIB::sysName.0 = STRING: Core-Switch-01

С флагом: snmpget -v2c -c public -On 10.0.0.5 sysName.0 Результат: .1.3.6.1.2.1.1.5.0 = STRING: Core-Switch-01

Именно значение .1.3.6.1.2.1.1.5.0 готово для копирования в поле Key элемента данных Zabbix.

Практический сценарий: поиск метрики трафика

Свяжем инструменты воедино на реальной задаче. Нам нужно добавить в шаблон мониторинг входящего трафика на порту «GigabitEthernet0/2», но мы не знаем его OID.

Шаг 1. Находим индекс порта. Используем snmpwalk по ветке описаний интерфейсов, чтобы найти нужный порт: snmpwalk -v2c -c public 192.168.1.100 ifDescr Видим в выдаче: IF-MIB::ifDescr.2 = STRING: GigabitEthernet0/2. Отлично, индекс нужного порта — 2.

Шаг 2. Находим OID счетчика трафика. Мы знаем, что входящий трафик — это ветка ifInOctets. Соединяем ветку и найденный индекс: ifInOctets.2.

Шаг 3. Получаем числовой OID для Zabbix. Делаем точечный запрос с флагом -On, чтобы получить готовую строку для шаблона: snmpget -v2c -c public -On 192.168.1.100 ifInOctets.2 Результат: .1.3.6.1.2.1.2.2.1.10.2 = Counter32: 34598213

Теперь у нас есть точный числовой адрес .1.3.6.1.2.1.2.2.1.10.2, который гарантированно будет работать в Zabbix без зависимости от загруженных на сервер MIB-файлов. Мы исследовали устройство и добыли нужные координаты.

Создание элементов данных SNMP в Zabbix

Создание элементов данных SNMP в Zabbix

В консоли мы выполнили snmpget и получили ответ от коммутатора: счетчик входящего трафика равен 15432098 байт. Отлично, устройство отдаёт данные. Но консольная утилита делает это единожды и по нашему требованию. Как превратить этот ручной запрос в автоматический процесс, который Zabbix будет выполнять каждые пять минут, сохраняя историю и строя графики?

Для этого консольную команду нужно «перевести» на язык интерфейса Zabbix, создав элемент данных внутри нашего шаблона.

От консоли к интерфейсу: маппинг параметров

Создание элемента данных (Item) для SNMP концептуально не отличается от создания простой проверки, которую мы делали ранее. Разница кроется в типе элемента и специфичных полях, которые в точности повторяют параметры утилиты snmpget.

Зайдите в ваш шаблон, откройте раздел Items и нажмите Create item. В поле Type выберите SNMP agent. Интерфейс немного изменится, подстраиваясь под протокол.

Давайте разберем, как аргументы из консоли ложатся в поля Zabbix:

  1. SNMP OID Это самое важное поле. Сюда мы вставляем тот самый числовой идентификатор, который нашли с помощью snmpwalk и флага -On. Например: .1.3.6.1.2.1.2.2.1.10.1. Никаких текстовых MIB-имен здесь быть не должно — только цифры и точки.

  2. Key (Ключ) Здесь новички часто совершают ошибку, пытаясь вставить OID.

    В SNMP-элементах поле Key не участвует в опросе устройства. Оно нужно исключительно самому Zabbix для уникальной идентификации метрики в базе данных.

    Вы можете написать в ключе traffic.in.port1 или cisco.bytes.rx[1]. Главное правило: ключ должен быть уникальным в рамках узла сети и понятным вам.

  3. Type of information (Тип информации) В выводе snmpget мы видели тип данных, который отдает устройство: Counter32, Gauge32, INTEGER или STRING. Zabbix должен знать, как сохранить эти данные:

    • Counter32/64, Gauge32, Timeticks → выбираем Numeric (unsigned) (целое положительное число).
    • Значения с плавающей точкой (например, температура 36.6) → выбираем Numeric (float).
    • STRING (текст, название модели) → выбираем Character или Text.

Авторизация: где указывать Community?

Когда мы делали запрос в консоли, мы явно указывали пароль сообщества: -c public. Но в настройках самого элемента данных SNMP в современных версиях Zabbix вы не найдете поля «SNMP community».

Почему? Потому что пароль — это свойство конкретного железа, а не шаблона. Если мы зашьем слово public прямо в элемент данных шаблона, мы не сможем применить этот шаблон к клиенту, у которого пароль secret123.

Zabbix решает это элегантно: авторизация настраивается на уровне Host interface (интерфейса узла сети). Когда вы будете привязывать шаблон к реальному коммутатору, вы добавите ему интерфейс типа SNMP, и именно там укажете IP-адрес, версию протокола (v2c) и Community.

В шаблонах же для Community по умолчанию используется системный макрос {$SNMP_COMMUNITY}. Элемент данных просто берет настройки из интерфейса того узла, к которому прикреплен шаблон.

Практический нюанс: работа со счетчиками (Counters)

Допустим, мы создали элемент данных для сбора входящего трафика (ifInOctets.1). Мы указали OID, выбрали тип Numeric (unsigned) и задали единицу измерения (поле Units) как B (байты).

Если мы оставим всё как есть, на графике мы увидим постоянно растущую линию: 10 МБ, 15 МБ, 100 МБ, 2 ГБ. Это происходит потому, что сетевые интерфейсы отдают не текущую скорость, а абсолютный счетчик пропущенных через них байт с момента включения устройства.

Нам же нужна скорость — байты в секунду.

Для этого в Zabbix существует вкладка Preprocessing (Предобработка) внутри настроек элемента данных. Это конвейер, который модифицирует полученное значение до того, как оно попадет в базу. Чтобы превратить растущий счетчик в скорость, нужно добавить один шаг предобработки:

  • Name: Change per second (Изменение в секунду).

Zabbix сам возьмет новое значение, вычтет из него предыдущее и разделит на количество прошедших секунд. В базу запишется реальная текущая скорость.

Инструмент Test: отладка без ожидания

При ручном создании шаблонов неизбежны опечатки: забыли точку в начале OID, ошиблись индексом порта, выбрали не тот тип данных.

Раньше приходилось сохранять элемент, идти в раздел Latest data и ждать 5 минут, пока Zabbix попытается его опросить, чтобы увидеть статус Not supported.

Сейчас в самом низу окна настройки элемента данных есть кнопка Test. Она позволяет выполнить тестовый опрос прямо из браузера, не сохраняя элемент и не дожидаясь расписания.

Так как мы находимся в шаблоне (у которого нет IP-адреса), при нажатии Test откроется окно, где Zabbix попросит временно указать параметры для проверки:

  • Host address: IP вашего тестового устройства.
  • Port: 161 (стандартный порт SNMP).
  • Macro {$SNMP_COMMUNITY}: впишите реальный пароль (например, public).

Нажмите Get value. Если всё настроено верно, вы мгновенно увидите сырое значение от устройства. Если есть ошибка (например, неверный OID) — Zabbix сразу покажет причину (например, No Such Instance currently exists at this OID). Это экономит часы времени при разработке объемных шаблонов.

Использование динамических OID и индексов

Использование динамических OID и индексов

Вы создали идеальный шаблон для коммутатора, жестко прописав OID .1.3.6.1.2.1.2.2.1.10.1 для сбора трафика с первого порта. Вы применяете этот шаблон к 50 устройствам у клиента, и на следующий день получаете шквал ложных срабатываний. Оказывается, на половине коммутаторов под индексом .1 скрывается не физический порт, а виртуальный интерфейс управления (VLAN), на котором почти нет трафика. Шаблон, который отлично работал на тестовом стенде, в реальной сети оказался бесполезен.

Эта ситуация — классическое столкновение с проблемой смещения индексов. Чтобы создавать профессиональные шаблоны, метрики нужно привязывать не к порядковым номерам, а к именам.

Ловушка жестких индексов (Index Shifting)

В прошлой главе мы выяснили, что скалярные объекты (например, аптайм устройства) всегда заканчиваются на .0. Но метрики интерфейсов, дисков или процессоров хранятся в таблицах, и их OID заканчивается индексом строки — .1, .2, .15.

Проблема в том, что протокол SNMP не гарантирует постоянства этих индексов. Индекс .1 может принадлежать порту GigabitEthernet0/1 сегодня, но если администратор добавит в коммутатор новый модуль расширения или просто перезагрузит устройство, операционная система маршрутизатора может перестроить таблицу. Порт GigabitEthernet0/1 получит индекс .50, а индекс .1 уйдет другому интерфейсу. Это явление называется Index shifting (смещение индексов).

Если в элементе данных Zabbix жестко прописан статический OID, после смещения индексов Zabbix продолжит опрашивать старый номер. В лучшем случае вы начнете собирать данные от чужого порта, в худшем — метрика перейдет в состояние Not supported, так как индекс перестанет существовать.

Как связаны таблицы SNMP

Чтобы решить эту проблему, нужно понять, как SNMP организует связанные данные. Протокол не хранит имя порта и его трафик в одной строке. Вместо этого он использует несколько параллельных таблиц, которые связываются через общий индекс.

Рассмотрим две ветки OID:

  1. Базовый OID имен интерфейсов (ifDescr): .1.3.6.1.2.1.2.2.1.2
  2. Базовый OID входящего трафика (ifInOctets): .1.3.6.1.2.1.2.2.1.10

Если порт GigabitEthernet0/1 при инициализации получил индекс 5, то:

  • Его имя будет лежать по адресу: .1.3.6.1.2.1.2.2.1.2.5
  • Его трафик будет лежать по адресу: .1.3.6.1.2.1.2.2.1.10.5

Нам нужен механизм, который скажет серверу мониторинга: «Найди в таблице имен порт с названием GigabitEthernet0/1, посмотри, какой у него индекс на конце, и подставь этот индекс к базовому OID трафика».

Синтаксис динамических индексов в Zabbix

Сам по себе протокол SNMP не умеет искать по строкам — он понимает только точные числовые адреса. Динамический поиск — это эксклюзивная функция самого сервера Zabbix.

Вместо того чтобы писать статический OID в поле SNMP OID элемента данных, мы используем специальную конструкцию:

целевой_OID["index","поисковый_OID","искомая_строка"]

Разберем каждый элемент на нашем примере с трафиком:

  1. целевой_OID — базовая часть OID той метрики, которую мы хотим собирать (трафик). В нашем случае это .1.3.6.1.2.1.2.2.1.10.
  2. "index" — обязательное системное слово Zabbix, указывающее, что дальше идет инструкция для поиска.
  3. поисковый_OID — базовая часть OID той таблицы, где лежат текстовые значения (имена интерфейсов). Это .1.3.6.1.2.1.2.2.1.2.
  4. искомая_строка — точное имя интерфейса, которое мы ищем. Например, GigabitEthernet0/1.

Итоговая строка, которую нужно вставить в поле SNMP OID в Zabbix, выглядит так: .1.3.6.1.2.1.2.2.1.10["index",".1.3.6.1.2.1.2.2.1.2","GigabitEthernet0/1"]

Как это работает под капотом и влияние на производительность

Когда Zabbix видит такую конструкцию, он выполняет два шага:

  1. Делает snmpwalk (обход) по поисковому OID (.1.3.6.1.2.1.2.2.1.2), запрашивая все имена интерфейсов, пока не найдет строку GigabitEthernet0/1. Найдя её, он извлекает индекс (например, 5).
  2. Приклеивает найденный индекс 5 к целевому OID и делает обычный snmpget по адресу .1.3.6.1.2.1.2.2.1.10.5.

Может показаться, что обход дерева при каждом сборе метрики убьет производительность сети и сервера. Однако Zabbix использует кэширование индексов. Выполнив поиск один раз, Zabbix запоминает, что GigabitEthernet0/1 = 5. При следующих опросах он сначала проверяет сохраненный индекс (запрашивает имя по индексу 5). Если имя совпадает, Zabbix запрашивает саму метрику. Если устройство перезагрузится и индекс сменится (по индексу 5 окажется другое имя или пустота), Zabbix обнаружит несовпадение, сбросит кэш и заново обойдет таблицу для поиска нового индекса.

Когда использовать динамические индексы

Динамические OID — мощный инструмент, но применять его нужно с умом.

Этот метод идеально подходит для известных, единичных интерфейсов. Например, если вам нужно мониторить главный Uplink-порт на всех коммутаторах провайдера, и вы знаете, что он везде называется eth-trunk1. Вы создаете один элемент данных с динамическим индексом, и он безотказно работает на всем парке устройств, игнорируя смещение индексов.

Но что, если вам нужно мониторить все 48 портов на коммутаторе? Создавать 48 элементов данных вручную, прописывая динамический индекс для каждого порта (Port1, Port2 и т.д.) — это грубое нарушение принципов профессиональной разработки шаблонов. Шаблон должен адаптироваться к устройству сам: если портов 24 — собрать 24 метрики, если 48 — собрать 48.

Для массового автоматического создания элементов данных на основе таблиц SNMP используется другой механизм Zabbix — низкоуровневое обнаружение (LLD). К нему мы перейдем в следующих главах, но базовый принцип связи таблиц через общий индекс, разобранный здесь, станет фундаментом для понимания автоматизации.

Создание триггеров для SNMP-метрик

Создание триггеров для SNMP-метрик

Вы настроили сбор данных по SNMP. В разделе Latest data бегут значения счетчиков трафика, статусы портов и загрузка процессора маршрутизатора. Но мониторинг — это не наблюдение за экраном с цифрами. Система должна сама анализировать поток данных и бить тревогу, когда параметры выходят за допустимые пределы. Для этого в Zabbix используются триггеры.

Триггер — это логическое выражение, которое непрерывно оценивает поступающие данные. Если выражение истинно, триггер переходит в состояние Problem (Проблема). Если ложно — возвращается в состояние OK.

Триггер не собирает данные сам. Он лишь смотрит на значения, которые уже принес элемент данных (Item), и делает математический вывод.

Анатомия выражения триггера

Чтобы Zabbix понял, когда создавать проблему, мы пишем выражение. В современном Zabbix синтаксис выражения выглядит как вызов функции, внутри которой указывается путь к метрике и параметры оценки.

Базовый шаблон выражения: функция(/Имя_шаблона/Ключ_элемента, параметры) оператор константа

Давайте разберем самые частые функции, которые используются в профессиональных шаблонах для сетевого оборудования.

Функция last() — реакция на статус

Функция last() берет самое последнее полученное значение метрики. Она идеальна для дискретных состояний (включено/выключено, работает/сломано).

В SNMP статус интерфейса (ifOperStatus) передается целыми числами. Согласно MIB-файлам, значение 11 означает «Up» (работает), а 22 — «Down» (упал).

Если мы хотим получить алерт при падении порта, выражение будет таким: last(/Template Network Cisco/net.if.status["index","ifDescr","GigabitEthernet0/1"]) = 2

Как только устройство пришлет по SNMP двойку, выражение 2=22 = 2 станет истинным, и зажжется проблема.

Функция avg() — сглаживание пиков

Функция avg() вычисляет среднее значение за указанный период времени. Она незаменима для аналоговых величин: загрузки процессора, памяти или утилизации канала.

Если вы настроите триггер на last() > 80 для процессора маршрутизатора, вы будете получать ложные тревоги каждый раз, когда кто-то подключается к устройству по SSH (это вызывает секундный всплеск нагрузки).

Правильный подход — оценивать среднюю температуру по больнице: avg(/Template Network Cisco/system.cpu.util, 5m) > 80

Этот триггер сработает, только если средняя загрузка CPU за последние 5 минут превысит 80%80\%. Секундные пики будут проигнорированы.

Функция nodata() — защита от тишины UDP

Протокол SNMP работает поверх UDP. Это означает, что Zabbix отправляет запрос и просто ждет ответа. Если коммутатор завис, сгорел или кабель перерезали, Zabbix не получит ошибку «Connection refused» (как было бы с TCP). Он просто перестанет получать данные.

Если данные не поступают, функции last() и avg() продолжают оперировать старыми закэшированными значениями. Триггер last() = 2 никогда не сработает, потому что устройство физически не может прислать статус «упал».

Поэтому для проверки доступности узла по SNMP критически важно использовать функцию nodata(): nodata(/Template Network Cisco/sysUpTime.0, 5m) = 1

Функция возвращает 11, если новых данных по указанной метрике не было в течение заданного времени (в данном случае 5 минут). Это главный способ узнать, что устройство «умерло».

Проблема «дребезга» (Flapping) и Гистерезис

Представьте, что вы настроили триггер на температуру в серверной: проблема возникает, если температура поднимается выше 2525 градусов. Выражение: last(/Template/temp) > 25.

Кондиционер сломался, температура достигла 25.125.1. Триггер сработал, вы получили письмо. Через минуту сквозняк остудил датчик до 24.924.9. Выражение стало ложным, проблема закрылась, вы получили письмо «Всё ОК». Ещё через минуту температура снова 25.125.1 — новая проблема, новое письмо.

Это явление называется Flapping (дребезг). Метрика колеблется вокруг порогового значения, генерируя десятки бесполезных уведомлений, заставляя инженеров игнорировать мониторинг.

Профессиональный шаблон не должен «спамить». Для решения этой проблемы применяется гистерезис — разделение порогов срабатывания и восстановления.

В Zabbix для этого используется специальная настройка триггера — OK event closes переключается в режим Recovery expression (Выражение восстановления).

Вместо одного условия мы пишем два:

  1. Problem expression: last(/Template/temp) > 25 (Когда бить тревогу).
  2. Recovery expression: last(/Template/temp) < 22 (Когда считать, что всё точно наладилось).

Теперь, если температура скачет между 2424 и 2626 градусами, триггер сработает один раз при пересечении отметки 2525. Он останется в состоянии Problem и не закроется, пока температура не упадет ниже 2222 градусов. Дребезг устранен.

Использование гистерезиса — это маркер качественного шаблона. Его обязательно нужно применять для метрик, склонных к микроколебаниям: загрузка CPU, заполненность дисков, напряжение на ИБП и утилизация сетевых каналов.

В следующих статьях мы разберем, как избавиться от жестко зашитых чисел (вроде 8080 или 2525) в триггерах и сделать шаблоны по-настоящему гибкими с помощью макросов.

Макросы в шаблонах: глобальные, шаблона и пользовательские

Макросы в шаблонах: глобальные, шаблона и пользовательские

Представьте, что вы создали идеальный шаблон для мониторинга коммутаторов. Вы прописали сбор трафика, температуры и загрузки процессора. И вот вы внедряете его у первого клиента: пароль для SNMP (Community) у него public, а критическая температура в серверной — 25 градусов. Шаблон работает отлично.

Затем вы идете ко второму клиенту. У него Community — secret_sw, а коммутаторы стоят в горячем цеху, где нормальная температура — 40 градусов. Если настройки жестко вшиты в шаблон, вам придется копировать его и переделывать под каждого нового клиента. К десятому внедрению у вас будет зоопарк из десятков почти одинаковых шаблонов, управлять которыми невозможно.

Профессиональная разработка шаблонов исключает жесткое кодирование (hardcode) изменяемых параметров. Для этого в Zabbix существует механизм макросов.

Что такое макросы в Zabbix

Макрос — это переменная. Zabbix использует макросы, чтобы динамически подставлять нужные значения в элементы данных, триггеры и интерфейсы в момент их выполнения.

Глобально макросы делятся на две большие группы:

  1. Встроенные макросы — их значения Zabbix вычисляет сам. Например, макрос {HOST.IP} автоматически подставит IP-адрес узла сети, к которому привязан шаблон. Их синтаксис — фигурные скобки без дополнительных символов.
  2. Пользовательские макросы — переменные, значения которых задаете вы сами. Их отличительный признак — знак доллара внутри фигурных скобок: {$MACRO_NAME}.

Именно пользовательские макросы делают шаблоны гибкими и универсальными.

Пользовательские макросы в триггерах

В прошлой главе мы рассматривали триггер для отслеживания температуры с использованием гистерезиса. Он выглядел примерно так: Проблема открывается при last() > 25 и закрывается при last() < 22.

Числа 25 и 22 — это классический хардкод. Если мы заменим их на макросы, триггер приобретет следующий вид: Проблема открывается при last() > {$TEMP.MAX.CRIT} и закрывается при last() < {$TEMP.MAX.RECOVER}.

Теперь сам триггер в шаблоне становится универсальной логической формулой. Он говорит: «Я сработаю, когда температура превысит критический порог, каким бы он ни был для данного устройства». А вот сами значения порогов мы вынесем в настройки макросов.

Иерархия разрешения макросов

Главная суперсила пользовательских макросов — это механизм их переопределения (наследования). Когда Zabbix видит в элементе данных или триггере макрос {$SNMP_COMMUNITY}, он начинает искать его значение, двигаясь строго сверху вниз по трем уровням.

1. Уровень узла сети (Host level)

Это самый высокий приоритет. Сначала Zabbix проверяет, задан ли макрос {$SNMP_COMMUNITY} в настройках конкретного устройства (коммутатора, сервера). Если значение найдено, поиск немедленно прекращается, и используется именно оно. Это позволяет точечно переопределить настройки для одного нестандартного устройства, не трогая остальные.

2. Уровень шаблона (Template level)

Если на самом узле сети макроса нет, Zabbix спускается на уровень шаблона, который привязан к этому узлу. Здесь задаются значения по умолчанию для данного класса устройств. Например, в шаблоне «Cisco IOS by SNMP» логично задать {$TEMP.MAX.CRIT} равным 60, так как это типичный порог для такого оборудования.

3. Глобальный уровень (Global level)

Если макрос не найден ни на узле, ни в шаблоне, Zabbix ищет его в глобальных настройках системы (Administration -> Macros, или Administration -> General -> Macros в версиях до 7.0). Здесь хранятся абсолютные значения по умолчанию для всей инсталляции Zabbix. Например, глобальный макрос {$SNMP_COMMUNITY} часто задают как public, чтобы новые устройства опрашивались базовым паролем, если нигде не указано иное.

Иерархия макросов реализует принцип «от частного к общему». Вы задаете базовые правила глобально, уточняете их в шаблонах для групп устройств, и при необходимости точечно переопределяете на конкретных хостах.

Типы пользовательских макросов (безопасность)

При создании макроса Zabbix позволяет выбрать его тип, что критически важно для безопасности, особенно при работе с протоколом SNMP.

Тип макроса Описание Применение
Text Обычный текст, видимый всем пользователям, имеющим доступ к шаблону или узлу сети. Пороги триггеров ({$CPU.UTIL.CRIT}), порты ({$SNMP.PORT}).
Secret text Значение скрыто звездочками (******). После сохранения его нельзя посмотреть в интерфейсе, можно только перезаписать. Пароли, SNMP Community ({$SNMP_COMMUNITY}), токены API.
Vault secret Значение не хранится в базе Zabbix, а извлекается на лету из внешнего хранилища секретов (HashiCorp Vault или CyberArk). Enterprise-инсталляции с жесткими требованиями ИБ.

В профессиональных шаблонах макрос {$SNMP_COMMUNITY} всегда должен создаваться с типом Secret text. Это защищает инфраструктуру клиента от компрометации паролей через интерфейс мониторинга.

Стандарты именования (Naming Conventions)

Поскольку макросы из разных шаблонов могут пересекаться на одном узле сети, бессистемное именование приведет к хаосу. Если в одном шаблоне вы назовете порог {$CRIT}, а в другом {$MAX_VAL}, вы быстро запутаетесь, какой макрос за что отвечает.

Официальный гайдлайн Zabbix предписывает использовать точечную нотацию: {$СУЩНОСТЬ.МЕТРИКА.ДЕЙСТВИЕ}

Примеры правильного именования:

  • {$CPU.UTIL.CRIT} — загрузка CPU, утилизация, критический порог.
  • {$MEMORY.UTIL.MAX} — память, утилизация, максимальное значение.
  • {$VFS.FS.PUSED.MAX.WARN} — виртуальная файловая система, процент использования, максимум, порог предупреждения.

Соблюдение этого стандарта делает ваши шаблоны предсказуемыми. Любой инженер, взглянув на макрос {$ICMP.LOSS.WARN}, сразу поймет, что он управляет порогом предупреждения для потери ICMP-пакетов, даже не открывая сам триггер.

В следующей главе мы расширим возможности макросов и разберем, как задавать разные пороги для разных объектов одного типа (например, разные пороги свободного места для диска C: и диска D:) с помощью контекстных макросов.

Использование контекстных макросов

Использование контекстных макросов

Представьте 48-портовый сетевой коммутатор. Вы настроили триггер, который отправляет уведомление, если количество ошибок на любом порту превышает 10 в секунду. Но порт GigabitEthernet0/1 — это магистральный аплинковый канал, для которого 50 ошибок в секунду являются нормой из-за высокой нагрузки, а порт GigabitEthernet0/2 подключен к старому серверу, где даже 2 ошибки говорят о проблеме с кабелем. Создавать 48 отдельных триггеров с жестко заданными порогами — значит сделать шаблон нечитаемым и невозможным для поддержки.

Эту архитектурную проблему решают контекстные макросы. Они позволяют использовать в триггере одну и ту же переменную, которая динамически меняет свое значение в зависимости от того, к какому именно объекту (контексту) она применяется в данный момент.

Синтаксис и анатомия контекста

Контекстный макрос — это расширение обычного пользовательского макроса, к которому через двоеточие добавляется уточняющая строка.

Базовый синтаксис выглядит так: {$МАКРОС:"контекст"}.

  • {$IF.ERRORS.MAX} — базовый макрос (значение по умолчанию).
  • {$IF.ERRORS.MAX:"GigabitEthernet0/1"} — макрос с контекстом для конкретного порта.

Контекст всегда рекомендуется заключать в двойные кавычки. Если внутри самого контекста встречаются кавычки, их необходимо экранировать обратным слешем (\"). Zabbix использует контекст как ключ поиска: когда триггер вычисляет выражение для конкретного сетевого интерфейса, он подставляет имя этого интерфейса в макрос и ищет соответствующее значение.

Контекст не обязательно должен быть именем интерфейса. Это может быть точка монтирования диска ({$VFS.FS.FREE.MIN:"/var/log"}), имя службы Windows ({$SERVICE.STARTUP:"W3SVC"}) или даже код HTTP-ответа.

Механизм фоллбэка (Fallback)

Главная сила контекстных макросов кроется не в самом синтаксисе, а в алгоритме, по которому Zabbix ищет их значения. Этот алгоритм называется фоллбэком (отступлением) и гарантирует, что система не сломается, если для конкретного объекта не задан индивидуальный порог.

Когда Zabbix встречает в триггере макрос с контекстом, он выполняет поиск значения в строгой последовательности:

  1. Точное совпадение контекста. Сначала система ищет макрос, контекст которого буква в букву совпадает с запрошенным. Поиск идет по стандартной иерархии: сначала на уровне узла сети, затем в шаблоне, затем в глобальных макросах.
  2. Совпадение по регулярному выражению. Если точного совпадения нет, Zabbix проверяет макросы, где контекст задан в виде регулярного выражения (синтаксис regex:паттерн).
  3. Базовый макрос (без контекста). Если ни точный контекст, ни регулярное выражение не найдены, Zabbix отбрасывает контекст и использует значение базового макроса {$МАКРОС}. Это и есть фоллбэк — страховочная сетка.

Регулярные выражения в контекстах

Возможность использовать регулярные выражения (RegEx) внутри контекста позволяет группировать объекты и применять к ним общие политики без необходимости прописывать каждый объект индивидуально.

Чтобы Zabbix понял, что перед ним регулярное выражение, контекст должен начинаться с префикса regex:.

Рассмотрим практический пример настройки порогов утилизации для различных типов портов на маршрутизаторе Cisco:

Имя макроса в шаблоне Значение Логика применения
{$IF.UTIL.MAX:"regex:^GigabitEthernet"} 90 Для всех гигабитных портов тревога сработает при 90% загрузки.
{$IF.UTIL.MAX:"regex:^FastEthernet"} 70 Старые 100-мегабитные порты не должны нагружаться выше 70%.
{$IF.UTIL.MAX:"regex:^Tunnel"} 50 VPN-туннели требуют запаса пропускной способности, порог 50%.
{$IF.UTIL.MAX} 80 Базовый порог. Применится ко всем остальным интерфейсам (например, Loopback или Vlan), которые не попали под регулярные выражения выше.

Если в триггере для порта FastEthernet0/5 будет вызван макрос {$IF.UTIL.MAX:"FastEthernet0/5"}, Zabbix не найдет точного совпадения, перейдет к проверке регулярных выражений, найдет совпадение с префиксом ^FastEthernet и вернет значение 70.

Взаимодействие с иерархией объектов

Контекстные макросы подчиняются тем же правилам наследования, что и обычные. Это позволяет архитекторам мониторинга создавать гибкие шаблоны, которые инженеры эксплуатации могут точечно переопределять на конечных устройствах.

В шаблоне Cisco IOS by SNMP вы задаете базовую политику:

  • {$IF.ERRORS.MAX} = 10
  • {$IF.ERRORS.MAX:"regex:^Gigabit"} = 20

Шаблон применяется к сотне коммутаторов. Но на одном конкретном коммутаторе (узле сети) порт GigabitEthernet0/48 подключен к нестандартному оборудованию, которое постоянно генерирует фоновые ошибки. Чтобы триггер не спамил алертами, инженер открывает настройки этого конкретного узла сети и добавляет макрос:

  • {$IF.ERRORS.MAX:"GigabitEthernet0/48"} = 1000

При оценке триггера для этого порта Zabbix сначала проверит макросы узла сети. Он найдет точное совпадение 1000 и остановит поиск. Для порта GigabitEthernet0/47 на этом же коммутаторе точного совпадения на узле сети не будет, система спустится на уровень шаблона, найдет регулярное выражение ^Gigabit и применит значение 20.

Такой подход избавляет от необходимости клонировать шаблоны ради одного нестандартного порта и сохраняет централизованное управление логикой мониторинга. Вся мощь контекстных макросов раскрывается, когда контекст подставляется не вручную, а генерируется автоматически на основе данных, полученных от самого устройства.

Безопасность SNMP: настройка SNMPv3 в шаблонах

Безопасность SNMP: настройка SNMPv3 в шаблонах

Если вы используете SNMPv1 или SNMPv2c в корпоративной сети, любой человек с запущенным анализатором трафика (например, Wireshark) может прочитать все ваши метрики. Более того, вместе с метриками в открытом виде передается и Community string — пароль для доступа к устройству. В современных сетях банков, дата-центров и крупных enterprise-клиентов использование SNMPv2c строго запрещено политиками безопасности.

Чтобы внедрять шаблоны профессионально, вы должны уметь работать с SNMPv3 — версией протокола, которая решает проблемы аутентификации и шифрования.

Архитектура SNMPv3: от Community к USM

В SNMPv2c авторизация строилась на едином пароле (Community), общем для всего устройства. В SNMPv3 используется USM (User-Based Security Model) — модель безопасности на основе пользователей.

Теперь вместо одного пароля вы создаете учетную запись, которая состоит из трех компонентов:

  1. Security Name — имя пользователя.
  2. Authentication (Auth) — проверка подлинности. Гарантирует, что запрос пришел именно от сервера Zabbix, а данные не были изменены в пути.
  3. Privacy (Priv) — шифрование полезной нагрузки. Гарантирует, что никто не сможет прочитать значения метрик при перехвате трафика.

Для аутентификации (Auth) обычно используются алгоритмы хеширования SHA или MD5. Для шифрования (Priv) — алгоритмы AES или DES.

В профессиональных шаблонах и при настройке оборудования всегда избегайте MD5 и DES — они признаны устаревшими и уязвимыми. Золотой стандарт сегодня: SHA для аутентификации и AES (AES-128 или AES-256) для шифрования.

Уровни безопасности (Security Levels)

В зависимости от того, какие компоненты USM вы активируете, SNMPv3 может работать на трех разных уровнях безопасности. При создании элемента данных в Zabbix вам нужно будет выбрать один из них в поле Security level:

Уровень безопасности Аутентификация (Auth) Шифрование (Priv) Когда использовать
noAuthNoPriv Нет (только логин) Нет (открытый текст) Почти никогда. Смысла переходить на v3 ради этого уровня нет.
authNoPriv Да (проверка подлинности) Нет (открытый текст) В закрытых management-сетях, где важно подтвердить источник запроса, но шифрование метрик избыточно и тратит CPU роутера.
authPriv Да Да (полное шифрование) Стандарт по умолчанию для любых сетей, передача данных через интернет или недоверенные сегменты.

Настройка SNMPv3 в шаблоне Zabbix

При создании элемента данных (Item) типа SNMP agent и выборе версии SNMPv3, интерфейс Zabbix скрывает поле SNMP community и открывает блок настроек USM.

Здесь кроется главная ошибка новичков: вписывать логины и пароли прямо в поля элемента данных. Если вы так сделаете, шаблон станет «одноразовым» — его нельзя будет экспортировать и применить у другого клиента без ручного переписывания сотен элементов данных.

Опираясь на знания из предыдущих глав, мы обязаны использовать пользовательские макросы для всех текстовых полей SNMPv3.

Стандартный набор макросов для профессионального шаблона выглядит так:

  • Поле Security name \rightarrow {$SNMP.V3.USER}
  • Поле Authentication passphrase \rightarrow {$SNMP.V3.AUTH.PASS}
  • Поле Privacy passphrase \rightarrow {$SNMP.V3.PRIV.PASS}
  • Поле Context name \rightarrow {$SNMP.V3.CONTEXT}

Сами алгоритмы (например, SHA и AES) задаются в Zabbix через выпадающие списки (радиокнопки). Их нельзя задать макросом. Поэтому в описании вашего шаблона (в поле Description) обязательно нужно указать: "This template requires SNMPv3 with SHA authentication and AES encryption".

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

Пароли для Auth и Priv — это чувствительные данные. В настройках шаблона (вкладка Macros) вы должны задать для них пустые значения по умолчанию, но обязательно изменить их тип на Secret text или Vault secret.

Это гарантирует, что когда администратор на стороне клиента заполнит эти макросы на уровне конкретного узла сети (Host), пароли скроются за звездочками и не попадут в открытом виде в логи или на экраны других пользователей Zabbix.

Что такое Context name?

В настройках элемента данных SNMPv3 есть неочевидное поле Context name. В 95% случаев его нужно оставлять пустым (или передавать пустой макрос {$SNMP.V3.CONTEXT}).

Контекст используется в сложном оборудовании, которое виртуализировано внутри себя. Например, в коммутаторах Cisco с технологией VRF (Virtual Routing and Forwarding) или межсетевых экранах CheckPoint VSX. В таких устройствах один физический роутер содержит несколько виртуальных таблиц маршрутизации. Чтобы Zabbix мог опросить метрики конкретного виртуального роутера, в поле Context name передается его имя (например, VRF-GUEST).

Отладка SNMPv3 в консоли

Если элемент данных в Zabbix перешел в состояние Not supported, отладку, как и в случае с v2c, нужно начинать с консоли сервера Zabbix. Утилиты snmpget и snmpwalk поддерживают третью версию, но синтаксис становится сложнее.

Пример запроса OID с уровнем authPriv: snmpget -v3 -l authPriv -u zabbix_user -a SHA -A "AuthPassword123" -x AES -X "PrivPassword123" 192.168.1.10 1.3.6.1.2.1.1.3.0

Разбор флагов:

  • -v3 — версия протокола.
  • -l authPriv — уровень безопасности (Security Level).
  • -u — Security Name (пользователь).
  • -a и -A — алгоритм и пароль аутентификации.
  • -x и -X — алгоритм и пароль шифрования.

Если консольная утилита возвращает данные, а Zabbix — нет, проверьте, совпадают ли выбранные радиокнопки алгоритмов (SHA/AES) в настройках элемента данных с теми, что настроены на устройстве, и убедитесь, что макросы на уровне узла сети заполнены без лишних пробелов.

Создание десятков элементов данных вручную, даже с использованием макросов, — процесс долгий. В следующей главе мы перейдем к мощнейшему инструменту Zabbix, который позволяет автоматизировать создание метрик на основе SNMP-таблиц — низкоуровневому обнаружению (LLD).

Принципы низкоуровневого обнаружения (LLD)

Принципы низкоуровневого обнаружения (LLD)

Представьте коммутатор на 48 портов. Чтобы полноценно за ним следить, нужно собирать входящий трафик, исходящий трафик, статус линка и количество ошибок на каждом порту. Это 48×4=19248 \times 4 = 192 элемента данных. Если это стек из четырех таких коммутаторов — 768768 элементов. Создавать их вручную, даже копированием, — это часы монотонной работы. А если через месяц сетевой инженер добавит в стек еще один коммутатор, мониторинг этого не заметит, пока вы снова не вмешаетесь руками.

Чтобы автоматизировать этот процесс внутри самого шаблона, в Zabbix существует механизм низкоуровневого обнаружения — LLD (Low-Level Discovery). Это встроенный алгоритм, который сам опрашивает устройство, выясняет, сколько у него портов, дисков или процессоров, и динамически создает для них метрики и триггеры.

Конвейер LLD: от сырых данных к мониторингу

LLD работает не как единая монолитная команда, а как сборочный конвейер. Чтобы шаблон мог динамически подстраиваться под любое устройство, процесс разбит на четыре этапа.

  1. Правило обнаружения (Discovery rule). Это инструкция, которая говорит Zabbix, куда пойти и что спросить. Она может использовать SNMP (запросить таблицу интерфейсов), скрипт, SQL-запрос или Zabbix-агента. Цель правила — получить сырой список сущностей.
  2. LLD JSON. Zabbix берет сырые данные от устройства и конвертирует их в строго стандартизированный формат JSON. Это универсальный язык обнаружения.
  3. LLD-макросы. Из полученного JSON система извлекает переменные (например, имена портов или их индексы) и присваивает их специальным макросам.
  4. Прототипы (Prototypes). Это «чертежи» будущих элементов данных, триггеров и графиков. В них вместо жестко заданных OID или имен вписаны LLD-макросы. Zabbix берет прототип, прогоняет через него каждый набор переменных из JSON и штампует готовые сущности.

Универсальный язык: формат LLD JSON

Главный принцип LLD: ядру Zabbix абсолютно неважно, каким способом вы собираете данные. Вы можете использовать snmpwalk, написать скрипт на Python или сделать HTTP-запрос к API маршрутизатора.

Единственное жесткое требование — на выходе Правило обнаружения должно отдать Zabbix массив объектов в формате JSON, где ключами выступают LLD-макросы.

[
  {
    "{#IFNAME}": "GigabitEthernet0/1",
    "{#SNMPINDEX}": "1"
  },
  {
    "{#IFNAME}": "GigabitEthernet0/2",
    "{#SNMPINDEX}": "2"
  }
]

В этом примере JSON содержит информацию о двух сетевых интерфейсах. Для каждого интерфейса определены две переменные. Обратите внимание на синтаксис ключей: они начинаются с решетки {#...}.

Это LLD-макросы. В отличие от пользовательских макросов {$MACRO}, которые мы разбирали ранее и которые задаются администратором статично, LLD-макросы {#MACRO} существуют только внутри конкретного правила обнаружения и получают свои значения динамически из JSON в момент опроса.

Прототипы: чертежи с переменными

Получив JSON, Zabbix переходит к Прототипам элементов данных (Item prototypes). Прототип выглядит точно так же, как обычный элемент данных, но в его полях используются LLD-макросы.

Допустим, мы создаем прототип для сбора входящего трафика по SNMP. В поле Name мы пишем: Traffic In on {#IFNAME}. В поле SNMP OID мы пишем: .1.3.6.1.2.1.2.2.1.10.{#SNMPINDEX}.

Когда Zabbix обрабатывает первый блок из нашего JSON, он подставляет значения и создает реальный элемент данных:

  • Имя: Traffic In on GigabitEthernet0/1
  • OID: .1.3.6.1.2.1.2.2.1.10.1

Затем он берет второй блок из JSON и создает следующий элемент:

  • Имя: Traffic In on GigabitEthernet0/2
  • OID: .1.3.6.1.2.1.2.2.1.10.2

Если при следующем опросе коммутатора правило обнаружения вернет JSON с пятью интерфейсами, Zabbix автоматически создаст недостающие три элемента данных. Если какой-то интерфейс исчезнет из JSON (например, сетевую карту физически вытащили из сервера), Zabbix пометит созданные для нее элементы как устаревшие и удалит их через заданное время (по умолчанию — 30 дней).

Связка LLD и контекстных макросов

Настоящая мощь профессиональных шаблонов раскрывается, когда мы объединяем динамику LLD с гибкостью контекстных пользовательских макросов.

Вспомните механизм контекстных макросов: мы можем задать глобальный порог {$IF.ERRORS.MAX} = 10, а для конкретного важного аплинка переопределить его через контекст: {$IF.ERRORS.MAX:"GigabitEthernet0/1"} = 100.

Но как применить это в прототипе триггера, если мы заранее не знаем имена интерфейсов? Мы используем LLD-макрос прямо внутри контекста пользовательского макроса.

В прототипе триггера это выглядит так: last(/Template Network/net.if.errors[{#SNMPINDEX}]) > {$IF.ERRORS.MAX:"{#IFNAME}"}

Как это разворачивается на практике:

  1. LLD находит порт GigabitEthernet0/1.
  2. Zabbix подставляет {#IFNAME} в триггер.
  3. Выражение превращается в ... > {$IF.ERRORS.MAX:"GigabitEthernet0/1"}.
  4. Zabbix проверяет, задал ли администратор макрос с таким контекстом на уровне узла сети. Если да — использует его значение (100). Если нет — срабатывает фоллбэк, и используется базовый макрос {$IF.ERRORS.MAX} (10).

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

Создание LLD-правила для сетевых интерфейсов по SNMP

Создание LLD-правила для сетевых интерфейсов по SNMP

Ядро Zabbix ожидает от любого правила обнаружения строго определенный формат данных — массив JSON. Но сетевой коммутатор не умеет отдавать JSON. Он отвечает на запросы SNMP, отдавая сырые строки и числа, привязанные к OID. Чтобы автоматизация сработала, нам нужен встроенный переводчик, который на лету превратит столбцы SNMP-таблицы в структурированный JSON с LLD-макросами.

В Zabbix эту роль выполняет специальная директива discovery[].

Синтаксис директивы discovery

Когда мы создаем обычный элемент данных SNMP, в поле SNMP OID мы пишем конкретный числовой адрес, например 1.3.6.1.2.1.2.2.1.2.1 (имя первого интерфейса).

Когда мы создаем правило низкоуровневого обнаружения (Discovery rule) с типом SNMP agent, в поле SNMP OID мы используем специальную конструкцию:

discovery[{#МАКРОС1}, OID_СТОЛБЦА_1, {#МАКРОС2}, OID_СТОЛБЦА_2, ...]

Эта команда говорит серверу Zabbix: «Сделай SNMP-запрос GetNext (аналог snmpwalk) по указанным базовым OID. Пройдись по всем строкам таблицы. Для каждой строки создай JSON-объект, где значение из первого OID будет присвоено {#МАКРОС1}, а из второго — {#МАКРОС2}».

Самая частая задача — обнаружить сетевые интерфейсы и получить их имена. Базовый OID для таблицы имен интерфейсов (ifDescr) — это 1.3.6.1.2.1.2.2.1.2.

Конструкция для обнаружения будет выглядеть так: discovery[{#IFNAME}, 1.3.6.1.2.1.2.2.1.2]

Магия неявного {#SNMPINDEX}

Внимательный взгляд заметит нестыковку. Мы запросили только имя интерфейса ({#IFNAME}). Но чтобы в дальнейшем опрашивать трафик или статус этого интерфейса, нам критически необходим его индекс (то самое число на конце OID, например .1 или .48). Без индекса мы не сможем собрать метрики.

В Zabbix есть жесткое правило: макрос {#SNMPINDEX} генерируется автоматически.

Вам не нужно указывать его в директиве discovery[]. Когда Zabbix обходит таблицу SNMP, он берет последнюю часть OID (индекс строки) и сам помещает ее в макрос {#SNMPINDEX} для каждого найденного объекта.

Настройка правила в интерфейсе

Чтобы создать правило, перейдите в ваш шаблон, откройте раздел Discovery rules и нажмите Create discovery rule.

Заполните ключевые поля:

  • Name: Network interfaces discovery
  • Type: SNMP agent
  • Key: net.if.discovery
  • SNMP OID: discovery[{#IFNAME}, 1.3.6.1.2.1.2.2.1.2]
  • Update interval: 1h (Обнаружение интерфейсов — тяжелая операция для сети и процессора коммутатора. Интерфейсы не появляются каждую минуту, поэтому опрашивать их чаще раза в час или даже нескольких часов бессмысленно).

Важно: Поле Key в правилах обнаружения SNMP не несет функциональной нагрузки. В отличие от Zabbix-агента, где ключ — это жестко заданная команда для ОС, здесь ключ — это просто уникальный идентификатор правила в базе данных Zabbix. Вы можете назвать его my.custom.discovery, и правило все равно отработает, так как реальный опрос идет по полю SNMP OID. Однако стандарт net.if.discovery является общепринятым.

Сбор нескольких параметров (Join по индексу)

Часто одного имени интерфейса недостаточно. Например, коммутатор отдает техническое имя GigabitEthernet0/1 в таблице ifDescr (1.3.6.1.2.1.2.2.1.2), но администратор также прописал понятное описание «Uplink to Core» в таблице ifAlias (1.3.6.1.2.1.31.1.1.1.18).

Мы хотим использовать оба значения: техническое имя для ключей, а описание — для красивого отображения на графиках. Zabbix позволяет собирать данные из нескольких SNMP-таблиц одновременно, объединяя их в один JSON-объект по совпадающему индексу.

Расширяем нашу директиву: discovery[{#IFNAME}, 1.3.6.1.2.1.2.2.1.2, {#IFALIAS}, 1.3.6.1.2.1.31.1.1.1.18]

Как это работает под капотом:

  1. Zabbix делает snmpwalk по ветке ifDescr. Находит индекс .1 со значением GigabitEthernet0/1.
  2. Zabbix делает snmpwalk по ветке ifAlias. Находит индекс .1 со значением Uplink to Core.
  3. Так как индексы совпадают, Zabbix склеивает их в один объект.

Проверка результата

Прежде чем переходить к созданию прототипов, правило нужно проверить. Если на этапе обнаружения допущена опечатка в OID, все последующие прототипы метрик и триггеров просто не создадутся.

В самом низу формы настройки Discovery rule нажмите кнопку Test. Укажите IP-адрес реального коммутатора и корректный SNMP Community (или учетные данные SNMPv3, если используете их). Нажмите Get value.

В поле результата вы должны увидеть валидный JSON:

[
  {
    "{#SNMPINDEX}": "1",
    "{#IFNAME}": "GigabitEthernet0/1",
    "{#IFALIAS}": "Uplink to Core"
  },
  {
    "{#SNMPINDEX}": "2",
    "{#IFNAME}": "GigabitEthernet0/2",
    "{#IFALIAS}": "Server Rack A"
  }
]

Если вы видите такой массив — мост между миром SNMP и миром автоматизации Zabbix успешно построен. Правило отработало, динамические переменные заполнены данными с реального железа. Теперь этот массив можно передавать дальше по конвейеру — в прототипы элементов данных.

Прототипы элементов данных, триггеров и графиков

Прототипы элементов данных, триггеров и графиков

В прошлой главе мы настроили правило обнаружения, которое опросило коммутатор и вернуло массив JSON. В этом массиве лежат пары макросов: {#IFNAME} со значением имени порта и {#SNMPINDEX} с его порядковым номером. Но сам по себе этот JSON ничего не мониторит. Ядро Zabbix просто держит его в памяти. Чтобы превратить этот сырой список в сотни реально собираемых метрик, нам нужны чертежи — прототипы.

Прототип — это шаблон внутри шаблона. Это заготовка, в которой вместо конкретных имен, ключей и OID расставлены LLD-макросы. Когда Zabbix получает JSON от правила обнаружения, он прогоняет каждый объект из массива через этот чертеж, генерируя готовые сущности.

Прототипы элементов данных (Item prototypes)

Создание прототипа элемента данных почти не отличается от создания обычного Item, за исключением одного правила: имя, ключ и OID должны быть уникальными для каждого сгенерированного элемента. Если Zabbix попытается создать две метрики с одинаковым ключом, процесс обнаружения завершится с ошибкой.

Чтобы обеспечить уникальность, мы встраиваем LLD-макросы прямо в настройки прототипа.

Рассмотрим создание прототипа для сбора входящего трафика (ifInOctets). Базовый OID этой метрики в дереве SNMP — 1.3.6.1.2.1.2.2.1.10.

  1. Name (Имя): Делаем его понятным для человека. Пишем Interface {#IFNAME}: Incoming traffic. При генерации Zabbix заменит макрос, и в интерфейсе мы увидим красивые названия вроде Interface GigabitEthernet0/1: Incoming traffic.
  2. Key (Ключ): Ключ обязан быть уникальным в пределах узла сети. Традиционно параметры передаются в квадратных скобках. Пишем net.if.in[{#IFNAME}].
  3. SNMP OID: Это самое важное поле. Мы берем базовый OID таблицы и через точку добавляем к нему макрос индекса. Пишем 1.3.6.1.2.1.2.2.1.10.{#SNMPINDEX}.

Когда процесс обнаружения запустится, Zabbix возьмет первый элемент из JSON (например, порт с индексом 1 и именем Gi0/1) и создаст реальный элемент данных. Затем возьмет второй — и создаст следующий. Для 48-портового коммутатора один прототип за секунду развернется в 48 работающих метрик.

Прототипы триггеров (Trigger prototypes)

Собирать метрики недостаточно — нужно автоматически создавать логику реагирования на аварии. Прототипы триггеров работают по тому же принципу: они размножаются для каждого найденного объекта.

Главная сложность в прототипах триггеров — правильно сослаться на сгенерированный элемент данных и задать гибкий порог срабатывания.

Допустим, мы создали прототип метрики ошибок на порту с ключом net.if.errors[{#IFNAME}]. Теперь мы хотим создать триггер, который сработает, если количество ошибок превысит норму.

Имя триггера также должно содержать макрос, чтобы в панели проблем было понятно, где именно произошла авария: High error rate on interface {#IFNAME}

Выражение (Expression) строится с использованием ключа прототипа. Но самое мощное применение LLD в триггерах — это комбинация LLD-макросов с контекстными пользовательскими макросами, которые мы разбирали ранее.

Вместо того чтобы жестко указывать порог (например, >100> 100), мы передаем имя интерфейса в качестве контекста для макроса:

last(/Template Network/net.if.errors[{#IFNAME}]) > {$IF.ERRORS.MAX:"{#IFNAME}"}

Как это работает на практике?

  1. Zabbix генерирует триггер для порта FastEthernet0/1.
  2. Выражение превращается в last(...) > {$IF.ERRORS.MAX:"FastEthernet0/1"}.
  3. Zabbix ищет макрос с точным контекстом FastEthernet0/1. Если не находит — ищет по регулярному выражению (например, для всех Fast-портов). Если и его нет — использует базовый макрос {$IF.ERRORS.MAX}.

Это позволяет вам иметь один прототип триггера на весь шаблон, но при этом устанавливать разные пороги срабатывания для аплинков, пользовательских портов и служебных интерфейсов, просто управляя макросами на уровне узла сети.

Прототипы графиков (Graph prototypes)

Анализировать сырые числа трафика для десятков портов неудобно. Zabbix умеет автоматически рисовать графики для каждого обнаруженного интерфейса.

В разделе Graph prototypes мы создаем новый чертеж:

  1. Задаем имя: Traffic on interface {#IFNAME}.
  2. В блок Items (Элементы графика) добавляем наши прототипы элементов данных: входящий трафик (net.if.in[{#IFNAME}]) и исходящий трафик (net.if.out[{#IFNAME}]).

В результате для каждого порта будет создан свой индивидуальный график, где входящий и исходящий трафик отрисовываются вместе.

Жизненный цикл сгенерированных сущностей

Что произойдет, если физический порт на коммутаторе сгорит, и администратор удалит его из конфигурации устройства?

При следующем опросе LLD правило обнаружения вернет новый JSON, в котором этого порта уже не будет. Zabbix сравнит новый JSON со списком уже созданных элементов. Обнаружив, что порт исчез, Zabbix пометит все сгенерированные для него элементы данных, триггеры и графики как «Утерянные» (Lost).

По умолчанию Zabbix не удаляет их мгновенно, чтобы не потерять исторические данные из-за кратковременного сетевого сбоя. Они будут храниться количество дней, указанное в настройке правила обнаружения Keep lost resources period (обычно 30 дней), после чего Zabbix автоматически очистит базу данных от неактуальных метрик.

Фильтрация и предобработка в правилах обнаружения

Фильтрация и предобработка в правилах обнаружения

В предыдущей главе мы настроили автоматическую генерацию элементов данных и триггеров для сетевых интерфейсов. Если вы примените этот шаблон к реальному 48-портовому коммутатору, то ожидаете увидеть около 50 интерфейсов. Но Zabbix создаст 150 или даже 200.

Откуда берется этот мусор? Сетевое устройство отдает по SNMP не только физические порты, но и программные интерфейсы (Loopback, Null0), виртуальные сети (VLAN), а также порты, которые административно выключены и никуда не подключены. Мониторинг этих сущностей впустую расходует ресурсы базы данных Zabbix и генерирует ложные срабатывания триггеров. Нам нужно научить шаблон отличать полезные данные от информационного шума.

Расширение запроса для фильтрации

Чтобы отфильтровать интерфейс, Zabbix должен знать о нем какой-то отличительный признак. Прямо сейчас наше правило обнаружения собирает только имена портов: discovery[{#IFNAME}, 1.3.6.1.2.1.2.2.1.2]. Имя Vlan1 или Loopback0 можно отфильтровать по тексту, но это ненадежно — на оборудовании разных вендоров они называются по-разному.

Гораздо надежнее использовать стандартизированные метрики SNMP:

  • Тип интерфейса (ifType, OID 1.3.6.1.2.1.2.2.1.3). Например, физический Ethernet имеет тип 6, а программный Loopback — 24.
  • Статус порта (ifAdminStatus, OID 1.3.6.1.2.1.2.2.1.7). Значение 1 означает, что порт включен администратором, 2 — выключен (shutdown).

Чтобы использовать эти данные в фильтре, мы должны добавить их в наш LLD JSON. Расширим OID правила обнаружения:

discovery[{#IFNAME}, 1.3.6.1.2.1.2.2.1.2, {#IFTYPE}, 1.3.6.1.2.1.2.2.1.3, {#IFADMINSTATUS}, 1.3.6.1.2.1.2.2.1.7]

Теперь для каждого найденного интерфейса Zabbix сформирует JSON-объект с тремя макросами, которые мы можем использовать для принятия решений.

Настройка фильтра LLD

Фильтр — это строгий контрольно-пропускной пункт. Если объект из JSON-массива не проходит условия фильтра, Zabbix полностью игнорирует его: прототипы для него не создаются.

В настройках правила обнаружения на вкладке Filters мы задаем условия. Каждое условие состоит из макроса, оператора и регулярного выражения.

Настроим отсев выключенных портов и программных заглушек:

  1. Условие A: {#IFADMINSTATUS} matches ^1$ (пропускаем только те порты, где статус строго равен 1).
  2. Условие B: {#IFTYPE} does not match ^24$ (отбрасываем порты, тип которых равен 24).

По умолчанию Zabbix применяет логику AND (И) ко всем условиям. Интерфейс будет принят для мониторинга только в том случае, если он включен администратором И не является Loopback-интерфейсом. Если логика сложнее, можно выбрать тип вычисления Custom expression и написать формулу вручную, например: (A and B) or C.

Переопределения (Overrides): профессиональная гибкость

Фильтр работает в бинарной логике: «создать всё» или «не создавать ничего». Но в профессиональных шаблонах часто требуется более тонкая настройка.

Представьте задачу: мы хотим мониторить все активные порты коммутатора. Но магистральные порты (Uplink) критически важны — их нужно опрашивать каждые 30 секунд, а обычные пользовательские порты (Access) достаточно опрашивать раз в 5 минут.

Использовать фильтр здесь нельзя — нам нужны обе группы портов. Создавать два отдельных правила обнаружения — значит дублировать нагрузку на сеть. Здесь на помощь приходят Переопределения (Overrides).

Переопределение позволяет изменить параметры прототипа (интервал опроса, теги, статус триггера) на лету, прямо в момент создания элемента, если объект соответствует определенному условию.

Как настроить Override

На вкладке Overrides в правиле обнаружения мы создаем новое правило:

  1. Имя: Uplink ports fast polling.
  2. Условие (Filters): {#IFNAME} matches Trunk|Uplink|TenGigabit. (Если имя порта содержит эти слова).
  3. Операция (Operations): Добавляем операцию для Item prototype. Выбираем наш прототип трафика и задаем действие: Update interval = 30s.

Как это сработает: Zabbix берет очередной порт из LLD JSON. Порт проходит основной фильтр (он включен и это не Loopback). Zabbix собирается создать для него метрику с дефолтным интервалом из прототипа (5 минут). Но перед созданием он проверяет Overrides. Если имя порта TenGigabitEthernet0/1, срабатывает переопределение, и элемент данных создается с интервалом 30 секунд. Если это FastEthernet0/5, переопределение игнорируется, и применяется дефолтный интервал 5 минут.

С помощью Overrides можно делать невероятно гибкие вещи:

  • Отключать генерацию конкретных триггеров для определенных портов (например, не алертить о падении линка на пользовательских портах).
  • Назначать разные теги (добавить тег role: uplink для важных портов).
  • Изменять время хранения истории (хранить метрики магистралей год, а обычных — неделю).

Предобработка LLD (LLD Preprocessing)

Иногда устройство отдает по SNMP данные в таком виде, который невозможно сразу использовать ни в фильтрах, ни в прототипах.

Например, вы опрашиваете таблицу датчиков температуры, а устройство возвращает JSON, в котором имена датчиков написаны в нижнем регистре с пробелами, а вам для красивых графиков нужны имена с заглавной буквы. Или устройство возвращает огромный массив данных, из которого вам нужна только половина.

Для этого существует LLD Preprocessing (Предобработка обнаружения). В отличие от предобработки элементов данных (которая меняет значение конкретной метрики), LLD Preprocessing меняет сам массив обнаружения до того, как он попадет в фильтр и макросы.

Здесь можно использовать регулярные выражения, JSONPath или даже писать скрипты на JavaScript, чтобы пересобрать структуру данных. Инструменты предобработки — это обширная тема, требующая отдельного погружения, поэтому детальный разбор регулярных выражений и JSONPath мы проведем в следующих главах, когда перейдем к продвинутой обработке метрик.

Предобработка метрик: регулярные выражения и JSONPath

Предобработка метрик: регулярные выражения и JSONPath

Сетевые устройства и приложения редко отдают данные в том идеальном виде, который нужен Zabbix для построения графиков. Вы запрашиваете температуру, а устройство отвечает строкой Temperature: 45.5 C (Normal). Вы обращаетесь к современному API, а в ответ прилетает «простыня» JSON на 500 строк, где нужная метрика спрятана на пятом уровне вложенности.

Если попытаться сохранить строку с текстом в элемент данных с типом Numeric, Zabbix переведет его в состояние Not supported. Чтобы этого избежать, сырые данные нужно очистить и трансформировать «на лету». За это отвечает механизм предобработки (Preprocessing).

Конвейер предобработки

Предобработка в Zabbix работает как сборочный конвейер. Вы можете назначить элементу данных не один, а сразу несколько шагов.

Главное правило конвейера: результат выполнения предыдущего шага становится входными данными для следующего.

Если на входе у вас огромный JSON, на первом шаге вы можете извлечь из него конкретную текстовую строку, на втором — вырезать из этой строки только цифры, а на третьем — умножить их на 1000, чтобы перевести килобайты в байты. В базу данных попадет только финальный результат.

Два самых мощных и часто используемых инструмента на этом конвейере — регулярные выражения и JSONPath.

Регулярные выражения: извлекаем суть из хаоса

Шаг предобработки Regular expression используется, когда метрика приходит в виде неструктурированного текста, из которого нужно вычленить полезную нагрузку.

В Zabbix этот шаг требует заполнения двух полей:

  1. Pattern (Шаблон) — само регулярное выражение, которое описывает, что мы ищем.
  2. Output (Вывод) — то, что мы хотим получить на выходе.

Ключевая концепция здесь — группы захвата (Capturing groups). В регулярных выражениях часть шаблона, взятая в круглые скобки (), сохраняется в памяти. К ней можно обратиться в поле Output, используя синтаксис \1 для первой скобки, \2 для второй и так далее.

Пример: очистка текстового вывода

Допустим, старый ИБП по SNMP отдает статус батареи в виде строки: Battery capacity is at 85 percent

Нам нужно число 85.

  • Pattern: ([0-9]+) percent
  • Output: \1

Как это работает: Zabbix ищет в строке последовательность цифр [0-9]+, за которой следует пробел и слово percent. Поскольку цифры обернуты в круглые скобки, они попадают в первую группу захвата. В поле Output мы указываем \1, и Zabbix отбрасывает весь остальной текст, передавая дальше по конвейеру только 85.

Важно: Всегда настраивайте обработку ошибок (Custom on fail) для шагов предобработки. Если прошивка ИБП обновится и он начнет отвечать Capacity: 85%, регулярное выражение сломается. В настройках шага можно указать: если шаблон не совпал, отбросить значение (Discard value) или задать дефолтное, чтобы элемент данных не ушел в Not supported.

JSONPath: навигация по структурированным данным

Если регулярные выражения — это скальпель для текста, то JSONPath — это GPS-навигатор для JSON. Сегодня всё больше устройств (особенно при использовании HTTP agent или внешних скриптов) отдают метрики в формате JSON.

Шаг предобработки JSONPath позволяет извлечь конкретное значение из сложной структуры, не прибегая к написанию скриптов.

Базовая навигация

Синтаксис JSONPath всегда начинается с символа $ (корень документа). Допустим, у нас есть ответ от API:

{
  "system": {
    "hostname": "srv-db-01",
    "uptime": 3600
  }
}

Чтобы получить время работы, в шаге JSONPath достаточно указать путь через точку: $.system.uptime. На выходе конвейер получит число 3600.

Фильтрация массивов (самое полезное для Zabbix)

Часто API возвращает массив однотипных объектов, например, список дисков или сетевых интерфейсов.

{
  "disks": [
    {"name": "sda", "capacity": 500, "used": 100},
    {"name": "sdb", "capacity": 1000, "used": 800}
  ]
}

Если нам нужно получить занятое место (used) конкретно для диска sdb, мы не можем написать $.disks[1].used, потому что порядок дисков в массиве может измениться после перезагрузки.

Здесь применяется синтаксис фильтрации: [?(@.ключ == 'значение')]. Символ @ означает «текущий элемент массива».

Правильный JSONPath для нашей задачи: $.disks[?(@.name == 'sdb')].used

Zabbix просмотрит массив disks, найдет объект, у которого ключ name равен sdb, и извлечет из него значение used (800).

Комбинирование шагов

Настоящая мощь предобработки раскрывается при комбинировании инструментов. Представьте, что API возвращает JSON, но значения внутри него «грязные»:

{
  "sensor_data": [
    {"location": "server_room", "temp": "Temp: 22.5C"}
  ]
}

Чтобы получить чистое число для графика, мы выстраиваем конвейер из двух шагов:

  1. Шаг 1: JSONPath. Параметр: $.sensor_data[?(@.location == 'server_room')].temp Результат после первого шага: строка "Temp: 22.5C"
  2. Шаг 2: Regular expression. Pattern: ([0-9.]+) Output: \1 Результат после второго шага: число 22.5

В базу данных Zabbix запишется идеальное числовое значение, готовое к срабатыванию триггеров и отрисовке на дашбордах.

Регулярные выражения и JSONPath покрывают 90% задач по очистке метрик. Однако иногда данные требуют не просто извлечения, а математической логики, сложных условий или преобразования форматов (например, конвертации шестнадцатеричной строки в десятичное число). Для таких случаев в Zabbix предусмотрен шаг предобработки, позволяющий писать полноценный программный код, который мы рассмотрим далее.

Использование JavaScript для сложной предобработки данных

Использование JavaScript для сложной предобработки данных

В предыдущей главе мы построили конвейер предобработки, используя регулярные выражения и JSONPath. Они отлично справляются с извлечением нужного фрагмента из текста или структуры. Но что делать, если данные нужно не просто извлечь, а вычислить, преобразовать или полностью перестроить?

Например, устройство отдает температуру в Фаренгейтах: Temp: 75F. Регулярное выражение легко достанет число 75. Но чтобы перевести его в градусы Цельсия, нужна математика: Tc=(Tf32)×59T_c = (T_f - 32) \times \frac{5}{9}, где TcT_c — искомая температура в градусах Цельсия, а TfT_f — исходная температура в Фаренгейтах. Например, при Tf=75T_f = 75 мы получим (7532)×5923.89(75 - 32) \times \frac{5}{9} \approx 23.89 °C. Ни RegEx, ни JSONPath не умеют считать. Для таких задач в Zabbix встроен полноценный интерпретатор JavaScript.

Среда выполнения: что может и чего не может Zabbix JS

В Zabbix интегрирован легковесный движок Duktape. Это означает, что вы пишете код на стандартном ECMAScript (JavaScript), но среда его выполнения кардинально отличается от браузера или Node.js.

Главное правило: JavaScript в Zabbix полностью изолирован.

  • Здесь нет объекта window или document.
  • Вам недоступны стандартные браузерные fetch или XMLHttpRequest (однако Zabbix предоставляет собственный объект HttpRequest для внешних сетевых запросов).
  • Вы не можете работать с файловой системой или таймерами (setTimeout).
  • Скрипт жестко ограничен по времени выполнения (обычно 10 секунд) и потребляемой памяти.

Единственная задача этого скрипта — получить на вход сырую строку, произвести над ней синхронные вычисления в оперативной памяти и вернуть новую строку.

Переменная value и возврат результата

Когда метрика попадает на шаг предобработки JavaScript, Zabbix автоматически помещает входящие данные в глобальную переменную с именем value. Независимо от того, что прислало устройство (число, JSON, бинарный код), в переменной value это всегда будет строка (String).

Ваша задача — написать тело функции, которая обработает эту строку и завершится оператором return.

Простейший пример перевода Фаренгейтов в Цельсии:

// value содержит строку "75" (предположим, мы уже отрезали "Temp: " и "F" предыдущими шагами)
var fahrenheit = Number(value);
var celsius = (fahrenheit - 32) * 5 / 9;
return celsius.toFixed(2); // Возвращаем строку "23.89"

Важно: Zabbix ожидает, что скрипт вернет строку или число (которое будет приведено к строке). Если вы попытаетесь вернуть сложный объект, Zabbix запишет в базу бесполезное [object Object].

Практика 1: Парсинг сложных форматов

Представим, что мы опрашиваем нестандартный ИБП, который отдает время своей работы (Uptime) в виде человекочитаемой строки: Uptime: 12d 04h 30m. Zabbix для корректного построения графиков и работы триггеров требует хранить Uptime строго в секундах.

Решить это одним регулярным выражением невозможно. Зато JavaScript справляется с этим в несколько строк:

// Входящая строка: "Uptime: 12d 04h 30m"
// Шаг 1: Убираем лишний текст
var cleanStr = value.replace("Uptime: ", ""); // "12d 04h 30m"

// Шаг 2: Извлекаем числа с помощью RegEx внутри JS
var days = cleanStr.match(/(\d+)d/);
var hours = cleanStr.match(/(\d+)h/);
var mins = cleanStr.match(/(\d+)m/);

// Шаг 3: Преобразуем найденное в числа (или 0, если совпадений нет)
var d = days ? Number(days[1]) : 0;
var h = hours ? Number(hours[1]) : 0;
var m = mins ? Number(mins[1]) : 0;

// Шаг 4: Вычисляем секунды
var totalSeconds = (d * 86400) + (h * 3600) + (m * 60);

return totalSeconds;

Практика 2: Перестройка JSON для низкоуровневого обнаружения (LLD)

Это самая частая и мощная причина использовать JavaScript в профессиональных шаблонах. Как мы помним, правило LLD жестко требует на вход массив объектов, где ключами выступают LLD-макросы: [{"{#MACRO}": "value"}].

Но сторонние API или нестандартные скрипты часто возвращают данные в виде словаря (объекта), где ключами являются имена интерфейсов или дисков. Например:

{
  "eth0": { "status": "up", "speed": 1000 },
  "eth1": { "status": "down", "speed": 100 }
}

Если скормить это напрямую в LLD, Zabbix выдаст ошибку, так как это объект {}, а не массив []. JSONPath здесь бессилен — он может фильтровать массивы, но не может превратить ключи объекта в значения макросов.

Используем шаг JavaScript, чтобы перестроить структуру:

// 1. Парсим входящую строку в JS-объект
var input = JSON.parse(value);
var lldArray = [];

// 2. Проходим по всем ключам объекта (eth0, eth1)
Object.keys(input).forEach(function(interfaceName) {
    // 3. Формируем объект в формате Zabbix LLD
    lldArray.push({
        "{#IFNAME}": interfaceName,
        "{#STATUS}": input[interfaceName].status,
        "{#SPEED}": input[interfaceName].speed
    });
});

// 4. Превращаем готовый массив обратно в строку и возвращаем
return JSON.stringify(lldArray);

На выходе Zabbix получит идеальный LLD JSON:

[
  { "{#IFNAME}": "eth0", "{#STATUS}": "up", "{#SPEED}": 1000 },
  { "{#IFNAME}": "eth1", "{#STATUS}": "down", "{#SPEED}": 100 }
]

Обработка ошибок: конструкция Try / Catch

Когда вы внедряете шаблон у клиента, вы не можете гарантировать, что устройство всегда будет присылать данные в идеальном формате. Если прошивка обновится и устройство пришлет Uptime: unknown, наш скрипт вычисления секунд может выдать NaN (Not a Number) или упасть с ошибкой выполнения.

Чтобы элемент данных перешел в состояние Not supported с понятным текстом ошибки, а не с системным трейсом движка Duktape, всегда оборачивайте сложную логику в try...catch:

try {
    var data = JSON.parse(value);

    if (typeof data.temperature === 'undefined') {
        throw "Ключ temperature отсутствует в ответе устройства";
    }

    return data.temperature;
} catch (error) {
    // Эта ошибка отобразится в интерфейсе Zabbix в колонке Info
    throw "Ошибка обработки JS: " + error;
}

Использование JavaScript дает абсолютную свободу в обработке данных. Однако помните о производительности: запуск JS-движка требует больше ресурсов процессора сервера, чем встроенный шаг регулярного выражения или множитель (Custom multiplier). Применяйте JS тогда, когда логика ветвления (if/else), математика или перестройка структур данных неизбежны.

В следующей главе мы разберем, как встроенными средствами Zabbix обрабатывать ситуации, когда метрика временно пропадает или не меняется, чтобы не перегружать базу данных лишней информацией.

Валидация данных и обработка ошибок (Discard unchanged)

Валидация данных и обработка ошибок (Discard unchanged)

Представьте, что вы настроили идеальный JavaScript-парсер для снятия температуры с ядра маршрутизатора. Он работает месяцами, но однажды при перезагрузке устройство вместо числа отдает строку sensor_init. Скрипт падает с ошибкой, метрика переходит в состояние Not supported, а вы получаете алерт о сломанном мониторинге. Или другая крайность: вы опрашиваете серийный номер устройства каждые 5 минут. За год Zabbix сохранит в базу данных более 100 000 одинаковых строк для одного узла.

Встроенные шаги валидации и троттлинга (throttling) решают обе эти проблемы на уровне конвейера предобработки, до того как данные попадут в базу или вычислятся триггеры.

Валидация: отсечение невозможных значений

Даже если протокол или скрипт отработали корректно, само полученное значение может быть логическим мусором. Аппаратные датчики при сбоях часто выдают экстремальные значения (например, -999 или 65535). Если такое значение попадет в базу, оно испортит графики, исказит агрегацию и вызовет ложное срабатывание триггера.

Для защиты метрики используются шаги валидации:

  1. In range — проверяет, попадает ли число в заданный диапазон. Например, для загрузки процессора разумно указать диапазон 0x1000 \leq x \leq 100.
  2. Matches regular expression — проверяет текстовые данные на соответствие формату. Если вы ждете MAC-адрес, регулярное выражение убедится, что пришла именно шестнадцатеричная строка нужной длины, а не сообщение об ошибке от демона.
  3. Check for error in JSON / XML — ищет стандартные паттерны ошибок внутри структурированных данных до их парсинга.

Валидация в предобработке концептуально отличается от триггеров. Триггер говорит: «Данные верны, но ситуация критическая (температура 90)». Валидация говорит: «Данные невозможны, мы отказываемся их принимать (температура 5000)».

Custom on fail: управление поведением при ошибке

По умолчанию, если любой шаг предобработки завершается неудачей (скрипт упал, регулярное выражение не нашло совпадений, число вышло за пределы In range), весь элемент данных переходит в красное состояние Not supported. Сбор останавливается до следующего интервала.

Чтобы взять этот процесс под контроль, в Zabbix существует механизм Custom on fail (Пользовательская обработка ошибок). Установив эту галочку напротив шага предобработки, вы можете выбрать один из трех сценариев:

  • Discard value (Отбросить значение). Zabbix сделает вид, что опроса не было. Данные не запишутся в БД, триггеры не пересчитаются, метрика останется зеленой (Supported). Это идеальный выбор для игнорирования редких аппаратных глитчей.
  • Set value to (Установить значение). Заменяет ошибочный результат на жестко заданное дефолтное значение (например, 0 или -1). Полезно, если отсутствие данных по логике бизнеса означает ноль (например, скрипт не нашел ни одной активной сессии и вернул пустую строку).
  • Set error to (Установить текст ошибки). Метрика все равно перейдет в Not supported, но вместо системной ошибки (например, «ReferenceError in JavaScript») вы передадите понятный текст: «Сенсор вернул значение вне диапазона 0-100».

Throttling: защита базы данных от статики

Если валидация защищает от мусора, то Throttling (прореживание) защищает базу данных от избыточности.

Сетевые устройства имеют множество параметров, которые меняются крайне редко: версия прошивки, серийный номер, состояние физического линка (Up/Down), модель устройства. Опрашивать их раз в сутки опасно — если порт упадет, вы узнаете об этом только завтра. Опрашивать раз в минуту — значит записать в базу 1440 одинаковых значений Up за один день.

Шаг предобработки Discard unchanged (Отбрасывать неизменное) решает эту дилемму. Zabbix кэширует последнее полученное значение в оперативной памяти сервера. При следующем опросе он сравнивает новое значение с кэшем. Если они идентичны, Zabbix отбрасывает новое значение. В базу данных пишется только факт изменения.

У этого шага есть критический недостаток. Если метрика не меняется месяцами, в базе данных за этот период не будет ни одной записи. Триггеры, использующие функцию nodata() (отсутствие данных), решат, что мониторинг сломался, и поднимут ложную тревогу. Кроме того, на графиках появятся пустые разрывы.

Discard unchanged with heartbeat

Чтобы сохранить преимущества прореживания, но подтверждать жизнеспособность метрики, используется шаг Discard unchanged with heartbeat (Отбрасывать неизменное с сердцебиением).

Вы задаете интервал «сердцебиения» (например, 1h — один час). Логика работы становится следующей:

  1. Если значение изменилось — сохранить немедленно.
  2. Если значение не менялось, отбрасывать его.
  3. Но если с момента последней записи в БД прошел заданный интервал (1 час), принудительно сохранить текущее неизменное значение.

Это самый мощный инструмент оптимизации шаблонов. Для текстовых инвентарных данных (версия ПО) heartbeat обычно ставят 1d (сутки). Для бинарных статусов (Up/Down) — 1h или 30m. Это снижает нагрузку на базу данных в сотни раз, сохраняя при этом мгновенную реакцию на изменения (так как опрос устройства по-прежнему происходит, например, каждые 5 минут).

Сборка отказоустойчивого конвейера

Профессиональный подход к созданию элементов данных требует комбинирования этих шагов. Рассмотрим конвейер предобработки для нестабильного датчика температуры:

  1. Regular expression: Temperature: ([0-9]+) -> \1 (Извлекаем число. Если устройство вернуло sensor_error, регулярка упадет. Настраиваем Custom on fail -> Discard value. Мы просто пропустим этот цикл опроса).
  2. In range: 10 ... 80 (Защита от глитчей сенсора. Если придет 255, шаг упадет. Custom on fail -> Discard value).
  3. Discard unchanged with heartbeat: 1h (Температура в серверной может держаться на уровне 22 градусов часами. Нет смысла писать это каждую минуту. Пишем только при изменении, либо раз в час для графика).

Такой конвейер гарантирует, что в базу данных попадут только валидные, очищенные данные, а размер базы будет расти минимальными темпами.

Оптимизация производительности шаблонов и throttling

Оптимизация производительности шаблонов и throttling

Представьте ситуацию: вы написали идеальный шаблон для коммутатора ядра. В нём 500 элементов данных, настроены красивые графики, умные триггеры. Вы применяете этот шаблон к одному устройству — всё работает безупречно. Затем вы раскатываете его на 200 коммутаторов в сети клиента. Через пять минут очередь Zabbix (Zabbix queue) улетает в небеса, процессы поллеров загружены на 100%, а база данных начинает задыхаться от потока записи. Шаблон работает, но он убивает сервер мониторинга.

Профессиональная разработка шаблонов отличается от любительской именно тем, что учитывает «стоимость» каждой собираемой метрики. В этой главе мы разберем, как проектировать шаблоны, которые выдержат масштабирование на тысячи устройств.

Бюджет NVPS и умные интервалы

NVPS (New Values Per Second) — главная метрика производительности любого сервера Zabbix. Это количество новых значений, которые сервер должен опросить, обработать и записать в базу данных каждую секунду.

Формула расчета проста:

NVPS=NTNVPS = \frac{N}{T}

где NN — количество элементов данных, а TT — интервал опроса в секундах.

Если у вас 1000 метрик с интервалом опроса 60 секунд, они генерируют 16.6\approx 16.6 NVPS. Если вы бездумно поставите интервал 10 секунд для тех же метрик, нагрузка вырастет в шесть раз — до 100100 NVPS.

Первый шаг к оптимизации — отказ от дефолтного интервала «1 минута для всего». Разные данные имеют разную динамику:

  • 1–3 минуты: Загрузка CPU, утилизация сетевых каналов (то, что может быстро привести к аварии).
  • 5–15 минут: Температура, статус блоков питания, свободное место на дисках (меняется медленно).
  • 1–24 часа: Серийные номера, версии прошивок, инвентарные данные.

Пользовательские интервалы (Custom intervals)

Иногда метрику нужно опрашивать часто, но только в определенное время. Zabbix позволяет задавать расписание (Scheduling) вместо жесткого интервала.

Например, если вы мониторите нагрузку на офисные точки доступа Wi-Fi, нет смысла опрашивать их каждую минуту ночью в воскресенье. Вы можете задать интервал wd1-5h9-18 (рабочие дни с 1 по 5, с 09:00 до 18:00). В остальное время опрос производиться не будет, что сэкономит ресурсы поллеров.

Оптимизация сети: механизм SNMP GetBulk

При работе с SNMP узким местом часто становится не процессор сервера, а сетевые задержки (latency).

В классическом режиме (GetNext) Zabbix запрашивает таблицу маршрутизации устройства так:

  1. Сервер: «Дай мне первую строку».
  2. Устройство: «Вот первая строка».
  3. Сервер: «Дай мне вторую строку».
  4. Устройство: «Вот вторая строка».

Если в таблице 1000 строк, а пинг до устройства составляет 50 миллисекунд, полный опрос займет почти минуту только из-за ожидания ответов по сети. Чтобы решить эту проблему, в протоколах SNMPv2c и SNMPv3 был внедрен механизм GetBulk.

SNMP GetBulk — механизм, который позволяет серверу сказать: «Отправь мне следующие 50 записей начиная с этого OID одним пакетом». Это кардинально снижает количество сетевых запросов и время ожидания при обходе больших таблиц.

В Zabbix использование этого механизма регулируется галочкой «Use bulk requests» в настройках SNMP-интерфейса узла сети. В 99% случаев она должна быть включена. Исключение составляют только очень старые или нестандартные устройства, чьи SNMP-агенты падают при получении bulk-запроса (в таких случаях галочку снимают точечно для конкретного хоста).

Оптимизация поллеров: Зависимые элементы (Dependent items)

Самый мощный архитектурный прием при создании шаблонов — использование зависимых элементов данных. Это критически важно, когда вы собираете данные через API, скрипты или сложные SNMP-таблицы.

Представьте, что вы обращаетесь к REST API системы хранения данных. API возвращает огромный JSON-документ, в котором содержатся статусы 50 дисков. Если вы создадите 50 обычных элементов данных типа HTTP agent, Zabbix откроет 50 TCP-соединений, сделает 50 HTTP-запросов и заставит СХД 50 раз сгенерировать один и тот же тяжелый JSON.

Правильная архитектура строится иначе:

  1. Master item (Основной элемент): Делает один тяжелый запрос к API раз в минуту. Его тип информации обычно Text, так как он сохраняет весь сырой JSON целиком.
  2. Dependent items (Зависимые элементы): 50 элементов, которые не ходят в сеть. Они привязаны к Master item. Как только Master получает новый JSON, он передает его копию всем зависимым элементам.
  3. Предобработка: В каждом Dependent item настраивается шаг предобработки (например, JSONPath), который извлекает из большого JSON только одну нужную цифру (статус конкретного диска).

Такой подход переносит нагрузку с сети и внешнего устройства на внутреннюю память Zabbix-сервера, который парсит текст за доли миллисекунды.

Многоуровневый Throttling: собираем всё вместе

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

  1. Уровень сбора (Master Item + GetBulk). Мы минимизируем сетевые запросы. Вместо тысяч мелких вопросов мы задаем один крупный (через bulk или скачивая полный JSON).
  2. Уровень распределения (Dependent Items). Мы не дергаем поллеры Zabbix для каждого параметра. Зависимые элементы разбирают полученный массив данных внутри оперативной памяти сервера.
  3. Уровень валидации (In range / RegEx). Мы отбрасываем очевидный мусор (например, температуру -999) еще до того, как она дойдет до триггеров.
  4. Уровень прореживания (Discard unchanged with heartbeat). Это последний и самый важный рубеж защиты базы данных.

Даже если мы опрашиваем серийный номер коммутатора раз в час (что уже хорошо), он не меняется годами. Без прореживания Zabbix будет записывать одну и ту же строку в БД 24 раза в сутки. Применив шаг предобработки Discard unchanged with heartbeat (например, с тайм-аутом в 1 день), мы заставим Zabbix игнорировать дубликаты на лету. В базу данных пойдет только первая запись, а следующая — либо когда серийный номер реально изменится, либо через сутки (чтобы подтвердить, что метрика жива).

Шаблон, построенный по такой схеме, генерирует минимальный сетевой трафик, не забивает очередь поллеров и снижает нагрузку на запись в базу данных (I/O) в десятки раз. Именно такие шаблоны готовы к внедрению в крупных Enterprise-сетях. В следующих главах мы перейдем к автоматизации: как с помощью API массово раскатывать такие оптимизированные шаблоны на инфраструктуру клиента.

Введение в Zabbix API и авторизация

Введение в Zabbix API и авторизация

Вы разработали идеальный шаблон: настроили LLD, написали JavaScript-предобработку, оптимизировали интервалы опроса и выстроили иерархию Master/Dependent элементов. Теперь клиент просит внедрить этот мониторинг в 300 филиалах. Делать это через веб-интерфейс — значит обречь себя на дни монотонных кликов мышью и неизбежные человеческие ошибки. Чтобы масштабировать свою работу и стать настоящим профессионалом, нужно перестать использовать мышь и начать общаться с ядром Zabbix напрямую.

Для этого существует Zabbix API.

Язык общения: JSON-RPC 2.0

Многие современные веб-сервисы используют архитектуру REST, где для разных действий вы обращаетесь к разным URL (например, GET /templates, POST /hosts). Zabbix работает иначе. Весь его API построен на протоколе JSON-RPC 2.0.

Это означает два фундаментальных правила:

  1. Единая точка входа (Endpoint). Все без исключения запросы отправляются на один и тот же URL: http://<адрес-zabbix>/api_jsonrpc.php.
  2. Только POST-запросы. Даже если вы просто хотите прочитать данные (аналог GET в REST), вы всё равно отправляете HTTP POST-запрос, в теле которого лежит JSON-документ с описанием того, что вам нужно.

Любой запрос к Zabbix API состоит из пяти обязательных полей:

  • jsonrpc — всегда строка "2.0". Указывает версию протокола.
  • method — команда, которую вы хотите выполнить. Состоит из названия сущности и действия через точку (например, host.get, template.create, item.delete).
  • params — объект или массив с параметрами запроса. Здесь вы указываете, какие именно данные нужно найти, или передаете настройки для создания нового объекта.
  • id — произвольный идентификатор запроса (обычно целое число). Zabbix вернет это же число в ответе. Это критически важно при асинхронной отправке нескольких запросов, чтобы понять, к какому именно запросу пришел ответ.
  • auth — строка с ключом авторизации (или null, если метод не требует проверки прав).

Первый контакт: запрос без авторизации

В Zabbix API есть ровно один метод, который можно вызвать без авторизации — apiinfo.version. Он возвращает версию API, которая совпадает с версией самого Zabbix-сервера. Это идеальный способ проверить, что Endpoint доступен и правильно принимает JSON.

Сформируем тело запроса:

{
    "jsonrpc": "2.0",
    "method": "apiinfo.version",
    "params": [],
    "id": 1,
    "auth": null
}

Отправим его с помощью консольной утилиты curl. Обратите внимание, что мы явно указываем заголовок Content-Type: application/json.

curl -X POST http://192.168.1.100/zabbix/api_jsonrpc.php \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","method":"apiinfo.version","params":[],"id":1,"auth":null}'

Ответ Zabbix всегда содержит поле jsonrpc, тот же самый id, который мы отправили, и поле result с полезной нагрузкой:

{
    "jsonrpc": "2.0",
    "result": "6.4.12",
    "id": 1
}

Если бы мы допустили ошибку (например, опечатку в названии метода), вместо result вернулся бы объект error с кодом и описанием проблемы.

Авторизация: Сессии против API-токенов

Чтобы управлять шаблонами и узлами сети, системе нужно знать, кто вы, и есть ли у вас права администратора. Исторически в Zabbix использовался метод user.login. Скрипт отправлял логин и пароль, получал в ответ временный Session ID и подставлял его в поле auth каждого последующего запроса.

Этот подход имел серьезный недостаток: сессии истекали по таймауту, скриптам приходилось постоянно перелогиниваться, а в базе данных Zabbix скапливались тысячи «мертвых» сессий от автоматики, что замедляло работу системы.

Начиная с Zabbix 5.4, золотым стандартом для скриптов и интеграций стали API-токены (API Tokens).

API-токен — это длинная криптографическая строка, которая генерируется в веб-интерфейсе Zabbix (раздел Users -> API tokens). Он привязывается к конкретному пользователю, наследует все его права, но, в отличие от сессии, может быть бессрочным.

Главное техническое отличие при использовании API-токена заключается в способе его передачи. Согласно современным стандартам безопасности, токен передается не в теле JSON-запроса, а в HTTP-заголовке Authorization со схемой Bearer. Поле auth в самом JSON при этом остается пустым (null).

Выполнение авторизованного запроса

Предположим, мы сгенерировали API-токен в интерфейсе и получили строку 0424b3a4a15a81ca7404.... Проверим его работоспособность, запросив список групп узлов сети с помощью метода hostgroup.get.

Чтобы не получить в ответ огромную простыню данных, передадим в params ограничение limit: 1.

{
    "jsonrpc": "2.0",
    "method": "hostgroup.get",
    "params": {
        "limit": 1
    },
    "id": 2,
    "auth": null
}

Теперь отправим запрос, добавив заголовок Authorization:

curl -X POST http://192.168.1.100/zabbix/api_jsonrpc.php \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer 0424b3a4a15a81ca7404..." \
     -d '{"jsonrpc":"2.0","method":"hostgroup.get","params":{"limit":1},"id":2,"auth":null}'

Ответ сервера:

{
    "jsonrpc": "2.0",
    "result": [
        {
            "groupid": "1",
            "name": "Templates",
            "internal": "0",
            "uuid": "7df96b18c230490a9a0a9e2307226338"
        }
    ],
    "id": 2
}

Запрос успешен. Мы получили массив result, содержащий первый найденный объект группы узлов сети.

Теперь у нас есть универсальный ключ к ядру Zabbix и понимание того, как формировать запросы. Мы готовы полностью отказаться от веб-интерфейса и перейти к программному извлечению и созданию шаблонов.

Методы template.get и template.create

Методы template.get и template.create

У нас есть API-токен, и мы умеем отправлять авторизованные запросы к api_jsonrpc.php. Представьте типичную задачу интегратора: вы приходите в инфраструктуру клиента, где создано 50 разрозненных кастомных шаблонов. Вам нужно провести их аудит, стандартизировать имена и перенести на другой сервер. Делать это через веб-интерфейс — часы монотонной работы и неизбежные ошибки.

Через API эта задача решается скриптом за несколько секунд. Но прежде чем автоматизировать массовые операции, нужно разобраться, как Zabbix отдает данные о шаблонах и как принимает команды на их создание.

Чтение конфигурации: метод template.get

В Zabbix API для получения информации о любой сущности используется метод .get. Для шаблонов это template.get.

Если вы отправите этот метод без параметров, API вернет массив абсолютно всех шаблонов в системе. Это долго и ресурсоемко. Поэтому в блоке params всегда используются фильтры и ограничители выдачи.

Рассмотрим запрос, который ищет конкретный шаблон по его техническому имени:

{
    "jsonrpc": "2.0",
    "method": "template.get",
    "params": {
        "output": ["templateid", "host", "name"],
        "filter": {
            "host": ["Linux by Zabbix agent"]
        }
    },
    "id": 1,
    "auth": "ваш_токен_здесь"
}

Здесь мы вводим два важнейших архитектурных понятия Zabbix API: фильтрацию и управление выводом.

Фильтрация: filter vs search

В параметрах .get методов есть два основных способа найти нужный объект:

  1. filter — строгое соответствие. В примере выше мы ищем точное совпадение поля host (техническое имя шаблона) со строкой "Linux by Zabbix agent".
  2. search — поиск по подстроке (аналог SQL-оператора LIKE). Если бы мы написали "search": {"host": "Linux"}, API вернул бы все шаблоны, в имени которых есть слово "Linux".

Управление выводом: параметр output

По умолчанию Zabbix API старается экономить трафик и возвращает только идентификаторы объектов (templateid). Чтобы получить другие поля сущности, используется параметр output.

Вы можете передать массив конкретных полей (как в примере: ["templateid", "host", "name"]) или строку "extend", чтобы получить все базовые свойства шаблона (описание, статус и т.д.).

Реляционная модель и параметры select

Шаблон в Zabbix — это не одна плоская таблица в базе данных. Это ядро, к которому привязаны десятки других сущностей: группы, макросы, элементы данных, триггеры.

Параметр output возвращает только те поля, которые хранятся непосредственно в таблице самого шаблона. Если вы запросите output: "extend", вы не увидите ни привязанных макросов, ни групп.

Чтобы получить связанные сущности, используются параметры с префиксом select.

{
    "jsonrpc": "2.0",
    "method": "template.get",
    "params": {
        "output": ["host"],
        "filter": {
            "host": ["Linux by Zabbix agent"]
        },
        "selectTemplateGroups": ["groupid", "name"],
        "selectMacros": "extend"
    },
    "id": 2,
    "auth": "ваш_токен"
}

В этом запросе мы говорим API: «Дай мне техническое имя шаблона (output), а также присоедини к ответу информацию о группах шаблонов (selectTemplateGroups), в которых он состоит (только их ID и имена), и выведи все макросы (selectMacros), привязанные к этому шаблону».

Ответ сервера будет иметь вложенную структуру:

{
    "jsonrpc": "2.0",
    "result": [
        {
            "host": "Linux by Zabbix agent",
            "templategroups": [
                {
                    "groupid": "10",
                    "name": "Templates/Operating systems"
                }
            ],
            "macros": [
                {
                    "macroid": "152",
                    "macro": "{$VFS.FS.PUSED.MAX.CRIT}",
                    "value": "90"
                }
            ]
        }
    ],
    "id": 2
}

Такой подход позволяет собрать полную конфигурацию шаблона за один HTTP-запрос, избегая проблемы N+1 запросов к базе данных.

Создание нового шаблона: метод template.create

Поняв структуру данных через template.get, мы можем перейти к созданию. Метод template.create принимает JSON-объект, описывающий новый шаблон.

Согласно документации Zabbix, для создания шаблона обязательны всего два поля:

  1. host — техническое имя (уникальное в рамках системы, без пробелов, обычно на английском).
  2. groups — массив объектов с идентификаторами групп шаблонов, к которым он будет принадлежать (шаблон не может висеть в воздухе).

Сформируем запрос на создание кастомного шаблона для источника бесперебойного питания:

{
    "jsonrpc": "2.0",
    "method": "template.create",
    "params": {
        "host": "Template_Custom_UPS_SNMP",
        "name": "Custom UPS by SNMP",
        "description": "Шаблон для мониторинга ИБП через SNMPv3",
        "groups": [
            {
                "groupid": "13"
            }
        ],
        "tags": [
            {
                "tag": "class",
                "value": "power"
            }
        ]
    },
    "id": 3,
    "auth": "ваш_токен"
}

Обратите внимание на поле name — это видимое имя шаблона в веб-интерфейсе. Если его не передать, Zabbix будет использовать техническое имя host в качестве видимого. Также мы сразу добавили тег для удобной фильтрации в будущем.

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

Если запрос успешен, Zabbix не возвращает весь созданный объект. В блоке result вернется объект с массивом templateids:

{
    "jsonrpc": "2.0",
    "result": {
        "templateids": [
            "10567"
        ]
    },
    "id": 3
}

Этот templateid (в нашем случае 10567) критически важен. В реальных скриптах автоматизации вы сохраняете этот ID в переменную, чтобы следующими API-запросами прикрепить к этому шаблону элементы данных, триггеры и графики.

Метод template.create позволяет передать в params не один объект, а массив объектов. Таким образом, одним HTTP-запросом можно создать десятки шаблонов, что радикально ускоряет развертывание базовой конфигурации у нового клиента.

Мы научились читать конфигурацию шаблонов и программно создавать пустые оболочки. В следующем шаге мы наполним эту оболочку метриками.

Автоматизация создания элементов данных через API

Автоматизация создания элементов данных через API

В прошлой главе мы успешно создали пустой шаблон Template_Custom_UPS_SNMP с помощью метода template.create. Но пустой шаблон бесполезен. Представьте, что вам нужно добавить в него 150 метрик: температуры, статусы батарей, токи по каждой фазе. Делать это через веб-интерфейс — значит потратить часы на монотонные клики мышью с риском опечататься в OID. Вместо этого мы напишем код, который наполнит шаблон за доли секунды.

Для создания метрик в Zabbix API используется метод item.create. В этой статье мы разберем его анатомию, научимся создавать специфичные типы метрик (SNMP и Dependent) и рассмотрим, как отправлять данные целыми пакетами.

Анатомия метода item.create

Когда вы создаете элемент данных в веб-интерфейсе, Zabbix скрывает от вас многие технические детали за выпадающими списками. В API вам придется передавать точные числовые идентификаторы и соблюдать строгие правила именования полей.

Чтобы метод item.create отработал успешно, в блоке params необходимо передать шесть обязательных параметров:

  1. name — имя элемента данных (например, "UPS Battery Capacity").
  2. key_ — ключ элемента данных. Обратите внимание на подчеркивание на конце! В базе данных Zabbix слово "key" является зарезервированным, поэтому разработчикам API пришлось использовать key_.
  3. hostid — идентификатор узла сети или шаблона, к которому привязывается метрика. Это тот самый ID, который мы получили в ответ на template.create в прошлой главе.
  4. type — тип элемента данных. В API это всегда число. Например, 20 означает "SNMP agent", а 18 — "Dependent item".
  5. value_type — тип возвращаемого значения (0 — число с плавающей точкой, 1 — текст, 3 — целое число). Не путайте с type! type говорит, как собирать данные, а value_typeв каком формате их хранить.
  6. delay — интервал обновления (например, "1m" или "30s").

Создание SNMP-метрики

Если вы указали type: 20 (SNMP agent), Zabbix API потребует еще один обязательный параметр, специфичный именно для этого типа — snmp_oid.

Вот как выглядит минимальный рабочий JSON-запрос для создания SNMP-метрики заряда батареи в нашем шаблоне (допустим, ID шаблона — 10543):

{
    "jsonrpc": "2.0",
    "method": "item.create",
    "params": {
        "name": "Battery capacity",
        "key_": "ups.bat.capacity",
        "hostid": "10543",
        "type": 20,
        "value_type": 0,
        "delay": "1m",
        "snmp_oid": "1.3.6.1.2.1.33.1.2.4.0",
        "tags": [
            {
                "tag": "component",
                "value": "battery"
            }
        ]
    },
    "id": 1,
    "auth": "ваш_api_токен"
}

Обратите внимание, что мы также добавили массив tags. Хотя теги не являются строго обязательными, профессиональная разработка шаблонов подразумевает их наличие для удобной фильтрации проблем в будущем.

Создание Master и Dependent элементов через API

Ранее мы разбирали архитектуру оптимизации, при которой один Master-элемент делает тяжелый запрос и получает большой JSON, а десятки Dependent-элементов разбирают его в оперативной памяти сервера. Как реализовать эту связку через API?

Для зависимого элемента данных (Dependent item) тип указывается как type: 18. Но как Zabbix поймет, из какого именно Master-элемента брать данные? Для этого существует специальное поле master_itemid.

Здесь возникает логическая задача: чтобы создать зависимый элемент, вам нужно знать ID мастера. Но если вы создаете шаблон с нуля, ID мастера еще не существует.

Поэтому процесс создания такой связки через API всегда разбивается на два последовательных шага:

  1. Запрос 1: Вы отправляете item.create для Master-элемента. Zabbix возвращает вам его свежесгенерированный itemid (например, 22001).
  2. Запрос 2: Вы отправляете item.create для Dependent-элемента, подставляя полученный 22001 в поле master_itemid.

Пример запроса на создание зависимого элемента, который извлекает вольтаж фазы из JSON:

{
    "jsonrpc": "2.0",
    "method": "item.create",
    "params": {
        "name": "Phase 1 Voltage",
        "key_": "ups.phase1.voltage",
        "hostid": "10543",
        "type": 18,
        "value_type": 0,
        "master_itemid": "22001",
        "preprocessing": [
            {
                "type": 12,
                "params": "$.phases[0].voltage",
                "error_handler": 0,
                "error_handler_params": ""
            }
        ]
    },
    "id": 2,
    "auth": "ваш_api_токен"
}

В этом примере мы также передали массив preprocessing. Тип предобработки 12 соответствует шагу JSONPath. Поле params содержит само выражение для поиска нужного значения.

Массовое создание метрик (Batching)

Вызывать API отдельным HTTP-запросом для каждой из 150 метрик — плохая практика. Это создает избыточную сетевую нагрузку и замедляет работу вашего скрипта автоматизации.

Метод item.create спроектирован так, чтобы принимать не только один объект, но и массив объектов в блоке params. Это позволяет создать десятки метрик за одно обращение к серверу.

{
    "jsonrpc": "2.0",
    "method": "item.create",
    "params": [
        {
            "name": "Battery Temperature",
            "key_": "ups.bat.temp",
            "hostid": "10543",
            "type": 20,
            "value_type": 0,
            "delay": "5m",
            "snmp_oid": "1.3.6.1.2.1.33.1.2.7.0"
        },
        {
            "name": "Estimated Minutes Remaining",
            "key_": "ups.bat.time",
            "hostid": "10543",
            "type": 20,
            "value_type": 3,
            "delay": "1m",
            "snmp_oid": "1.3.6.1.2.1.33.1.2.3.0"
        }
    ],
    "id": 3,
    "auth": "ваш_api_токен"
}

В ответ на такой запрос Zabbix вернет объект itemids с массивом идентификаторов в том же порядке, в котором вы передавали элементы:

{
    "jsonrpc": "2.0",
    "result": {
        "itemids": [
            "22002",
            "22003"
        ]
    },
    "id": 3
}

Используя массовое создание, вы можете сначала сформировать в вашем скрипте (например, на Python) полный список всех независимых метрик и отправить их одним пакетом. Затем, получив ID созданных Master-элементов, сформировать второй массив со всеми Dependent-метриками и отправить их вторым пакетом.

Таким образом, мы программно наполнили наш шаблон. Теперь он содержит логику сбора данных, предобработку и теги.

Массовое связывание шаблонов с устройствами через скрипты

Массовое связывание шаблонов с устройствами через скрипты

Представьте: вы потратили неделю на идеальный шаблон для ИБП APC Smart-UPS. Он автоматически находит батареи, считает оставшееся время работы и использует продвинутую предобработку. Шаблон готов. Но у вашего клиента в инфраструктуре 300 таких ИБП, разбросанных по разным филиалам. Будете ли вы открывать веб-интерфейс Zabbix 300 раз, чтобы нажать кнопку «Добавить шаблон»?

Профессиональный подход подразумевает, что раскатка мониторинга должна быть такой же автоматизированной, как и сам сбор метрик. Имея на руках API-токен, мы можем связать наш новый шаблон с сотнями устройств за один HTTP-запрос.

Шаг 1: Поиск целевых узлов сети (host.get)

Прежде чем привязывать шаблон, скрипту нужно понять, к кому его привязывать. В Zabbix узлы сети идентифицируются внутренним ID (hostid). Чтобы получить список нужных ID, используется метод host.get.

Обычно устройства группируются по типам оборудования, вендорам или тегам. Допустим, мы хотим найти все серверы, которые лежат в группе «UPS» (предположим, её ID равен 15), чтобы повесить на них наш шаблон.

Запрос host.get будет выглядеть так:

{
    "jsonrpc": "2.0",
    "method": "host.get",
    "params": {
        "output": ["hostid", "host"],
        "groupids": "15"
    },
    "id": 1,
    "auth": "ваш_токен"
}

В ответ Zabbix вернет массив объектов. Нас интересуют только значения hostid. Вытащив их в скрипте, мы формируем список целей: [{"hostid": "1001"}, {"hostid": "1002"}, {"hostid": "1003"}].

Шаг 2: Массовая привязка (host.massupdate)

Для изменения сразу множества узлов сети в Zabbix API есть специальный метод — host.massupdate. Он принимает массив узлов и применяет к ним заданные изменения.

Здесь кроется главная ловушка для новичков. Если вы используете обычный метод host.update и передаете ему параметр templates, Zabbix заменит весь список шаблонов на узле. То есть, если на сервере уже висел базовый шаблон ICMP Ping, он будет удален, и останется только ваш новый шаблон. Это катастрофа для работающей инфраструктуры.

Чтобы безопасно добавить шаблон, ничего не удаляя, метод host.massupdate предлагает параметр templates_link.

Структура безопасного запроса на массовую привязку:

{
    "jsonrpc": "2.0",
    "method": "host.massupdate",
    "params": {
        "hosts": [
            {"hostid": "1001"},
            {"hostid": "1002"},
            {"hostid": "1003"}
        ],
        "templates_link": [
            {"templateid": "10254"}
        ]
    },
    "id": 2,
    "auth": "ваш_токен"
}

В этом запросе мы говорим: «Возьми три указанных хоста и долинкуй к ним шаблон с ID 10254». Все старые шаблоны, которые уже были на этих хостах, останутся нетронутыми.

Разница между link и clear

Zabbix API предоставляет два родственных параметра для управления шаблонами при массовом обновлении:

  • templates_link — добавляет указанные шаблоны к узлу сети.
  • templates_clear — отвязывает указанные шаблоны от узла сети и удаляет все собранные ими данные (метрики, графики, историю). Это программный аналог кнопки «Unlink and clear» в веб-интерфейсе.

Идемпотентность скриптов автоматизации

Важное правило профессиональной автоматизации: скрипт должен быть идемпотентным. Это значит, что вы можете запустить его один раз, десять раз или сто раз подряд, и результат будет одинаковым — система придет в нужное состояние без ошибок и дублирования.

Метод host.massupdate с параметром templates_link идемпотентен по своей природе. Если вы попытаетесь привязать шаблон к хосту, на котором этот шаблон уже висит, Zabbix API не выдаст ошибку и не создаст дубликаты метрик. Он просто проигнорирует действие для этого конкретного узла и вернет успешный ответ. Это позволяет запускать скрипт раскатки по расписанию (например, раз в сутки), чтобы автоматически накрывать мониторингом новые ИБП, которые инженеры добавили в группу за день.

Практический пример на Python

Соберем логику воедино. Напишем скрипт, который находит все устройства в группе и привязывает к ним шаблон. Для работы с HTTP-запросами в Python стандартом де-факто является библиотека requests.

import requests

API_URL = "http://zabbix.local/api_jsonrpc.php"
TOKEN = "ваш_секретный_токен"
GROUP_ID = "15"          # ID группы UPS
TEMPLATE_ID = "10254"    # ID нашего нового шаблона

headers = {"Content-Type": "application/json-rpc"}

# 1. Получаем список хостов
get_payload = {
    "jsonrpc": "2.0",
    "method": "host.get",
    "params": {
        "output": ["hostid"],
        "groupids": GROUP_ID
    },
    "id": 1,
    "auth": TOKEN
}

response = requests.post(API_URL, json=get_payload, headers=headers).json()
hosts = response.get("result", [])

if not hosts:
    print("В группе нет узлов сети.")
    exit()

# 2. Формируем запрос на массовую привязку
update_payload = {
    "jsonrpc": "2.0",
    "method": "host.massupdate",
    "params": {
        "hosts": hosts, # Передаем полученный массив [{'hostid': '...'}, ...]
        "templates_link": [{"templateid": TEMPLATE_ID}]
    },
    "id": 2,
    "auth": TOKEN
}

update_response = requests.post(API_URL, json=update_payload, headers=headers).json()

if "error" in update_response:
    print("Ошибка привязки:", update_response["error"]["data"])
else:
    print(f"Шаблон успешно привязан к {len(hosts)} устройствам.")

Этот компактный скрипт заменяет часы рутинной работы. Вы можете интегрировать подобную логику в CI/CD пайплайны (например, в GitLab CI), чтобы шаблоны автоматически разъезжались по инфраструктуре клиента сразу после того, как вы закоммитили изменения в репозиторий.

Сквозной проект: сборка шаблона для кастомного ИБП

Сквозной проект: сборка шаблона для кастомного ИБП

У клиента на объекте появилась партия новых промышленных источников бесперебойного питания (ИБП) от китайского вендора «MegaPower». Официального шаблона Zabbix в репозиториях нет, на форумах пусто, а мониторинг нужно запустить уже завтра. На руках есть только IP-адрес устройства и PDF-документ с таблицей OID.

Сборка шаблона с нуля — это не просто механический перенос OID в интерфейс Zabbix. Это проектирование конвейера, который будет надежно собирать данные, автоматически адаптироваться к разным моделям в линейке (например, с разным количеством фаз) и не перегружать базу данных.

Соберем профессиональный шаблон шаг за шагом, объединив все механизмы работы с SNMP, макросами и предобработкой.

Шаг 1: Проектирование каркаса и макросов

Любой профессиональный шаблон начинается с изоляции жестко заданных значений (хардкода). Если мы пропишем пороги срабатывания триггеров прямо в их выражениях, клиенту придется править сам шаблон для каждого нестандартного узла.

Создаем пустой шаблон Template Power MegaPower UPS SNMP и сразу закладываем фундамент из макросов:

  1. Доступ: {$SNMP.COMMUNITY} со значением public. Это позволит переопределить community на уровне конкретного ИБП, если безопасники изменят пароль.
  2. Пороги батареи: {$BATTERY.CAP.MIN.WARN} = 30 (предупреждение) и {$BATTERY.CAP.MIN.CRIT} = 15 (критический уровень).
  3. Пороги напряжения: {$VOLTAGE.MIN.CRIT} = 200 и {$VOLTAGE.MAX.CRIT} = 240.

Теперь шаблон готов к наполнению логикой.

Шаг 2: Статические метрики и защита БД

Согласно документации вендора, у ИБП есть общие параметры, которые существуют в единственном экземпляре. Заведем их как обычные элементы данных (Items).

Первая метрика — Уровень заряда батареи:

  • Name: Battery capacity
  • Type: SNMP agent
  • Key: ups.battery.capacity
  • SNMP OID: .1.3.6.1.4.1.99999.1.1.1.0
  • Type of information: Numeric (unsigned)
  • Units: %

Вторая метрика — Текущий статус ИБП:

  • Name: System status
  • Key: ups.status
  • SNMP OID: .1.3.6.1.4.1.99999.1.1.2.0

Документация гласит, что статус возвращается в виде числа: 1 (Online), 2 (On Battery), 3 (Fault). Оставлять «голые» цифры непрофессионально — дежурный инженер не должен помнить коды наизусть. Создаем Value map (Преобразование значений) с именем MegaPower Status и прописываем соответствия. Привязываем этот Value map к элементу данных.

Здесь кроется важная архитектурная деталь. Статус ИБП — это метрика, которая в 99% случаев равна единице и меняется крайне редко. Если опрашивать ее каждые 30 секунд, за месяц в базу данных запишутся десятки тысяч одинаковых единиц.

Чтобы этого избежать, переходим на вкладку Preprocessing (Предобработка) элемента ups.status и добавляем шаг Discard unchanged with heartbeat с параметром 1h. Теперь Zabbix будет запрашивать статус по сети каждые 30 секунд, но в базу данных запишет значение, только если оно изменилось (например, ИБП перешел на батарею) или прошел ровно час с момента последней записи.

Шаг 3: Динамические метрики и LLD

В линейке MegaPower есть модели с одной входной фазой и с тремя. Если мы жестко пропишем три метрики напряжения (Phase 1, Phase 2, Phase 3), то на однофазном ИБП две метрики перейдут в состояние Not supported, генерируя мусор в логах Zabbix.

Используем низкоуровневое обнаружение (LLD). В документации указана таблица входных фаз с базовым OID .1.3.6.1.4.1.99999.2.1.1.

Создаем Discovery rule:

  • Name: Input phases discovery
  • Key: ups.phases.discovery
  • SNMP OID: discovery[{#PHASE_INDEX}, .1.3.6.1.4.1.99999.2.1.1.1]

Это правило обойдет SNMP-таблицу и сформирует массив, где макрос {#PHASE_INDEX} получит значения 1, 2 и 3 (для трехфазного устройства).

Теперь создаем Item prototype (Прототип элемента данных) для напряжения:

  • Name: Phase {#PHASE_INDEX}: Input voltage
  • Key: ups.phase.voltage[{#PHASE_INDEX}]
  • SNMP OID: .1.3.6.1.4.1.99999.2.1.1.2.{#PHASE_INDEX}
  • Units: V

Zabbix автоматически сгенерирует ровно столько метрик напряжения, сколько фаз физически присутствует на устройстве.

Шаг 4: Валидация данных в прототипах

Аппаратные датчики иногда сбоят. Если датчик напряжения на секунду вернет значение 0 или 9999, это спровоцирует ложное срабатывание триггеров и панику в дежурной смене.

Защитим прототип напряжения на уровне предобработки. Добавляем шаг In range с параметрами от 100 до 300. Обязательно ставим галочку Custom on fail и выбираем Discard value (Отбросить значение).

Если ИБП пришлет аномальное значение V=9999V = 9999, Zabbix просто проигнорирует этот конкретный ответ, не переводя метрику в ошибку и не вызывая триггер. График останется чистым.

Шаг 5: Прототипы триггеров и контекстные макросы

Осталось настроить алертинги. Создаем Trigger prototype для падения напряжения на фазе:

Name: Phase {#PHASE_INDEX}: Voltage is too low Expression: last(/Template Power MegaPower UPS SNMP/ups.phase.voltage[{#PHASE_INDEX}]) < {$VOLTAGE.MIN.CRIT:"{#PHASE_INDEX}"}

Обратите внимание на синтаксис макроса: {$VOLTAGE.MIN.CRIT:"{#PHASE_INDEX}"}. Мы вложили LLD-макрос фазы внутрь контекста пользовательского макроса. Зачем это нужно?

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

Благодаря контекстному макросу администратор сможет зайти в настройки конкретного узла сети и создать макрос {$VOLTAGE.MIN.CRIT:"1"} со значением 200, оставив для остальных фаз глобальный порог 220 В. Механизм фоллбэка Zabbix автоматически применит сниженный порог только к первой фазе, а для второй и третьей использует базовое значение {$VOLTAGE.MIN.CRIT}.

Итог сборки

Мы получили шаблон, который:

  1. Автоматически адаптируется под количество фаз конкретной модели ИБП.
  2. Экономит место в базе данных за счет прореживания (Throttling) статических статусов.
  3. Защищен от аппаратных глитчей датчиков (In range + Discard).
  4. Позволяет точечно настраивать пороги алертинга для каждой фазы в отдельности без дублирования триггеров.

Шаблон готов к использованию. Следующий шаг — научиться массово разворачивать такие шаблоны на сотни устройств клиента, не кликая мышкой в интерфейсе, а используя программный подход.

Сквозной проект: автоматическое развертывание мониторинга через API

Сквозной проект: автоматическое развертывание мониторинга через API

В прошлой главе мы спроектировали профессиональный шаблон Template Power MegaPower UPS SNMP. Он изолирует хардкод в макросах, отсекает аппаратные глитчи и динамически обнаруживает фазы питания. Шаблон идеален. Но теперь представьте: клиент передает вам Excel-таблицу с IP-адресами 500 таких источников бесперебойного питания, разбросанных по филиалам.

Вводить 500 узлов через веб-интерфейс, прописывать каждому IP-адрес, прикреплять шаблон и задавать индивидуальные SNMP Community — это несколько дней монотонной работы, в которой неизбежны опечатки. Профессиональный подход заключается в том, чтобы превратить эту таблицу в источник истины и развернуть мониторинг скриптом за несколько секунд.

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

Источник истины (Source of Truth)

Любая автоматизация начинается со стандартизации входных данных. Скрипту нужен предсказуемый формат. Чаще всего в инфраструктуре это выгрузка из системы инвентаризации (DCIM/IPAM) в формате CSV или JSON.

Назовем этот файл «Источником истины». Если устройства нет в файле — его не должно быть в мониторинге. Если у устройства изменился IP-адрес в файле — скрипт должен обновить его в Zabbix.

Допустим, наша выгрузка ups_inventory.csv выглядит так:

hostname,ip,community,location
msk-core-ups01,10.0.1.50,SecretComm1,Moscow_DC
spb-edge-ups02,10.0.2.50,SecretComm2,SPB_Branch
kaz-edge-ups01,10.0.3.50,SecretComm3,Kazan_Branch

Здесь есть техническое имя, IP-адрес для опроса, уникальный пароль SNMP и локация (которую мы можем использовать для распределения по группам).

Архитектура идемпотентного конвейера

Мы уже знаем, что скрипты должны быть идемпотентными — безопасными для многократного запуска. Мы не можем просто в цикле вызывать метод создания узла. Скрипт должен принимать решения на основе текущего состояния Zabbix.

Логика обработки каждой строки из CSV выглядит так:

  1. Запросить узел в Zabbix по имени (host.get).
  2. Если узла нет — собрать полный JSON-объект и отправить host.create.
  3. Если узел есть — сравнить текущие параметры с файлом и при необходимости отправить host.update.

Специфика создания SNMP-узлов через API

Метод host.create требует передачи нескольких обязательных массивов. Для SNMP-устройств критически важен массив interfaces.

В веб-интерфейсе вы просто нажимаете «Добавить SNMP интерфейс». В API вы должны передать объект с жестко заданными числовыми константами. Для SNMP тип интерфейса всегда равен 2.

"interfaces": [
    {
        "type": 2,
        "main": 1,
        "useip": 1,
        "ip": "10.0.1.50",
        "dns": "",
        "port": "161",
        "details": {
            "version": 2,
            "bulk": 1,
            "community": "{$SNMP.COMMUNITY}"
        }
    }
]

Обратите внимание на блок details. Начиная с Zabbix 5.0, параметры SNMP (версия, community, контекст) перенесены внутрь интерфейса. Мы указываем, что используем SNMPv2, включаем оптимизацию GetBulk ("bulk": 1) и ссылаемся на макрос {$SNMP.COMMUNITY}.

Управление макросами на уровне узла

В нашем CSV-файле у каждого ИБП свой пароль SNMP. В шаблоне мы заложили использование макроса {$SNMP.COMMUNITY}. Теперь нам нужно переопределить этот макрос для каждого конкретного узла при его создании.

Это делается через массив macros прямо в теле запроса host.create или host.update:

"macros": [
    {
        "macro": "{$SNMP.COMMUNITY}",
        "value": "SecretComm1",
        "type": 1
    }
]

Здесь type: 1 означает обычный текстовый макрос (тип 2 — это Secret text, который скрывает значение звездочками в интерфейсе).

Итоговый скрипт развертывания

Объединим чтение файла, проверку существования, привязку шаблона Template Power MegaPower UPS SNMP (допустим, мы узнали через template.get, что его ID — 10254) и группы (ID — 15) в единый Python-скрипт с использованием библиотеки requests.

import csv
import requests

API_URL = "http://zabbix.local/api_jsonrpc.php"
HEADERS = {
    "Content-Type": "application/json-rpc",
    "Authorization": "Bearer YOUR_API_TOKEN"
}
TEMPLATE_ID = "10254"
GROUP_ID = "15"

def send_request(method, params):
    payload = {
        "jsonrpc": "2.0",
        "method": method,
        "params": params,
        "id": 1
    }
    response = requests.post(API_URL, headers=HEADERS, json=payload)
    return response.json()

# Читаем Источник истины
with open('ups_inventory.csv', mode='r') as file:
    reader = csv.DictReader(file)
    for row in reader:
        hostname = row['hostname']
        ip = row['ip']
        community = row['community']

        # Шаг 1: Проверяем, существует ли узел
        check_req = send_request("host.get", {
            "filter": {"host": [hostname]},
            "output": ["hostid"]
        })

        if not check_req.get('result'):
            # Шаг 2: Узла нет, создаем
            create_params = {
                "host": hostname,
                "groups": [{"groupid": GROUP_ID}],
                "templates": [{"templateid": TEMPLATE_ID}],
                "interfaces": [{
                    "type": 2,
                    "main": 1,
                    "useip": 1,
                    "ip": ip,
                    "dns": "",
                    "port": "161",
                    "details": {"version": 2, "bulk": 1, "community": "{$SNMP.COMMUNITY}"}
                }],
                "macros": [{
                    "macro": "{$SNMP.COMMUNITY}",
                    "value": community,
                    "type": 1
                }]
            }
            res = send_request("host.create", create_params)
            print(f"Создан узел {hostname}, ID: {res['result']['hostids'][0]}")
        else:
            # Шаг 3: Узел существует, можно обновить IP или макросы (упрощенно)
            hostid = check_req['result'][0]['hostid']
            print(f"Узел {hostname} уже существует (ID: {hostid}), пропускаем или обновляем.")

Этот скрипт можно запускать хоть каждую минуту через cron. Если вы добавите новую строку в CSV, скрипт создаст только новый ИБП, не трогая остальные. Это и есть профессиональная автоматизация инфраструктуры.

Мы прошли путь от изучения структуры MIB-файла до массовой раскатки готового шаблона скриптом. Конвейер работает, метрики собираются, триггеры готовы реагировать на сбои питания. Однако в реальной практике при развертывании часто возникают ситуации, когда метрика внезапно переходит в статус "Not supported", а LLD-правило отказывается создавать элементы. О том, как диагностировать и чинить такие проблемы, мы поговорим в следующей, заключительной главе.

Тестирование шаблонов и отладка типичных ошибок

Тестирование шаблонов и отладка типичных ошибок

Скрипт отработал идеально. Ваш новый шаблон для ИБП раскатан на пятьсот устройств через API. Вы открываете дашборд в ожидании красивых графиков, но вместо этого видите море красных иконок: половина элементов данных перешла в статус «Not supported». Клиент ждет объяснений.

Паника — инструмент дилетанта. Профессионал знает, что создание шаблона — это лишь половина дела. Вторая половина — умение быстро локализовать проблему на любом уровне: от сетевого таймаута до опечатки в JSON-RPC запросе. В этой финальной главе курса мы разберем системный подход к отладке мониторинга.

Анатомия ошибки: статус «Not supported»

Когда Zabbix не может получить корректные данные, он переводит элемент (Item) или правило обнаружения (LLD) в состояние «Not supported». Это защитный механизм: система фиксирует факт поломки, но не останавливает работу остальных проверок.

Причины всегда делятся на три уровня:

  1. Сетевой уровень (Timeout). Устройство выключено, закрыт порт UDP 161, неверный SNMP Community.
  2. Уровень устройства (No Such Object). Устройство доступно, но запрошенный OID не существует на данной модели (например, вы запросили температуру батареи, а датчика физически нет).
  3. Уровень логики Zabbix (Preprocessing/Type mismatch). Данные пришли, но шаг регулярного выражения ничего не нашел, или текст попытались записать в числовой тип данных.

Важно понимать поведение системы в этом состоянии. Если метрика сломалась, Zabbix не бросает попытки ее опросить. Он продолжит отправлять запросы в соответствии с настроенным интервалом обновления (Update interval). Как только устройство ответит корректно или вы исправите ошибку в предобработке, метрика автоматически «позеленеет» при следующем плановом опросе.

Кнопка «Test»: симуляция без ожидания

Ждать 5 или 10 минут до следующего опроса при отладке — непозволительная трата времени. В веб-интерфейсе Zabbix внутри каждого элемента данных и правила обнаружения есть кнопка Test.

Она выполняет две важнейшие функции:

1. Получение сырых данных (Get value). Вы можете отправить тестовый запрос прямо из браузера. Zabbix-сервер (или прокси) немедленно свяжется с устройством и покажет ответ. Если проблема на сетевом уровне, вы сразу увидите ошибку вроде Timeout while connecting to....

2. Пошаговая отладка предобработки. Это самый мощный инструмент разработчика шаблонов. Если метрика собирает сложный JSON через API или длинную строку по SNMP, вы можете вставить этот сырой текст в поле «Value» и нажать «Test». Zabbix прогонит текст через все шаги предобработки (RegEx, JSONPath, JavaScript) и покажет результат каждого шага. Вы сразу увидите, на каком именно этапе ломается логика, не отправляя реальные запросы к устройству.

Погружение на уровень ядра: zabbix_server.log

Иногда интерфейс дает слишком общую ошибку. Например, устройство отвечает по SNMPv3, но Zabbix пишет таймаут. Чтобы увидеть сырые пакеты и процесс аутентификации, нужно заглянуть в логи самого сервера.

По умолчанию Zabbix пишет в лог только критические ошибки (DebugLevel 3). Для глубокой отладки нам нужен DebugLevel 4 — детальная трассировка. Менять конфигурационный файл и перезапускать сервер нельзя — это прервет мониторинг всей инфраструктуры.

Используйте Runtime control — механизм управления ядром на лету. Подключитесь к серверу по SSH и выполните команду:

zabbix_server -R log_level_increase="poller,1"

Эта команда повысит уровень логирования только для процесса номер 1, отвечающего за обычные опросы (poller). Теперь в файле /var/log/zabbix/zabbix_server.log вы увидите каждый байт, который сервер отправляет и получает. Как только найдете причину (например, несовпадение алгоритма шифрования AES), верните лог в норму:

zabbix_server -R log_level_decrease="poller,1"

Отладка LLD: почему не создаются прототипы?

Самая частая и неприятная проблема при разработке: правило обнаружения горит зеленым, ошибок нет, но элементы данных из прототипов не появляются.

Алгоритм поиска проблемы:

  1. Проверьте сырой JSON. Зайдите в правило LLD, нажмите Test и посмотрите, что возвращает устройство. Это точно массив объектов [{"{#MACRO}": "value"}]? Если шаг предобработки вернул просто строку или пустой массив [] — генерировать не из чего.
  2. Проверьте фильтры. Возможно, ваш JSON идеален, но вкладка Filters отсекает все найденные сущности. Временно удалите условия фильтрации и проверьте, создадутся ли метрики.
  3. Ищите дубликаты ключей. Это классика. Zabbix не может создать два элемента данных с одинаковым ключом на одном узле сети. Если ваше LLD нашло два интерфейса с одинаковым именем (например, два {#IFNAME} равны "VLAN1"), Zabbix создаст метрику для первого, а при попытке создать для второго — тихо выбросит ошибку. Эту ошибку можно найти в списке правил обнаружения: в колонке «Info» появится красный значок с текстом Cannot create item: item with key "net.if.in[VLAN1]" already exists.

Чтение ответов API при ошибках раскатки

Если вы автоматизируете раскатку через Python, ошибки будут возвращаться не в интерфейсе, а прямо в скрипт. Zabbix API всегда возвращает HTTP-статус 200 OK, даже если запрос составлен неверно. Ошибку нужно искать внутри JSON-ответа.

Если запрос не удался, Zabbix вернет объект error вместо result:

{
    "jsonrpc": "2.0",
    "error": {
        "code": -32602,
        "message": "Invalid params.",
        "data": "Cannot find host interface on \"UPS_Main\" for item key \"ups.status\"."
    },
    "id": 1
}

Ключевое поле здесь — data. В данном примере API прямым текстом говорит: вы пытаетесь создать SNMP-метрику ups.status, но забыли прикрепить к узлу сети интерфейс типа SNMP (type: 2).

Частые коды ошибок:

  • -32602 (Invalid params) — ошибка в структуре запроса (забыли обязательное поле, неверный тип данных).
  • -32500 (Application error) — логическая ошибка Zabbix (попытка создать дубликат, нет прав доступа к указанной группе узлов).

Заключение курса

Отладка — это не магия, а методичное исключение неизвестных. Если метрика не работает, проверьте сеть утилитой snmpget. Если сеть работает — проверьте предобработку кнопкой Test. Если предобработка в норме — смотрите логи сервера.

Вы прошли путь от понимания того, что такое OID, до проектирования сложных конвейеров предобработки и массового управления инфраструктурой через код. Профессиональный разработчик шаблонов не просто собирает метрики — он создает надежные, оптимизированные и легко масштабируемые системы мониторинга. Теперь этот инструмент в ваших руках.