Skip to main content

Мониторинг сетевого оборудования через SNMP

Введение

Данная документация описывает процесс настройки системы мониторинга сетевого оборудования (коммутаторы SNR, маршрутизаторы MikroTik) с использованием стека технологий:

  • SNMP — протокол для сбора метрик с устройств
  • Telegraf — агент для сбора и отправки метрик
  • InfluxDB — база данных для хранения временных рядов
  • Grafana — платформа для визуализации и алертинга

Что такое метрики и SNMP

Метрики

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

МетрикаОписаниеПример значения
UptimeВремя работы устройства25 days, 9:12:47
ifInOctetsВходящий трафик (байты)29153382
ifOutOctetsИсходящий трафик (байты)1110677606
ifOperStatusСтатус интерфейса1 (up) / 2 (down)
CPU LoadЗагрузка процессора15%

SNMP (Simple Network Management Protocol)

SNMP — стандартный протокол для мониторинга и управления сетевыми устройствами. Работает по модели "запрос-ответ" через UDP порт 161.

Ключевые понятия SNMP

OID (Object Identifier) — уникальный идентификатор метрики в виде числовой последовательности:

1.3.6.1.2.1.1.3.0 = sysUptime (время работы системы)
│ │ │ │ │ │ │ │ └── индекс
│ │ │ │ │ │ │ └──── system (1)
│ │ │ │ │ │ └────── mib-2 (1)
│ │ │ │ │ └──────── mgmt (2)
│ │ │ │ └────────── internet (1)
│ │ │ └──────────── dod (6)
│ │ └────────────── org (3)
│ └──────────────── iso (1)
└────────────────── root

MIB (Management Information Base) — база данных, описывающая доступные OID'ы на устройстве. Бывают:

  • Стандартные (RFC) — одинаковые для всех вендоров
  • Приватные — специфичные для производителя (например, 1.3.6.1.4.1.14988 для MikroTik)

Community String — строка аутентификации (по сути пароль) для доступа к SNMP. По умолчанию часто public для чтения.

Стандартные OID'ы для интерфейсов

1.3.6.1.2.1.2.2.1.1  — ifIndex (индекс интерфейса)
1.3.6.1.2.1.2.2.1.2 — ifDescr (имя интерфейса)
1.3.6.1.2.1.2.2.1.3 — ifType (тип: 6=ethernet, 23=ppp)
1.3.6.1.2.1.2.2.1.4 — ifMtu (MTU)
1.3.6.1.2.1.2.2.1.5 — ifSpeed (скорость)
1.3.6.1.2.1.2.2.1.7 — ifAdminStatus (админ статус)
1.3.6.1.2.1.2.2.1.8 — ifOperStatus (операционный статус)
1.3.6.1.2.1.2.2.1.9 — ifLastChange (время последнего изменения)
1.3.6.1.2.1.2.2.1.10 — ifInOctets (входящие байты)
1.3.6.1.2.1.2.2.1.16 — ifOutOctets (исходящие байты)

Извлечение метрик через SNMP

Для работы с SNMP из командной строки используется пакет snmp:

# Установка
sudo apt install snmp

# Получить одно значение
snmpget -v2c -c public 192.168.1.1 1.3.6.1.2.1.1.3.0

# Обход дерева OID'ов
snmpwalk -v2c -c public 192.168.1.1 1.3.6.1.2.1.2.2.1.2

# Параметры:
# -v2c — версия SNMP (1, 2c или 3)
# -c — community string
# IP — адрес устройства
# OID — идентификатор метрики

Пример вывода snmpwalk для интерфейсов:

iso.3.6.1.2.1.2.2.1.2.1 = STRING: "Ethernet1/0/1"
iso.3.6.1.2.1.2.2.1.2.2 = STRING: "Ethernet1/0/2"
iso.3.6.1.2.1.2.2.1.2.15729389 = STRING: "<l2tp-Tashkent_Oazis>"

Число после последней точки (1, 2, 15729389) — это ifIndex, уникальный идентификатор интерфейса.


Архитектура системы мониторинга

┌─────────────────┐     SNMP (UDP 161)     ┌─────────────┐
│ SNR Switch │◄──────────────────────►│ │
172.20.104.253 │ │ │
└─────────────────┘ │ │
│ Telegraf │
┌─────────────────┐ SNMP (UDP 161)(сборщик)
│ MikroTik CCR │◄──────────────────────►│ │
172.20.107.254 │ │ │
└─────────────────┘ └──────┬──────┘

│ HTTP (8086)

┌─────────────┐
│ InfluxDB │
(хранение)
└──────┬──────┘

│ Flux queries

┌─────────────┐
│ Grafana │
(визуализа- │
│ ция)
└─────────────┘

