2020-10 upd: we reached the first fundraising goal and rented a server in Hetzner for development! Thank you for donating !
Экспорт и отображение jail и bhyve метрик с CBSD, Grafana и Prometheus
Часто возникает потребность знать, насколько сильно и по каким компонентам ваши контейнера и виртуальные среды (в рамках этой статьи речь идет о FreeBSD jail(8) и bhyve(8) виртуальных машинах) потребляют ресурсы в различные моменты времени и иметь визуализацию этого в виде графиков. Основные метрики которые интересны в первую очередь это, как правило, базовые системные:
- CPU usage;
- Memory usage;
- Storage I/O bandwitch;
- Storage IOPS;
- Traffic bandwitch;
Источники информации по этим метрикам в FreeBSD ОС избыточны в том плане, что вы можете получать их из разных мест - потребление CPU можно считывать из bhyve, из фреймворка rctl(4), из утилиты top(1) и ps(1) (kvm_getprocs(3) в частности); информацию по I/O - через GEOM или 'zfs iostat', vmstat(8)/iostat(8); трафик - с утилиты netstat(1) или счетчиков ipfw(8) и pf(4) и т.д.
Скрипты CBSD могут собирать и накапливать данную статистику и предоставлять к ним интерфейс для дальнейшей обработки. В качестве примера, вы можете посмотреть информацию о получении трафика в CBSD для определенного контейнера: trafstat. В этой статье рассказывается, каким образом цифры можно экспортировать в графическое представление для более наглядной формы. Начиная с версии 11.1.0, CBSD позволяет экспортировать метрики с jrctl и trafstat утилит в унифицированном формате как для jail так и для bhyve в формате prometheus.
Настройка Prometheus
Итак, наши компоненты:
- FreeBSD как ОС общего пользования, на которой все и происходит;
- bhyve и jail как гипервизор и контейнера, в которых запускаются некие сервисы и метрику с которых мы будем снимать;
- CBSD - фреймворк управления bhyve и jail, позволяющий также выгрузить статистику по тому или иному гипервизору или контейнеру в формате prometheus;
- Prometheus - система сбора метрик в формате key-value pairs с возможностью делать выборку запросами, с эффективным движком хранения данных (leveldb), имеющую встроенную интеграцию с Grafana, а также, имеющая клиентские библиотеки для популярных языков программирования;
- Grafana - популярная и гибкая система Dashboard-ов с аналитикой и графиками по любым метрикам;
Получить информацию о загрузке виртуальной машины или контейнера по их имени в CBSD вы можете по команде 'cbsd jrctl'. Этот скрипт использует метрики, предоставляемые RACCT фреймворком, поэтому убедитесь, что ваш /boot/loader.conf имеет соответствующую настройку:
kern.racct.enable=1
По-умолчанию, 'cbsd jrctl' выводит информацию в формате ключ-значение:
% cbsd jrctl mode=show jname=f11 datasize=2080K stacksize=264K coredumpsize=0 memoryuse=63M memorylocked=0 maxproc=1 openfiles=40 vmemoryuse=1099M nthr=29 nsemop=0 wallclock=6206 pcpu=0 readbps=0 writebps=0 readiops=0 writeiops=0
Если аргумент jname= опустить, вы увидете информацию по всем имеющимся окружениям. Если данная команда вызвана с ключем prometheus=1, вывод будет осуществляться в том формате, который ожидают prometheus targets.
Экспортировать метрики в prometheus можно по-разному. Один из способов - отправлять метрику напрямую в prometheus используя любой комфортный для вас язык программирования, где имеется библиотека клиента prometheus.
Мы реализуем второй вариант, когда сервер prometheus будет сам обходить точки и собирать необходимую статистику. Для этого можно написать простенький демон, проксирующий вывод команды 'cbsd jrctl mode=show prometheus=1' на определенном tcp порту. Либо, чтобы избежать потенциальных проблем с безопасностью (вам нужно обезопасить этот демон от действий возможных злоумышленников, поскольку работа с командой 'cbsd' требует привелигированного пользователя) и перенаправить вывод 'cbsd jrctl' в промежуточный файл, который будет доступен на отдачу через любой WEB сервер, например NGINX.
Схематично, это может выглядеть следующим образом:
В качестве сборщика и генератора index.html файла может выступать написанный самостоятельно демон, либо скрипт вызываемый из cron, либо демонизированный sh-скрипт, который и описывается здесь.
Каждая нода будет экспортировать свои метрики по http://<FQDN>/rctl/ , задача prometheus - собрать статистику и показать grafana-е.
Prometheus и Grafana мы установим также в jail, для чего запустим диалог создания контейнера:
В качестве jname, введем произвольное имя, например: grafana
% cbsd jconstruct-tui
Остальные параметры меняем по своему усмотрению (если это необходимо) и нажимаем 'Go PROCEED!'
Зайдем в jail и установим пакеты prometheus и grafana:
% cbsd jstart grafana % cbsd jlogin grafana % pkg install -y net-mgmt/prometheus www/grafana4
Установим сервисы в автозагрузку:
% sysrc grafana_enable="YES" % sysrc prometheus_enable="YES"
Отредактируем конфигурационный файл /usr/local/etc/prometheus.yml:
global: scrape_interval: 15s evaluation_interval: 15s external_labels: monitor: 'codelab-monitor' rule_files: scrape_configs: - job_name: rctl metrics_path: /rctl/ static_configs: - targets: ['rctl.olevole.ru:80']
где:
- rctl.olevole.ru:80 - непосредственно FQDN нашего хостера и порт nginx, который мы сконфигурируем ниже.
- scrape_interval: 15s - интервал, с которым prometheus будет опрашивать метрики. Мы выбрали частоту в 15 секунд.
Запускаем сервисы:
% service grafana start % service prometheus start
и на этом с контейнером и настройкой сервисов - все.
Если вы не имеете доступ в контейнер напрямую, выполним на хостере команды для проброса необходимых портов:
% cbsd expose mode=add in=3000 jname=grafana % cbsd expose mode=add in=9090 jname=grafanaДалее напишем скрипт, который будет запускаться при старте сервера и через необходимый интервал времени будет регенирировать index.html файл с метриками на основе данных из 'cbsd jrctl'. Интервал времени логично ставить такой, с какой частотой забирает prometheus - ранее мы зафиксировали этот интервал в 15 секунд.
Сам скрипт может выглядеть следующим образом (скачать):
#!/bin/sh while getopts "r:i:" opt; do case "$opt" in r) root_dir="${OPTARG}" ;; i) interval="${OPTARG}" ;; esac shift $(($OPTIND - 1)) done export TMPDIR="${root_dir}" unset jname if [ -z "${root_dir}" ]; then echo "Empty root_dir, please use $0 -r path" exit 1 fi [ -z "${interval}" ] && interval="15" [ ! -d "${root_dir}" ] && mkdir -p ${root_dir} while [ true ]; do INDEX_OLD=$( readlink ${root_dir}/index.html ) INDEX_TMP=$( mktemp ) trap "/bin/rm -f ${INDEX_TMP}" HUP INT ABRT BUS TERM EXIT chmod 0644 ${INDEX_TMP} truncate -s0 ${INDEX_TMP} /usr/bin/lockf -s -t0 /tmp/cbsd-rctl.lock /usr/local/bin/cbsd jrctl mode=show prometheus=1 > ${INDEX_TMP} ln -sf ${INDEX_TMP} ${root_dir}/index.html rm -f ${INDEX_OLD} sleep ${interval} done
На входе скрипту через параметр -r мы задаем корневой каталог, в котором будем сохранять index.html, через аргумент -i - регулировать частоту обновления.
Как мы видим, скрипт работает в бесконечном цикле, вызывая команду статистики и засыпая на определенную нами паузу.
Поместим этот файл в каталог /root/bin под именем cbsdrctl: /root/bin/cbsdrctl и установим флаг исполнения:
% chmod +x /root/bin/cbsdrctl
Осталось создать rc.d-скрипт, который будет контроллировать запуск и останов /root/bin/cbsdrctl.
Напишем скрипт следующего содержания (скачать):
#!/bin/sh # # PROVIDE: cbsdrctl # REQUIRE: LOGIN FILESYSTEMS sshd # KEYWORD: shutdown # # cbsd_rctl_enable="YES" # . /etc/rc.subr name=cbsdrctl rcvar=cbsdrctl_enable load_rc_config $name start_cmd=${name}_start stop_cmd=${name}_stop status_cmd="${name}_status" restart_cmd=${name}_restart extra_commands="restart" # Set defaults : ${cbsdrctl_enable:="NO"} : ${cbsdrctl_interval:="15"} : ${cbsdrctl_root:="/tmp/metrics/rctl"} cbsdrctl_start() { if [ -r ${pidfile} ]; then echo "Already running: `cat ${pidfile}`" exit 0 fi /usr/sbin/daemon -f -p ${pidfile} /root/bin/cbsdrctl -r ${cbsdrctl_root} -i ${cbsdrctl_interval} echo "STARTED: -r ${cbsdrctl_root} -i ${cbsdrctl_interval}" } cbsdrctl_status() { if [ -f "${pidfile}" ]; then pids=$( pgrep -F ${pidfile} 2>&1 ) _err=$? if [ ${_err} -eq 0 ]; then echo "Running" else echo "Not running" fi else echo "Not running" fi } cbsdrctl_restart() { cbsdrctl_stop cbsdrctl_start } cbsdrctl_stop() { if [ -f "${pidfile}" ]; then pids=$( pgrep -F ${pidfile} 2>&1 ) _err=$? if [ ${_err} -eq 0 ]; then kill -9 ${pids} && /bin/rm -f ${pidfile} else echo "pgrep: ${pids}" return ${_err} fi fi } pidfile=/var/run/$name.pid run_rc_command "$1"
Сохраним этот скрипт как /usr/local/etc/rc.d/cbsdrctl и выдадим ему исполняемый флаг:
% chown root:wheel /usr/local/etc/rc.d/cbsdrctl % chmod 0555 /usr/local/etc/rc.d/cbsdrctl
Параметры интервала и рабочего каталога вынесены в переменные:
cbsdrctl_interval (значение по-умолчанию: 15)
cbsdrctl_root (значение по-умолчанию: /tmp/metrics/rctl)
Если эти значения вас не устраивают, вы можете переопределить через rc.conf:
% sysrc cbsdrctl_interval="15" % sysrc cbsdrctl_root="/tmp/metrics/rctl"
Установим скрипт как запускаемый:
% sysrc cbsdrctl_enable="YES"
И наконец, запустим:
% service cbsdrctl start
Настройка NGINX
Если в предыдущем шаге все получилось, в каталоге /tmp/metrics/rctl начнет обновлятся символическая ссылка index.html указывающая на файл с метрикой.
Нам необходимо настроить WEB сервер на отдачу этих файлов. Установим nginx на нашей ноде:
% pkg install -y nginx % sysrc nginx_enable=YES
Допишем в конфигурационный файл nginx /usr/local/etc/nginx/nginx.conf описание нашего виртуального хоста (в примере, FQDN сервера: rctl.olevole.ru)
server { listen 80; listen [::]:80; server_name rctl.olevole.ru; location /rctl { root /tmp/metrics; } }
И запустим NGINX.
% service nginx start
На данном этапе, при обращении на http://<FQDN>/rctl вы должны видеть содержимое файла /tmp/metrics/rctl/index.html
Проверяем работу
Мы можем убедится, что prometheus получает метрики корректно. Для этого откроем броузером интерфейс предоставляемый процессом prometheus на 9090 порту.
Напротив Execute в выпадающем списке будут все метрики, которые предоставляет CBSD. Если метрика относится к контейнеру, то метрика будет начинаться с префикса jail_, если это параметр виртуальной машины, то с bhyve_.
Осталось воспользоваться плодами работы в Grafana и создать отдельный Dashboard для наших виртуальных сред.
GRAFANA
Для работы с GRAFANA, отроем в броузере сервер на порту 3000. Инсталляция GRAFANA по-умолчанию имеет пользователя 'admin' с паролем 'admin':
На первом экране нам предлагают сконфигурировать различые компоненты: завести пользователя, добавить источники данных и добавить дополнительные плагины:
Поскольку мы получаем данные от prometheus, добавим соответствующий источник. В данном примере, поскольку prometheus работает в том же самом окружении что и grafana, мы можем устанавить значение url как http://localhost:9090. Нажимаем Save&Test и переходим к созданию первого графика.
Для добавления индивидуальной метрики, вы можете начать вводить его в поле Metric lookup. Здесь работает автодополнение и вам будет проще найти искомый параметр:
Изучите на man странице rctl, в каких мерах выдается статистика - в процентах, в байтах, bit/sec или попугаях и настраивайте метрику в соответствии с этой системой счисления:
Как мы видим, экспортировать доступные параметры как по jail, так и по bhyve достаточно легко. Новые сервера будут автоматически попадать в базу метрик и настроенные скрипты вам трогать уже не придется. В данном примере мы получаем метрику из FreeBSD RACCT и она доступна для снятия с каждого сервера по пути /rctl. Вы можете увеличивать и расширять метрики, например по пути /trafstat вы можете настроить метрики по трафику контейнеров, а по /billing настроить метрики с графикой тарификаций по потребляемым ресурсам. Данная работа ограничена только вашей фантазией и потребностью в информации о состоянии ваших систем и возможных трендах по утилизацию ресурсов. Информация позволяет вам держать руку на пульсе и заранее прогнозировать потенциальные проблемы и в случае с FreeBSD и CBSD - получить эту информацию можно достаточно легко.