Мониторинг скорости интернет каналов в Zabbix

—

от автора

Всем привет!

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

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

Схема работы

В общем случае, схема мониторинга выглядит следующим образом:

Схема работы мониторинга скорости интернет каналов
Схема работы мониторинга скорости интернет каналов

На объектах установлены сетевые шлюзы на Linux, на которых поднят iperf3 в режиме сервера. В каждом филиале есть сервер Zabbix Proxy, на котором запускается iperf3 в режиме клиента и замеряет скорость интернета, после он в Zabbix trap записывает данные замера.

Настройка и запуск iperf3 на удаленном объекте

Как уже писал выше, на объектах установлены сетевые шлюзы на Linux. На них был установлен iperf3 и создана задача на запуск iperf3 при старте шлюза. Запуск осуществляется следующей командой, где <IP_address> интерфейса, через который осуществляется замер скорости:

/usr/bin/iperf3 -B <IP_address> -Ds

Настройка iperf3 на Zabbix Proxy сервере

Для начала необходимо установить следующие пакеты: iperf3, python-pip, python. Из pip нам необходимо установить py-zabbix и protobix.

apt install iperf3 python-pip python pip install py-zabbix pip install protobix

Далее создаем папку iperf в /usr/lib/zabbix/externalscripts/. В папке создаем два файла iperf3_speed_testing.py и iperf3_task.py (один для замера скорости из Zabbix, второй для периодических замеров всех). И даем им нужные разрешения. Владельцем папки делаем пользователя zabbix.

mkdir /usr/lib/zabbix/externalscripts/iperf touch /usr/lib/zabbix/externalscripts/iperf/iperf3_speed_testing.py touch /usr/lib/zabbix/externalscripts/iperf/iperf3_task.py chown -R zabbix:zabbix /usr/lib/zabbix/externalscripts/iperf chmod +x /usr/lib/zabbix/externalscripts/iperf/iperf3_speed_testing.py chmod +x /usr/lib/zabbix/externalscripts/iperf/iperf3_task.py

Описание и содержимое скриптов

Скрипт /usr/lib/zabbix/externalscripts/iperf/iperf3_speed_testing.py необходим для выполнения запуска замера скорости на текущий момент. Он запускает запуск замеров на выбранном хосте в Zabbix.

#!/usr/bin/python #- *- coding: utf-8 - *-  import protobix import argparse import subprocess import sys import json import time  proxy = subprocess.Popen(['hostname'], stdout=subprocess.PIPE) proxy = proxy.communicate()[0]  def showResult(_upload, _download):         print "Отправка: " + str(round(_upload/1000000,2)) + " Мбит/с"         print "Получение: " + str(round(_download/1000000,2)) + " Мбит/с"  def sendData(_upload, _download):         host_moria = sys.argv[2]         host_status = {}         host_status['speed_upload'] = _upload         host_status['speed_download'] = _download         zbx_datacontainer = protobix.DataContainer()         zbx_datacontainer.server_active = proxy.split('\n')[0]         zbx_datacontainer.server_port = 10051         zbx_datacontainer.data_type = "items"         zbx_datacontainer.add({host_moria: host_status}) #       print json.dumps({host_moria: host_status}, indent=4)         zbx_datacontainer.send()         showResult(_upload, _download)  start_time = time.time() result = subprocess.Popen(['/usr/bin/iperf3', '-c', sys.argv[1], '-J', '-P', '5'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)  wait = time.time()-start_time while wait < 45 and result.poll() == None:         wait = time.time()-start_time         if wait > 40 and wait < 45 :                 result.kill()                 stdout_value = {"error":"Timeout error"}                 stdout_json = stdout_value                 stdout_value = str(stdout_value)                 break  else:         stdout_value, stderr_value = result.communicate()         stdout_json = json.loads(stdout_value)  while stdout_value.find('error') != -1 and stdout_json['error'] == 'error - unable to receive results: Resource temporarily unavailable':                 result = subprocess.Popen(['/usr/bin/iperf3', '-c', sys.argv[1], '-J', '-P', '5'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)                 stdout_value, stderr_value = result.communicate()                 stdout_json = json.loads(stdout_value)  if stdout_value.find('error') == -1:         sendData(stdout_json['end']['sum_sent']['bits_per_second'],stdout_json['end']['sum_received']['bits_per_second']) else:         print stdout_json['error'] 

Скрипт /usr/lib/zabbix/externalscripts/iperf/iperf3_task.py необходим для запуска задачи на замер скорости в выбранных группах хостов Zabbix. Для работы данного скрипта также необходимо создать пользователя с доступом к Zabbix API. В данном скрипте используются следующие переменные:

  • zabbix_user — пользователь с доступом к API

  • zabbix_password — пароль пользователя API

  • zabbix_server — адрес сервера zabbix

  • group — группа или группы в Zabbix, для которых необходимо делать замер скорости интернета