Поток данных

  1. Устройства (свитчи, роутеры) хранят метрики и отвечают на SNMP-запросы
  2. Telegraf периодически опрашивает устройства по SNMP и отправляет данные в InfluxDB
  3. InfluxDB хранит временные ряды метрик
  4. Grafana запрашивает данные из InfluxDB и отображает дашборды

Telegraf — сборщик метрик

Что такое Telegraf

Telegraf — агент для сбора, обработки и отправки метрик. Поддерживает более 200 входных плагинов (inputs) и 50+ выходных (outputs).

Структура конфигурации

# Глобальные настройки агента
[agent]
interval = "60s" # Как часто собирать метрики
flush_interval = "60s" # Как часто отправлять в БД
hostname = "telegraf-server" # Имя хоста для тегов

# Куда отправлять данные
[[outputs.influxdb_v2]]
urls = ["http://influxdb:8086"]
token = "your-token"
organization = "myorg"
bucket = "network"

# Откуда собирать данные
[[inputs.snmp]]
agents = ["udp://192.168.1.1:161"]
version = 2
community = "public"

# Одиночные значения (scalars)
[[inputs.snmp.field]]
oid = "1.3.6.1.2.1.1.3.0"
name = "uptime"

# Таблицы (несколько значений с индексами)
[[inputs.snmp.table]]
name = "interface"
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.2"
name = "ifDescr"
is_tag = true # Сохранить как тег, не как значение

Ключевые концепции

Measurement — логическая группа метрик (аналог таблицы в SQL):

  • snmp — системные метрики устройства
  • interface — метрики интерфейсов

Fields — числовые значения метрик:

  • uptime = 219316700
  • ifInOctets = 29153382

Tags — строковые метки для фильтрации:

  • agent_host = "172.20.107.254"
  • ifDescr = "<l2tp-Tashkent_Oazis>"
  • hostname = "ccr-office"

Timestamp — время сбора метрики (наносекунды Unix epoch)

Формат данных (Line Protocol)

interface,agent_host=172.20.107.254,ifDescr=<l2tp-Tashkent_Oazis> ifInOctets=29153382,ifOperStatus=1 1770232095000000000
└───┬───┘ └────────────────────┬────────────────────────────────┘ └─────────────┬─────────────────┘ └────────┬────────┘
measurement tags fields timestamp

Тестирование конфигурации

# Проверить что Telegraf собирает
docker exec -it telegraf telegraf --config /etc/telegraf/telegraf.conf --test

# Вывод покажет собранные метрики:
> snmp,agent_host=172.20.104.253,hostname=ID-SW1 uptime=217262000u
> interface,agent_host=172.20.104.253,ifDescr=Ethernet1/0/1 ifInOctets=1755198811u,ifOperStatus=1i

InfluxDB — база данных временных рядов

Что такое InfluxDB

InfluxDB — специализированная база данных для хранения временных рядов (time series). Оптимизирована для:

  • Высокой скорости записи
  • Эффективного сжатия данных
  • Быстрых запросов по временным диапазонам

Основные понятия

Organization — логическая группировка ресурсов (как namespace)

Bucket — контейнер для данных с политикой хранения (retention policy)

Token — ключ доступа к API

Flux — язык запросов

Flux — функциональный язык запросов для InfluxDB 2.x. Использует pipe-forward оператор |> для построения цепочки преобразований.

Базовая структура запроса

from(bucket: "network")                    // 1. Источник данных
|> range(start: -1h) // 2. Временной диапазон
|> filter(fn: (r) => r._measurement == "interface") // 3. Фильтрация
|> filter(fn: (r) => r._field == "ifInOctets")
|> last() // 4. Агрегация

Основные функции Flux

Источник и диапазон:

from(bucket: "network")
|> range(start: -1h) // Последний час
|> range(start: -1h, stop: -30m) // От часа до 30 минут назад
|> range(start: v.timeRangeStart, stop: v.timeRangeStop) // Из Grafana

Фильтрация:

  |> filter(fn: (r) => r._measurement == "interface")
|> filter(fn: (r) => r.ifDescr =~ /l2tp/) // Regex
|> filter(fn: (r) => r._field == "ifInOctets" or r._field == "ifOutOctets")

Агрегация:

  |> last()                    // Последнее значение
|> first() // Первое значение
|> mean() // Среднее
|> sum() // Сумма
|> count() // Количество
|> min() / max() // Минимум / максимум

Группировка:

  |> group(columns: ["ifDescr"])          // Группировать по интерфейсу
|> group() // Убрать группировку (объединить всё)

Преобразование:

  |> pivot(rowKey: ["ifDescr"], columnKey: ["_field"], valueColumn: "_value")
// Превращает строки в столбцы (из длинного формата в широкий)

|> map(fn: (r) => ({ r with newField: r._value * 8 }))
// Создать новое поле

|> rename(columns: {oldName: "newName"})
// Переименовать столбец

|> keep(columns: ["ifDescr", "Status", "_value"])
// Оставить только указанные столбцы

|> drop(columns: ["_start", "_stop"])
// Удалить столбцы

Вычисление производных (для трафика):

  |> derivative(unit: 1s, nonNegative: true)
// Скорость изменения в секунду (байты/сек)

|> map(fn: (r) => ({ r with _value: r._value * 8.0 }))
// Конвертация в биты/сек

Работа со временем:

  |> map(fn: (r) => ({
r with
isStale: int(v: now()) - int(v: r._time) > 120000000000
// 120000000000 наносекунд = 2 минуты
}))

Примеры запросов

Получить статус всех L2TP туннелей:

from(bucket: "ideabuck")
|> range(start: -5m)
|> filter(fn: (r) => r._measurement == "interface")
|> filter(fn: (r) => r.ifDescr =~ /l2tp/)
|> filter(fn: (r) => r._field == "ifOperStatus")
|> last()

Подсчитать активные порты:

from(bucket: "ideabuck")
|> range(start: -5m)
|> filter(fn: (r) => r._measurement == "interface")
|> filter(fn: (r) => r._field == "ifOperStatus")
|> filter(fn: (r) => r.ifDescr =~ /Ethernet/)
|> last()
|> filter(fn: (r) => r._value == 1)
|> group()
|> count()

Трафик по портам в bits/sec:

from(bucket: "ideabuck")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "interface")
|> filter(fn: (r) => r._field == "ifInOctets")
|> derivative(unit: 1s, nonNegative: true)
|> map(fn: (r) => ({ r with _value: r._value * 8.0 }))

Таблица с несколькими полями (pivot):

from(bucket: "ideabuck")
|> range(start: -5m)
|> filter(fn: (r) => r._measurement == "interface")
|> filter(fn: (r) => r._field == "ifOperStatus" or r._field == "ifInOctets" or r._field == "ifOutOctets")
|> last()
|> pivot(rowKey: ["ifDescr"], columnKey: ["_field"], valueColumn: "_value")

Grafana — визуализация

Структура дашборда

Дашборд в Grafana — JSON-документ, содержащий:

{
"title": "SNR Switch Monitoring",
"uid": "unique-id",
"panels": [...], // Массив панелей
"templating": {...}, // Переменные дашборда
"time": { // Временной диапазон по умолчанию
"from": "now-1h",
"to": "now"
},
"refresh": "30s" // Автообновление
}

Типы панелей

Stat — одно большое число:

{
"type": "stat",
"title": "Active Ports",
"options": {
"colorMode": "value",
"graphMode": "none"
}
}

Time Series — график временного ряда:

{
"type": "timeseries",
"title": "Traffic",
"fieldConfig": {
"defaults": {
"unit": "bps" // bits per second
}
}
}

Table — таблица:

{
"type": "table",
"title": "Port Status",
"transformations": [
{ "id": "merge" } // Объединить фреймы
]
}

Структура панели

{
"type": "stat",
"title": "Switch Uptime",
"gridPos": { "h": 4, "w": 6, "x": 0, "y": 0 }, // Позиция и размер
"datasource": {
"type": "influxdb",
"uid": "datasource-uid"
},
"targets": [ // Запросы к данным
{
"query": "from(bucket: \"network\") |> ...",
"refId": "A"
}
],
"fieldConfig": { // Настройки отображения
"defaults": {
"unit": "dtdurations", // Формат: duration
"thresholds": {...}
},
"overrides": [...] // Переопределения для конкретных полей
},
"options": { // Специфичные настройки типа панели
"colorMode": "value"
}
}

Единицы измерения (units)

UnitОписаниеПример
bpsbits per second1.5 Mbps
Bpsbytes per second150 KB/s
decbytesbytes (decimal)1.5 GB
bytesbytes (binary)1.4 GiB
dtdurationsduration3 weeks
percentпроцент85%
noneбез единиц42

Value Mappings

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

{
"id": "mappings",
"value": [
{
"type": "value",
"options": {
"Up": {
"color": "green",
"text": "🟢 Up"
}
}
},
{
"type": "value",
"options": {
"Down": {
"color": "red",
"text": "🔴 Down"
}
}
}
]
}

Transformations

Преобразования данных на стороне Grafana:

  • Merge — объединить несколько фреймов в один
  • Organize fields — переупорядочить/переименовать столбцы
  • Filter by name — скрыть столбцы
  • Add field from calculation — вычисляемые поля

Практическое развёртывание

Docker Compose

version: '3.8'

services:
influxdb:
image: influxdb:2.7
container_name: influxdb
restart: unless-stopped
ports:
- "8086:8086"
volumes:
- influxdb_data:/var/lib/influxdb2

telegraf:
image: telegraf:latest
container_name: telegraf
restart: unless-stopped
volumes:
- ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro
depends_on:
- influxdb

grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
depends_on:
- influxdb

volumes:
influxdb_data:
grafana_data:

Порядок настройки

  1. Запустить стек:

    docker compose up -d
  2. Настроить InfluxDB:

    • Открыть http://localhost:8086
    • Создать пользователя, организацию, bucket
    • Сгенерировать API token
  3. Настроить Telegraf:

    • Создать telegraf/telegraf.conf
    • Указать token и bucket
    • Добавить SNMP agents
    • Перезапустить: docker compose restart telegraf
  4. Настроить Grafana:

    • Открыть http://localhost:3000 (admin/admin)
    • Добавить InfluxDB data source (Flux)
    • Импортировать или создать дашборд

Настройка SNMP на устройствах

SNR Switch:

  1. SNMP Configuration → SNMP management → SNMP Agent state: Open
  2. Community managers → добавить community string (например monitoring)
  3. Security IP state → Open (или добавить IP сервера мониторинга)

MikroTik:

/ip snmp set enabled=yes
/ip snmp community set 0 name=monitoring

Примеры конфигураций

Полный telegraf.conf

[agent]
interval = "60s"
flush_interval = "60s"

[[outputs.influxdb_v2]]
urls = ["http://influxdb:8086"]
token = "your-api-token"
organization = "idea"
bucket = "ideabuck"

# SNR Switch
[[inputs.snmp]]
agents = ["udp://172.20.104.253:161"]
version = 2
community = "monitoring"

[[inputs.snmp.field]]
oid = "1.3.6.1.2.1.1.3.0"
name = "uptime"

[[inputs.snmp.field]]
oid = "1.3.6.1.2.1.1.5.0"
name = "hostname"
is_tag = true

[[inputs.snmp.table]]
name = "interface"
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.2"
name = "ifDescr"
is_tag = true
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.8"
name = "ifOperStatus"
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.9"
name = "ifLastChange"
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.10"
name = "ifInOctets"
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.16"
name = "ifOutOctets"

# MikroTik Router
[[inputs.snmp]]
agents = ["udp://172.20.107.254:161"]
version = 2
community = "public"

[[inputs.snmp.field]]
oid = "1.3.6.1.2.1.1.3.0"
name = "uptime"

[[inputs.snmp.field]]
oid = "1.3.6.1.2.1.1.5.0"
name = "hostname"
is_tag = true

[[inputs.snmp.table]]
name = "interface"
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.2"
name = "ifDescr"
is_tag = true
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.8"
name = "ifOperStatus"
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.9"
name = "ifLastChange"
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.10"
name = "ifInOctets"
[[inputs.snmp.table.field]]
oid = "1.3.6.1.2.1.2.2.1.16"
name = "ifOutOctets"

Troubleshooting

SNMP не отвечает

# Проверить ping
ping 172.20.104.253

# Проверить SNMP
snmpwalk -v2c -c monitoring 172.20.104.253 1.3.6.1.2.1.1.1.0

# Если timeout — проблемы:
# 1. SNMP не включен на устройстве
# 2. Неправильный community string
# 3. Фильтрация по IP (Security IP state)
# 4. Firewall блокирует UDP 161

Telegraf не собирает метрики

# Тест конфигурации
docker exec -it telegraf telegraf --config /etc/telegraf/telegraf.conf --test

# Логи
docker logs telegraf

# Частые ошибки:
# "no such host" — неправильный IP или DNS
# "timeout" — нет сетевого доступа
# "authentication failure" — неправильный community

Данные не появляются в InfluxDB

# Проверить что bucket существует
# В InfluxDB UI: Data Explorer → выбрать bucket

# Проверить token
# Должен иметь права на запись в bucket

# Проверить логи Telegraf на ошибки записи
docker logs telegraf | grep -i error

Grafana не показывает данные

  1. Проверить Data Source → Test connection
  2. Проверить organization и bucket в настройках
  3. В панели → Query Inspector → посмотреть ошибки запроса
  4. Проверить временной диапазон (данные могут быть за другой период)

Панель показывает "No data"

  • Расширить временной диапазон
  • Проверить фильтры в запросе
  • Убедиться что measurement и field names совпадают с тем что присылает Telegraf

Таблица показывает один элемент вместо списка

  • Добавить transformation "Merge"
  • Проверить |> group() в конце Flux запроса

Полезные ссылки