Чтобы отслеживать состояние работающих приложений, необходимо проводить их постоянный мониторинг. А если приложения выполняются в таком хорошо масштабируемом окружении, как Docker Swarm, то потребуется также и хорошо масштабируемый инструмент мониторинга. В этой статье говорится о настройке именно такого инструмента.
В процессе работы мы установим агенты cAdvisor на каждой ноде для сбора метрик хоста и контейнеров. Метрики будут сохраняться в InfluxDB. Для построения графиков на основе этих метрик воспользуемся Grafana. Эти инструменты распространяются с открытым исходным кодом и могут быть развернуты в виде контейнеров.
Для построения кластера мы будем использовать Docker Swarm Mode и развернем необходимые сервисы в виде стека. Это позволит организовать динамическую систему мониторинга, которая способна автоматически начинать мониторинг новых нод по мере их добавления в рой (swarm). Файлы проекта можно найти здесь.
Обзор инструментов
Выбор систем мониторинга достаточно велик. Для построения нашего стека мы будем использовать хорошо работающие в контейнерах сервисы с открытым исходным кодом. Далее я опишу состав стека.
cAdvisor
cAdvisor будет собирать метрики хостов и контейнеров. Он устанавливается в виде docker-образа c подключенным в виде общего тома сокетом docker и корневой файловой системой на хосте. cAdvisor может записывать собираемые метрики в несколько видов баз данных временных рядов (time-series database), включая InfluxDB, Prometheus и т. д. У него даже есть веб-интерфейс, в котором по собранным данным строятся графики.
InfluxDB
Масштабируемое хранилище для метрик, событий и аналитики реального времени.
InfluxDB — это база данных временных рядов с открытым исходным кодом, которая позволяет хранить числовые метрики и назначать им теги. В этой системе реализован SQL-подобный язык запросов, который можно использовать для работы с хранимыми данными. События мы будем фильтровать с помощью тегов по хосту или даже контейнеру.
Grafana
Grafana — многофункциональная система с открытым исходным кодом, которая позволяет создавать панели инструментов и графики на основе метрик, получаемых из Graphite, Elasticsearch, OpenTSDB, Prometheus и InfluxDB.
Grafana — это популярный инструмент визуализации, который позволяет создавать панели инструментов, получая данные из Graphite, Elasticsearch, OpenTSDB, Prometheus и, конечно, InfluxDB. Начиная с четвертой версии появилась возможность настройки оповещений на основе результатов запросов. Мы создадим панель инструментов, с помощью которой можно будет вывести данные по конкретному хосту и сервису.
Docker Swarm Mode
Swarm Mode
появился в Docker начиная с версии 1.12.0. Он позволяет с легкостью создать из множества хостов рой (swarm) и без труда управлять им. Чтобы обеспечить работу встроенных механизмов обнаружения сервисов и оркестровки, в Swarm mode реализовано хранилище типа ключ-значение. Хосты могут выполнять роль менеджера (manager) или рабочего узла (worker). В общем случае менеджер отвечает за функцию оркестровки, а на рабочих узлах выполняются контейнеры. Поскольку это демонстрационная установка, мы разместим InfluxDB и Grafana на менеджере.
В Swarm Mode есть интересная функция маршрутная сетка (routing mesh), которая выполняет роль виртуального балансировщика нагрузки. Предположим, у нас есть 10 слушающих 80-й порт контейнеров, которые выполняются на 5 узлах. При попытке доступа к 80-у порту одного из этих контейнеров запрос может быть направлен любому из них, даже запущенному на другом хосте. Таким образом, опубликовав IP-адрес любой ноды, вы автоматически включаете балансировку запросов между десятью контейнерами.
Если вы планируете самостоятельно выполнить приведенные в этой демонстрации команды в своей системе, вам понадобятся следующие программы:
- Docker: версия >= 1.13 (для Docker Compose File версии 3 и Swarm Mode);
- Docker Machine: версия >= 0.8;
- Docker Compose: версия >= 1.10 (для Docker Compose File версии 3).
Рой будет состоять из трех локальных виртуальных машин, которые мы развернем с помощью docker-machine-плагина Virtualbox. Для этого у вас должна быть установлена система виртуализации Virtualbox. Используя другие плагины, можно развернуть виртуальные машины в облачных сервисах. Шаги после создания машин будут одинаковыми для всех плагинов. Более подробную информацию о docker-machine вы можете найти здесь.
При создании виртуальных машин мы оставим опции по умолчанию. Здесь размещена более подробная информация о доступных опциях. Хост, выполняющий функцию менеджера роя, назовем manager, а рабочие узлы — agent1 и agent2. Вы можете создать столько нод, сколько хотите. Просто повторите приведенные команды с другим именем хоста. Для создания виртуальной машины выполните следующие команды:
docker-machine create manager
docker-machine create agent1
docker-machine create agent2
На выполнение этих команд может потребоваться некоторое время. После создания машин вывод docker-machine ls
должен выглядеть примерно так:
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
agent1 - virtualbox Running tcp://192.168.99.101:2376 v17.03.1-ce
agent2 - virtualbox Running tcp://192.168.99.102:2376 v17.03.1-ce
manager - virtualbox Running tcp://192.168.99.100:2376 v17.03.1-ce
Для использования движка docker на хосте manager необходимо переключить контекст. Далее мы будем выполнять команды в docker, установленном на хосте manager, а НЕ в локальной системе. Для этого выполните команду:
eval `docker-machine env manager`
Теперь, когда мы переключились в docker на manager, инициализируем этот хост в качестве менеджера роя. Нам потребуется его IP, который будет опубликован на других подключаемых нодах. Команда docker-machine ip manager
позволяет получить необходимую информацию. Итак, для создания роя выполните следующую команду:
docker swarm init --advertise-addr `docker-machine ip manager`
Теперь нам нужно два рабочих узла. Для этого необходимо передать Join Token и IP, опубликованный при создании роя. Чтобы получить токен, выполните команду docker swarm join-token -q worker
. Команда docker-machine ip manager
, как и прежде, позволит получить IP менеджера и его стандартный порт 2377. Мы могли бы добавить новые машины в рой, по очереди переключаясь в контекст каждого рабочего узла, но гораздо проще выполнить эти команды по SSH. Для присоединения рабочих узлов к рою выполните следующие команды:
docker-machine ssh agent1 docker swarm join --token `docker swarm join-token -q worker` `docker-machine ip manager`:2377
docker-machine ssh agent2 docker swarm join --token `docker swarm join-token -q worker` `docker-machine ip manager`:2377
Список входящих в рой нод можно вывести командой docker node ls
. После добавления рабочих узлов вывод должен выглядеть так:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
3j231njh03spl0j8h67z069cy * manager Ready Active Leader
muxpteij6aldkixnl31f0asar agent1 Ready Active
y2gstaqpqix1exz09nyjn8z41 agent2 Ready Active
Docker Stack
С файлом docker-compose третьей версии в одном файле можно определить стек сервисов целиком, включая стратегию развертывания, и выполнить развертывание одной командой deploy. Основным отличием третьей версии файла docker-compose от второй стало появление параметра deploy в описании каждого сервиса. Этот параметр определяет способ развертывания контейнеров. Файл docker-compose для тестовой системы мониторинга приведен ниже:
version: '3'
services:
influx:
image: influxdb
volumes:
- influx:/var/lib/influxdb
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
grafana:
image: grafana/grafana
ports:
- 0.0.0.0:80:3000
volumes:
- grafana:/var/lib/grafana
depends_on:
- influx
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
cadvisor:
image: google/cadvisor
hostname: '{{.Node.ID}}'
command: -logtostderr -docker_only -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influx:8086
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
depends_on:
- influx
deploy:
mode: global
volumes:
influx:
driver: local
grafana:
driver: local
В нашем стеке 3 сервиса, которые описаны ниже.
influx
Здесь мы будем использовать образ influxdb. Для постоянного хранилища создадим том influx, который будет монтироваться в папку контейнера /var/lib/influxdb. Нам нужна только одна копия InfluxDB, которая будет размещена на хосте manager. Сервер docker запущен на этом же хосте, поэтому команды для контейнера могут выполняться здесь же. Поскольку обоим оставшимся сервисам нужна influxDB, мы добавим в описание этих сервисов ключ depends_on со значением influx.
grafana
Будем использовать образ grafana/grafana и пробросим 3000-й порт контейнера на 80-й порт хоста. Маршрутная сетка позволяет подключаться к grafana через 80-й порт любого хоста, входящего в рой. Для постоянного хранения данных создадим еще один том под названием grafana. Он будет монтироваться в папке контейнера /var/lib/grafana. Grafana также развернем на хосте manager.
cadvisor
Чтобы настроить cAdvisor, придется поработать чуть больше, чем с предыдущими сервисами. Более подробная информация доступна по этой ссылке. Выбор значения hostname в этом случае — задача непростая. Мы собираемся установить агенты на каждой ноде, и этот контейнер будет собирать метрики ноды и работающих на ней контейнеров. Когда cAdvisor посылает метрики в InfluxDB, он устанавливает тег machine, который содержит имя контейнера с cAdvisor. Его значение должно соответствовать ID ноды, на которой он запущен. В стеках Docker можно использовать шаблоны в именах. Более подробную информацию можно найти здесь. Мы дали контейнерам имена, содержащие ID ноды, на которой они запущены, и таким образом сможем определить, откуда пришла метрика. Это достигается использованием следующего выражения '{{.Node.ID}}'
.
Мы также добавим в cadvisor несколько параметров командной строки. Параметр logtostderr перенаправляет сгенерированные cadvsior логи в stderr, что упрощает отладку. Флаг docker_only говорит, что нас интересуют лишь контейнеры docker. Следующие три параметра определяют место в хранилище, где необходимо разместить собранные метрики. Мы попросим cAdvisor положить их в базу данных cadvisor на сервере InfluxDB, слушающем на influx:8086. Это позволит настроить отправку метрик на influx-сервис нашего стека. Внутри стека все порты открыты (exposed), поэтому их не нужно указывать отдельно.
Прописанные в файле тома нужны cAdvisor для сбора метрик с хоста и докера. Для развертывания cadvisor мы будем использовать режим global. Это даст уверенность, что на каждой ноде роя выполняется лишь один экземпляр сервиса cadvisor.
В конце файла у нас есть ключ volumes, в котором указаны тома influx и grafana. Поскольку оба тома будут размещены на хосте manager, для них мы пропишем драйвер local.
Для развертывания стека сохраните размещенный выше файл под именем docker-stack.yml и выполните следующую команду:
docker stack deploy -c docker-stack.yml monitor
Она запустит сервисы стека monitor. Первый запуск команды может занять некоторое время, поскольку ноды должны загрузить образы контейнеров. Вам также потребуется создать в InfluxDB базу данных для хранения метрик под названием cadvisor.
docker exec `docker ps | grep -i influx | awk '{print $1}'` influx -execute 'CREATE DATABASE cadvisor'
Выполнение команды может завершиться неудачей с сообщением, что контейнер influx не существует. Причина ошибки в том, что контейнер еще не готов. Подождите немного и выполните команду еще раз. Мы можем выполнять команды в сервисе influx, поскольку он запущен на хосте manager и мы используем установленный здесь docker. Чтобы выяснить ID контейнера с InfluxDB, можно воспользоваться командой docker ps | grep -i influx | awk '{print $1}'
, а для создания базы данных с именем cadvisor надо выполнить команду influx -execute 'CREATE DATABASE cadvisor'
.
Чтобы вывести список сервисов стека, выполните docker stack services monitor
. Вывод команды будет выглядеть примерно так:
ID NAME MODE REPLICAS IMAGE
0fru8w12pqdx monitor_influx replicated 1/1 influxdb:latest
m4r34h5ho984 monitor_grafana replicated 1/1 grafana/grafana:latest
s1yeap330m7e monitor_cadvisor global 3/3 google/cadvisor:latest
Список запущенных контейнеров можно получить командной docker stack ps monitor
, вывод которой будет примерно таким:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
n7kobaozqzj6 monitor_cadvisor.y78ac29r904m8uy6hxffb7uvn google/cadvisor:latest agent2 Running Running about a minute ago
1nsispop3hsu monitor_cadvisor.z52c9vloiutl5dbuj5lnykzvl google/cadvisor:latest agent1 Running Running about a minute ago
9n6djc80mamd monitor_cadvisor.qn82bfj5cpin2cpmx9qv1j56s google/cadvisor:latest manager Running Running about a minute ago
hyr8piriwa0x monitor_grafana.1 grafana/grafana:latest manager Running Running about a minute ago
zk7u8g73ko5w monitor_influx.1 influxdb:latest manager Running Running about a minute ago
Настройка Grafana
После того как все сервисы развернуты, можно открыть grafana. Для этого подойдет IP любой ноды роя. Мы укажем IP менеджера, выполнив следующую команду:
open http://`docker-machine ip manager`
По умолчанию для входа в grafana используются имя пользователя admin и пароль admin. В grafana в качестве источника данных надо добавить InfluxDB. На домашней страничке должна быть ссылка Create your first data source, кликните по ней. Если ссылки нет, выберите из меню Data Sources пункт Add data source, который откроет форму добавления нового Data Source.
Добавление Data Source в Grafana
Источнику данных можно дать любое имя. Поставьте галку в чекбоксе default, чтобы в дальнейшем не приходилось указывать его в других формах. Далее установим Type равным InfluxDB, URL — http://influx:8086 и Access — proxy. Таким образом мы указали на наш InfluxDb-контейнер. В поле Database введите cadvisor и нажмите Save and Test — должно появиться сообщение Data source is working.
В github-репозитории проекта есть файл dashboard.json, созданный для импорта в Grafana. В нем описана панель инструментов мониторинга систем и контейнеров, которые выполняются в рое. Сейчас мы только импортируем эту панель инструментов, а поговорим о ней в следующем разделе. Наведите курсор на пункт меню Dashboards и выберите Import Option. Нажмите кнопку Upload .json file и выберите dashboard.json. Далее выберите источник данных и нажмите кнопку Import.
Grafana Dashboard
Grafana Dashboard
Импортированная в Grafana панель инструментов предназначена для мониторинга хостов и контейнеров роя. Вы можете детализировать отчет до уровня хоста и выполняющихся на нем контейнеров. Нам понадобятся две переменные, для добавление которых в панель инструментов Grafana необходима функциональность работы с шаблонами. Более подробная информация о работе с шаблонами в связке с InfluxDB — на этой странице. У нас есть две переменные: host для выбора ноды и container для выбора контейнера. Чтобы увидеть эти переменные, на странице панели инструментов выберите Settings и нажмите Templating.
Первая переменная — host — позволяет выбрать ноду и ее метрики. Когда cAdvisor отправляет метрики в InfluxDB, он присоединяет к ним несколько тегов, которые можно использовать для фильтрации. У нас есть тег под названием machine, который содержит имя хоста (hostname) экземпляра cAdvisor. В данном случае он будет соответствовать ID хоста в рое. Для получения значений тега используется запрос show tag values with key = "machine"
.
Вторая переменная — container — позволяет детализировать отчет до уровня контейнера. У нас есть тег с именем container_name, в котором вполне предсказуемо содержится имя контейнера. Нам также надо фильтровать метрики по значению тега host. Запрос будет выглядеть следующим образом: show tag values with key = "container_name" WHERE machine =~ /^$host$/
. Он вернет нам список контейнеров, у которых переменная host содержит имя интересующего нас хоста.
Имя контейнера будет выглядеть примерно так:
monitor_cadvisor.y78ac29r904m8uy6hxffb7uvn.3j231njh03spl0j8h67z069cy. Мы, однако, заинтересованы только в его monitor_cadvisor-части (до первой точки). Если запущено несколько экземпляров одного сервиса, их данные нужно будет выводить в отдельных строках. Чтобы получить подстроку до первой точки, применим регулярное выражение /([^.]+)/
.
Переменные мы настроили, теперь можем использовать их в графиках. Далее разговор пойдет о графике Memory, а с остальными можно работать по такому же принципу. Данные, относящиеся к памяти, находятся в InfluxDB в ряде memory_usage, поэтому запрос будет начинаться с SELECT "value" FROM "memory_usage"
.
Теперь надо добавить фильтры в выражение WHERE. Первым условием будет равенство machine значению переменной host: "machine" =~ /^$host$/
. В следующем условии container_name должен начинаться со значения переменной container. Здесь мы воспользуемся оператором «начинается с», поскольку отфильтровали переменную container до первой точки: "container_name" =~ /^$container$*/
. Последние условие накладывает ограничение на время событий в соответствии с временным интервалом $timeFilter, выбранным в панели инструментов grafana. Запрос теперь выглядит так:
SELECT "value" FROM "memory_usage" WHERE "container_name" =~ /^$container$*/ AND "machine" =~ /^$host$/ AND $timeFilter
Поскольку нам нужны отдельные строки для разных хостов и контейнеров, необходимо сгруппировать данные на основе значений тегов machine и container_name:
SELECT "value" FROM "memory_usage" WHERE "container_name" =~ /^$container$*/ AND "machine" =~ /^$host$/ AND $timeFilter GROUP BY "machine", "container_name"
Мы также создали alias для этого запроса: Memory {host: $tag_machine, container: $tag_container_name}
. Здесь $tag_machine будет замещен значением тега machine, а tag_container_name — значением тега container_name. Остальные графики настраиваются похожим образом, меняются только имена рядов (series). Для этих метрик в Grafana можно создать предупреждения. Более подробную информацию о системе предупреждений (Alerting) см. здесь.
Заключение
В этой статье мы создали масштабируемую систему мониторинга для Docker Swarm, которая в автоматическом режиме собирает метрики со всех хостов и контейнеров, входящих в рой. В процессе работы мы познакомились с популярными инструментами с открытым исходным кодом: Grafana, InfluxDB и cAdvisor.
После завершения работы с демонстрацией стек может быть удален командной:
docker stack rm monitor
Ненужные виртуальные машины останавливаются и удаляются командами:
docker-machine stop manager agent1 agent2
docker-machine rm -f manager agent1 agent2
Ссылки:
Комментарии (4)
SicYar
03.05.2017 10:31Не холивара ради, но почему cAdvisor, а не Consul? Так же метрики, вэб-мордашка, запуск в контейнере ну и т.д.
sequence
Связка cadvisor + docker + aufs бомба замедленного действия для вашего окружения. Причина критичный баг двухлетней выдержки. Будьте осторожны, если вдруг ваш интерес не ограничится песочницей.
ZloyRabadaber
не подскажите в какую сторону смотреть, чтобы обойти этот баг?
sequence
storage-driver: overlay2, с ним проблемы вроде нет.
В любом случае применять cadvisor далее тестовых сред я бы не стал.