#!/usr/bin/python # - *- coding: utf- 8 - *- from pyzabbix.api import ZabbixAPI import protobix import argparse import subprocess import sys import json import time  zabbix_user = <zabbix_api_user> zabbix_password = <zabbix_api_password> group = ('Gateway_branch_1','Gateway_branch_2')  start_time_script = time.time()  proxy = subprocess.Popen(['hostname'], stdout=subprocess.PIPE) proxy = proxy.communicate()[0]  def sendData(host, upload, download):         host_moria = host         host_status = {}         host_status['speed_upload'] = upload         host_status['speed_download'] = download         zbx_datacontainer = protobix.DataContainer()         zbx_datacontainer.server_active = proxy.split('\n')[0]         zbx_datacontainer.server_port = 10051         zbx_datacontainer.data_type = "items"         zbx_datacontainer.add({host_moria: host_status}) #       print json.dumps({host_moria: host_status}, indent=4)         zbx_datacontainer.send()  def getZabbixGroupID(groupName):         groups = zapi.hostgroup.get(filter={'name':groupName})         for group in groups:                 return group['groupid']   zapi = ZabbixAPI(url=zabbix_server, user=zabbix_user, password=zabbix_password)  hosts = zapi.host.get(groupids=[getZabbixGroupID(group[0]),getZabbixGroupID(group[1])], selectInterfaces=['ip'])  for host in hosts:  #       print (host['host'])         start_time = time.time()         result = subprocess.Popen(['/usr/bin/iperf3', '-c', host['interfaces'][0]['ip'], '-J', '-P', '5'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)          wait = time.time()-start_time         while wait < 45 and result.poll() == None:                 wait = time.time()-start_time                 if wait > 40 and wait < 45 :                         result.kill()                         stdout_value = {"error":"Timeout error"}                         stdout_json = stdout_value                         stdout_value = str(stdout_value)                         break          else:                 stdout_value, stderr_value = result.communicate()                 stdout_json = json.loads(stdout_value)          while stdout_value.find('error') != -1 and stdout_json['error'] == 'error - unable to receive results: Resource temporarily unavailable':                 result = subprocess.Popen(['/usr/bin/iperf3', '-c', host['interfaces'][0]['ip'], '-J', '-P', '5'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)                 stdout_value, stderr_value = result.communicate()                 stdout_json = json.loads(stdout_value)          if stdout_value.find('error') == -1:                 sendData(host['host'], stdout_json['end']['sum_sent']['bits_per_second'], stdout_json['end']['sum_received']['bits_per_second'])  zapi.user.logout()  related_time = time.time() - start_time_script  host_moria = proxy.split('\n')[0] host_status = {} host_status['iperf_task_time'] = float(round(related_time,2)) zbx_datacontainer = protobix.DataContainer() zbx_datacontainer.server_active = 'zabbix-server' zbx_datacontainer.server_port = 10051 zbx_datacontainer.data_type = "items" zbx_datacontainer.add({host_moria: host_status}) zbx_datacontainer.send()

Создаем задачу в crontab

0 2,6,10,14,18,22 * * * /usr/lib/zabbix/externalscripts/iperf/iperf3_task.py

Мы делаем замер раз в 4 часа. Нам этого хватает.

Если у вас используется просто Zabbix сервер, то на нем нужно сделать то же самое.

Настройка шаблонов и скриптов в Zabbix

Для начала необходимо создать шаблон с элементами данных замеров скорости интернета. Я назвал шаблон Internet Speed Testing

Шаблон Inernet speed testing
Шаблон Inernet speed testing

В данном шаблоне необходимо создать следующие элементы данных:

  • Speed Upload

  • Speed Download

Триггеры:

  • Нет данных замеров скорости более 48 часов

  • Низкая скорость загрузки

  • Низкая скорость выгрузки

Триггеры
Триггеры

Макросы:

  • {$LOW_SPEED} — для записи скорости, при которой срабатывает триггер

Также добавляем Скрипт для замера скорости вручную (Администрирование -> Скрипты -> Создать скрипт)

Данные для настройки скрипта ручного замера
Данные для настройки скрипта ручного замера

В поле команда вставляем путь к скрипту в следующем виде /usr/lib/zabbix/externalscripts/iperf/iperf3_speed_testing.py {HOST.CONN} ‘{HOST.HOST}’

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

Нажимаем на нужный хост и выбираем Скорость интернета. Получаем ответ:

Результат замера скорости
Результат замера скорости

Далее проверяем элементы данных обновились. Ждем некоторое время и можем получаем такую статистику для каждого хоста:

Статистика замеров скорости интернета
Статистика замеров скорости интернета

На этом всё. Спасибо за внимание! ?


ссылка на оригинал статьи https://habr.com/ru/articles/590775/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *