Promethues оповещение через Telegram.
Tue 21 February 2023Расскажу про alert систему promethues и оповещение через telegram. На заре прометея с оповещениями было прямо сложно. Нужно было что-то костылить и использовать сторонние инструменты. Единственное, что хорошо работало из коробки это email и slack. Но в большинстве случаев все это не требуется, а хочется просто получать сообщения в telegram. С недавнего времени, прометей умеет наконец, работать с телеграм из коробки. Об этом ниже. Итак, делаем оповещение в телеграм черезе нативный драйвер прометея.
Создаем следующий docker-compose.yml
version: "3.9"
services:
prometheus:
image: prom/prometheus
container_name: prometheus
hostname: prometheus
restart: always
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./alert.rules:/etc/prometheus/alert.rules
environment:
TZ: "Europe/Moscow"
ports:
- 9090:9090
alertmanager:
image: prom/alertmanager
container_name: alertmanager
hostname: alertmanager
restart: always
ports:
- 9093:9093
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
command:
- '--config.file=/etc/alertmanager/alertmanager.yml'
Для работы нам нужно так же создать файл конфигурации самого прометея prometheus.yml, правила срабатывания тригеров, ну или сами триггеры если хотите alert.rules, а так же конфигурацию alertmanager-а, alertmanager.yml.
prometheus.yml
global:
scrape_interval: 5s
scrape_timeout: 5s
evaluation_interval: 5s
alerting:
alertmanagers:
- scheme: http
static_configs:
- targets:
- "alertmanager:9093"
rule_files:
- "alert.rules"
scrape_configs:
- job_name: alert_exporter
scrape_interval: 5s
static_configs:
- targets:
- "alert_exporter:9000"
alert.rules
groups:
- name: Тестовый счетчик получил значение 0
rules:
- alert: Значение тестового счетчика равно 0.
expr: randome_value == 0
for: 5s
labels:
severity: page
- name: Тестовый счетчик получил значение больше 10
rules:
- alert: Значение тестовго счетчика больше либо равно 10.
expr: randome_value >= 10
for: 5s
labels:
severity: critical
annotations:
summary: Значение тестовго счетчика больше либо равно 10.
- name: Тестовый счетчик получил значение больше 5
rules:
- alert: Значение тестовго счетчика больше либо равно 5.
expr: randome_value >= 5
for: 5s
labels:
severity: critical
annotations:
summary: Значение тестовго счетчика больше либо равно 5.
- name: Тестовый счетчик получил значение больше 3
rules:
- alert: Значение тестовго счетчика больше либо равно 3.
expr: randome_value >= 10
for: 5s
labels:
severity: critical
annotations:
summary: Значение тестовго счетчика больше либо равно 3.
alertmanager.yml
global:
resolve_timeout: 10s
route:
group_by: ['alertname']
group_wait: 3s
receiver: 'telegram_bot'
receivers:
- name: 'telegram_bot'
telegram_configs:
- bot_token: 'YOUR_TOKEN_HERE'
api_url: 'https://api.telegram.org'
chat_id: YOUR_CHAT_ID
parse_mode: 'HTML'
Что бы потестировать оповещения, я написал небольшой экспортер на python, который генерирует рандомное число, по этому числу написаны правила в файле alert.rules, как видите там только числа, но этого достаточно что бы понять как это работает. Возможно, вы так же как и я, захотите потестировать это. По этому я приведу листинг экспортера:
from prometheus_client import start_http_server, Gauge
import random
import time
def get_random_value():
random_value_list = ['1', '2', '3', '4', '10', '20', '0']
return random.choice(random_value_list)
prometheus_metric_value = Gauge('randome_value', 'Get randome value from list')
if __name__ == '__main__':
start_http_server(9000)
while True:
prometheus_metric_value.set(get_random_value())
time.sleep(120)
И на всякий случай, Dockerfile для этого экспортера, плюс блок для docker-compose.
FROM python:3.9-alpine
WORKDIR .
ADD alert_exporter.py .
RUN pip install prometheus-client
CMD ["python", "/alert_exporter.py"]
alert_exporter:
build: ./src
container_name: alert_exporter
hostname: alert_exporter
restart: always
ports:
- 9000:9000
Теперь вы можете запустить весь стек, если необходимо в экспортере можно заменить время ожидания
до следующей генерации числа: time.sleep(120)
, по умолчанию это 2 минуты, время можно уменьшить
что бы срабатывания триггеров было быстрее.
При этом вывод в телеграм канал, выглядит так:
В целом это удовлетворит требования многих пользователей, но мне захотелось пойти чуть дальше и изобрести свой велосипед. Prometheus дает прекрасную возможность использовать свое API, через которое вы можете получать статус и всю необходимую информацию.
Вывод при отсутствии триггеров:
>>> curl http://127.0.0.1:9090/api/v1/alerts
{
"status": "success",
"data": {
"alerts": []
}
}
Вывод при активных триггерах:
>>> curl http://127.0.0.1:9090/api/v1/alerts | jq
{
"status": "success",
"data": {
"alerts": [
{
"labels": {
"alertname": "Значение тестовго счетчика больше либо равно 5.",
"instance": "alert_exporter:9000",
"job": "alert_exporter",
"severity": "critical"
},
"annotations": {
"summary": "Значение тестовго счетчика больше либо равно 5."
},
"state": "firing",
"activeAt": "2023-02-21T09:28:04.540123176Z",
"value": "2e+01"
},
{
"labels": {
"alertname": "Значение тестовго счетчика больше либо равно 3.",
"instance": "alert_exporter:9000",
"job": "alert_exporter",
"severity": "critical"
},
"annotations": {
"summary": "Значение тестовго счетчика больше либо равно 3."
},
"state": "firing",
"activeAt": "2023-02-21T09:28:06.596726863Z",
"value": "2e+01"
},
{
"labels": {
"alertname": "Значение тестовго счетчика больше либо равно 10.",
"instance": "alert_exporter:9000",
"job": "alert_exporter",
"severity": "critical"
},
"annotations": {
"summary": "Значение тестовго счетчика больше либо равно 10."
},
"state": "firing",
"activeAt": "2023-02-21T09:28:02.404178541Z",
"value": "2e+01"
}
]
}
}
Почему я решил изобретать велосипед? Хотя бы просто потому что я могу сам формировать вывод сообщений в телеграм, шаблонизировать вывод, возможность интеграции с другими каналами связи которые ещё не интегрировали в prometheus. Мой небольшой скрипт для отправки оповещений в телеграм:
import urllib.request
import json
import time
import requests
prometheus_url = 'http://127.0.0.1:9090'
bot_token = "YOUR_TOKEN"
bot_chatID = "YOUR_CHAT_ID"
def tg_bot(bot_message):
send_text = "https://api.telegram.org/bot" + bot_token + "/sendMessage?chat_id=" + bot_chatID + "&parse_mode=HTML&text=" + bot_message
response = requests.get(send_text)
return response.json()
def get_data(api):
with urllib.request.urlopen(prometheus_url + '/api/v1/' + api) as url:
data = json.load(url)
return data
def get_alert_status():
data = get_data('rules')
alert_state = 0
for item in data['data']['groups']:
for state in item['rules']:
if state['state'] == 'firing':
alert_state += 1
return alert_state
def get_alerts_message():
data = get_data('alerts')
msg = ''
if data['data']['alerts']:
for items in data['data']['alerts']:
msg += '\nMessage: ' + items['labels']['alertname'] + '\n\n<i>' + \
'Host: ' + items['labels']['instance'] + '\n' + \
'Job: ' + items['labels']['job'] + '\n' + \
'Status: ' + items['labels']['severity'] + '\n</i>'
return msg
switch_state = None
while True:
try:
if get_alert_status() >= 1 and switch_state != 1:
tg_bot('<b>Alerts!</b>\n' + get_alerts_message())
switch_state = 1
if get_alert_status() == 0 and switch_state != 0:
tg_bot('<b>No alerts now!</b>')
switch_state = 0
time.sleep(5)
except:
print('Can`t connect to prometheus... Next try attempt for 30s')
time.sleep(30)
Вывод в телеграм будет выглядеть так:
Как обычно, весь код можно взять в репозиториях:
Home »