
Содержание статьи
Люк Рассел
В данном руководстве описан подход к созданию простого бота ChatOps, использующего Slack и Grafana для запроса состояния системы. Идея состоит в том, чтобы иметь возможность проверить состояние вашей системы с помощью разговорного интерфейса, если вы не за рабочим столом, но все еще имеете базовое подключение, например, на своем телефоне:

Учебник разделен на две части: первая часть настроит инфраструктуру для мониторинга Kafka с помощью Prometheus и Grafana, а вторая часть создаст простого бота из Python, который может отвечать на вопросы и возвращать графики Grafana через Slack.
Уведомление является родной функцией Grafana, то есть возможность отправлять уведомления на канал Slack, если условия нарушены. Бот Slack – это немного другой инструмент. Он сможет ответить на простые вопросы о состоянии системы, чтобы помочь с устранением неисправностей.
Цель состоит в том, чтобы разработать что-то, работающее внутри брандмауэра, без доступа к прокси-серверу или доступа к любым сторонним службам, таким как Amazon S3. Поэтому изображения графов генерируются в локальной файловой системе и загружаются как вложенные файлы в Slack во избежание размещения в публичной инфраструктуре.

компоненты
Основными компонентами здесь являются:
Кафка: Платформа потоковой передачи сообщений. Это система, которую мы заинтересованы контролировать.
Прометей: система мониторинга для сбора показателей через заданные промежутки времени, оценки правил и запуска предупреждений.
prometheus-jmx-exporter: Сборник Prometheus, который может очищать и открывать данные JMX, что позволяет собирать показатели от Kafka.
Графана: Платформа визуализации, обычно используемая для визуализации данных временных рядов для аналитики инфраструктуры и программ. Это позволяет графически отображать собранные показатели.
Томно: программа обмена сообщениями, которая позволит нам взаимодействовать с нашим чат-ботом.
Слак бот: Описанный во второй части ниже простой скрипт Python, который может получать графики из Grafana и загружать их в Slack.
Эти шаги основаны на мониторинге Kafka, но тот же общий подход применим для интеграции с другими службами.
Давайте начнем
Полный исходный код доступен здесь.
предпосылки
- Базовые знания Python: код, написанный для Python 3.6.
- Docker: docker-compose используется для запуска брокера Kafka.
- kafkacat: это полезный инструмент для взаимодействия с Kafka (например, публикация сообщений по темам)
Если вы спешите все запустить, просто клонируйте проект по ссылке выше и запустите docker-compose up -d
.
Остаток этого руководства состоит из двух частей. В первой части описано, как настроить инфраструктуру мониторинга, а во второй описан код Python для бота Slack.
Часть первая: Соберите стек мониторинга
Мы используем Grafana и Prometheus, чтобы настроить стек мониторинга. Сервисом, который будет отслеживаться, является Kafka, что означает, что нам понадобится мост для экспорта данных JMX из Kafka в Prometheus. Этот образ докера prometheus-jmx-exporter отлично выполняет эту роль. Эта служба извлекает показатели из JMX-сервера Kafka и предоставляет их через HTTP, чтобы Prometheus мог их опрашивать.
Чтобы включить метрику JMX на сервере Kafka, нам нужно применить некоторые настройки конфигурации к серверу Kafka и связать kafka-jmx-exporter
контейнер с сервером Kafka:
- Обеспечить
KAFKA_JMX_OPTS
иJMX_PORT
переменные среды устанавливаются на Кафка контейнер - Обеспечить kafka-jmx-exporter и Кафка контейнеры находятся в одной сети (
backend
) - Обеспечить
JMX_HOST
значение для kafka-jmx-exporter контейнер отвечаетKAFKA_ADVERTISED_HOST_NAME
на Кафка контейнер - Обеспечить
KAFKA_ADVERTISED_HOST_NAME
имеет соответствующую запись в/etc/hosts
. - Pin
wurstmeister/kafka
к версии1.0.0
. Может возникнуть проблема с настройкой JMX с предыдущими версиямиwurstmeister/kafka
изображение - Pin
prom/prometheus
к версииv2.0.0
- Для этого обновления требуется одно изменение совместимости, а именно переименование
target_groups
кstatic_configs
вprometheus.yml
файл.
Полученные разделы docker-compose.yml должны выглядеть следующим образом:
kafka:
image: wurstmeister/kafka:1.0.0
ports:
- "9092:9092"
- "1099:1099"
depends_on:
- zookeeper
environment:
- KAFKA_ADVERTISED_PORT=9092
- KAFKA_BROKER_ID=1
- KAFKA_ZOOKEEPER_CONNECT=zookeeper
- KAFKA_ADVERTISED_HOST_NAME=kafka
- ZOOKEEPER_CONNECTION_TIMEOUT_MS=180000
- KAFKA_CREATE_TOPICS=transactions:1:1
- KAFKA_JMX_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=kafka -Dcom.sun.management.jmxremote.rmi.port=1099
- JMX_PORT=1099
networks:
- backend
kafka-jmx-exporter:
build: ./prometheus-jmx-exporter
ports:
- "8080:8080"
links:
- kafka
environment:
- JMX_PORT=1099
- JMX_HOST=kafka
- HTTP_PORT=8080
- JMX_EXPORTER_CONFIG_FILE=kafka.yml
networks:
- backend
prometheus:
ports:
- 9090:9090/tcp
image: prom/prometheus:v2.0.0
volumes:
- ./etc:/etc/prometheus
- prometheus_data:/prometheus
links:
- kafka-jmx-exporter
restart: always
networks:
- backend
Grafana можно настроить для чтения файла информационной панели JSON при запуске – такой файл предоставляется в etc/Kafka.json
предварительно сконфигурированный с образцом информации мониторинга Kafka.
Запустите стек мониторинга
Если все настроено должным образом, вы сможете начать стек docker-compose up -d
. Затем отправьте несколько сообщений Кафцы с помощью kafkacat:
for i in `seq 1 3`;
do
echo "hello" | kafkacat -b kafka:9092 -t transactions
done
Просмотрите информационную панель Kafka по адресу, и вы увидите что-нибудь вроде этого:

Часть вторая: Создание Slack Bot
Имея инфраструктуру мониторинга, теперь мы можем написать наш простой бот Slack. В этом разделе описаны этапы создания бота и некоторые фрагменты кода.
Первым шагом является создание и регистрация бота на веб-сайте Slack.
На следующем экране можно настроить детали, например добавить значок и описание для бота.
Когда ваш бот будет создан, пригласите его куда-нибудь. Вы можете создать частный канал для тестирования:

Затем пригласите бота на тестовый канал с помощью /invite @handy_bot
:

Наш бот ответит на несколько простых вопросов, на которые мы определимся строки 1–3:
self.respond_to = ['list graph shortcuts',
'graph <shortcut>',
'help']
self.help_msg = '```\n'
for answer in self.respond_to:
self.help_msg += f'{answer}\n'
self.help_msg += '```'
в app.py
мы прочтем наш конфигурационный файл и запустим бота:
def main(arguments=None):
if not arguments:
arguments = docopt(__doc__)
config = configure(arguments['--config-file'])
mybot = SlackBot(config)
mybot.start()
The start
способ выглядит так:
def start(self):
if self.slack_client.rtm_connect():
print("Bot is alive and listening for messages...")
while True:
events = self.slack_client.rtm_read()
for event in events:
if event.get('type') == 'message':
# If we received a message, read it and respond if necessary
self.on_message(event)
time.sleep(1)
линия 2: создает подключение к Slack API
строка 5: на заданной частоте опроса (1 секунда) проверить наличие новых событий
строка 7: если событие является сообщением, перейдите к on_message
метод, и если мы получим ответ от этого метода, распечатаем его на канал, на котором было опубликовано сообщение:
def on_message(self, event):
...
full_text = event.get('text', '') or ''
if full_text.startswith(self.bot_id):
question = full_text[len(self.bot_id):]
if len(question) > 0:
question = question.strip().lower()
channel = event['channel']
...
elif 'graph' in question:
self.respond(channel, 'Please wait...', True)
The on_message
метод, где мы решим как реагировать на сообщения, которые получает бот. The generate_and_upload_graph
метод является наиболее интересным ответом. Идея состоит в том, чтобы запустить временный контейнер Docker, чтобы сделать снимок экрана.
Grafana имеет возможность отобразить любой график в формате PNG. Однако в последнем выпуске Grafana есть ошибка phantomjs библиотеки, которая используется внутренне для создания изображений.
Более надежной утилитой для безголового просмотра является Puppeteer, основанный на Google Chrome, и кто-то уже завернул это в образ Docker. Это дает нам возможность экспериментировать с API Docker Python:
def generate_and_upload_graph(self, filename, url, channel):
dir_name = os.path.dirname(os.path.abspath(__file__))
client = docker.APIClient()
container = client.create_container(
image="alekzonder/puppeteer:1.0.0",
command=f'screenshot \'{url}\' 1366x768',
volumes=[dir_name],
host_config=client.create_host_config(binds={
dir_name: {
'bind': '/screenshots'
}
}, network_mode="host")
)
files1 = prepare_dir(dir_name)
client.start(container)
# Poll for new files
while True:
time.sleep(2)
files2 = os.listdir(dir_name)
new = [f for f in files2 if all([f not in files1, f.endswith(".png")])]
for f in new:
with open(f, 'rb') as in_file:
ret = self.slack_client.api_call(
"files.upload",
filename=filename,
channels=channel,
title=filename,
file=io.BytesIO(in_file.read()))
if 'ok' not in ret or not ret['ok']:
print('File upload failed %s', ret['error'])
os.remove(f)
break
строки 6:16: используйте API Docker Python для динамического создания контейнера на основе alekzonder/puppeteer
изображение
строка 13: привязывает текущий каталог к /screenshots
в контейнере, чтобы мы могли записать файл в доступное место
строка 15: наборы network_mode=host
чтобы контейнер мог получить доступ к Grafana на локальном хосте
строки 23:38 будет наблюдать за добавлением новых изображений в каталог и загружать их
Запустите бота
Когда стек мониторинга запущен, вы можете запустить бота. от slackbot
каталог:
$ python bot.py --config=config.yaml
Bot is alive and listening for messages...
Бот может отвечать на несколько основных запросов, как показано ниже, и вы, конечно, можете адаптировать возможности бота к конкретным системам, которые вы хотите контролировать.

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