Prometheus: запуск сервера с Alertmanager, cAdvisor и Grafana

Автор: | 07/12/2017

Пример установки и настройки минимального мониторинга, чисто ознакомительного.

Используем Pormetheus для сбора метрик, Alertmanager для отправки сообщений о проблемах, cAdvisor для сбора метрик из Docker, node-exporter для сбора метрик с виртуальной машины и Grafana – для визуализации собранных данных, а запускать всё будем из Docker Compose.

Все получившиеся в результате конфиги можно посмотреть в репозитории.

На хосте мониторинга, prometheus-server, будут:

  • сам promeheus сервер
  • grafana
  • node-exporter
  • cadvisor
  • alertmanager

Хост, который будем мониторить, prometheus-client:

  • node-exporter
  • cadvisor

Далее выполним настройку первого стека для Prometheus:

  • запустим две ВМ – сервер и “клиент”
  • на сервере выполним установку NGINX
  • установку Docker и Docker Compose
  • создадим Compose файл для запуска Prometheus сервера
  • добавим Grafana
  • настроим NGINX для проксирования трафика к Grafana и Prometheus
  • добавим node-exporter, cAdvisor и Alertmanager
  • добавим дашборды в Grafana
  • и алерты в Alertmanager с отправкой уведомлений на почту

Второй Compose для клиента будет включать в себя:

  • cAdvisor
  • node-exporter

Вроде всё? Поехали.

Virtualbox

Делать всё будем в Virtualbox, запускаем две машины, сначала сервер:

[simterm]

$ VBoxManage createvm --name "prometheus-server" --register
Virtual machine 'prometheus-server' is created and registered.
UUID: 351d503f-3790-4d94-be12-6cf0c295234d
Settings file: '/home/setevoy/VirtualBox VMs/prometheus-server/prometheus-server.vbox'

[/simterm]

Меняем настройки сети машины – устанавливаем сетевой интерфейс в bridge и включаем его:

[simterm]

$ VBoxManage modifyvm "prometheus-server" --nic1 bridged --bridgeadapter1 enp0s25 --nictype1 82540EM --cableconnected1 on

[/simterm]

Указываем тип ОС:

[simterm]

$ VBoxManage modifyvm "prometheus-server" --ostype Debian_64

[/simterm]

Создаём диск:

[simterm]

$ cd /home/setevoy/VirtualBox\ VMs/prometheus-server/
$ VBoxManage createhd --filename prometheus-server.vdi --size 10000

[/simterm]

Добавляем IDE контроллер к машине:

[simterm]

$ VBoxManage storagectl "prometheus-server" --name "IDE Controller" --add ide

[/simterm]

Подключаем диск:

[simterm]

$ VBoxManage storageattach "prometheus-server" --storagectl "IDE Controller"  --port 0 --device 0 --type hdd --medium prometheus-server.vdi

[/simterm]

Устанавливем 2 гига памяти:

[simterm]

$ VBoxManage modifyvm prometheus-server --memory 2048

[/simterm]

Подключаем ISO с Debian:

[simterm]

$ VBoxManage storageattach "prometheus-server" --storagectl "IDE Controller" --port 1 --device 0 --type dvddrive --medium /home/setevoy/OS/debian-9.2.1-amd64-netinst.iso

[/simterm]

Запускаем машину:

[simterm]

$ VBoxManage startvm prometheus-server

[/simterm]

Аналогично – создаём машину prometheus-client, устанавливаем ОС:

Подготовка

Обвновляем всё на обоих хостах, сервере и клиенте:

[simterm]

# apt update && apt upgrade

[/simterm]

На сервере устанавливаем NGINX:

[simterm]

# apt install -y nginx curl vim

[/simterm]

На сервере и клиенте устанавливаем Docker:

[simterm]

# curl https://get.docker.com/ | bash

[/simterm]

И Docker Compose:

[simterm]

# curl -o /usr/local/bin/docker-compose -L "https://github.com/docker/compose/releases/download/1.17.1/docker-compose-$(uname -s)-$(uname -m)"
# chmod +x /usr/local/bin/docker-compose

[/simterm]

На хосте, на котором запущены обе виртуальные машины (рабочий ноут) – добавим две записи в /etc/hosts:

[simterm]

13:08:58 [setevoy@setevoy-arch-work ~]  $ sudo sh -c "echo '10.11.100.166 prometheus-server.local' >> /etc/hosts"
13:10:12 [setevoy@setevoy-arch-work ~]  $ sudo sh -c "echo '10.11.100.167 prometheus-client.local' >> /etc/hosts"

[/simterm]

Prometheus стек

Prometheus сервер

Теперь можно приступать к запуску сервисов, начинаем с хоста prometheus-server.local, клиент настроим в самом конце.

Создаём каталоги для хранения данных:

[simterm]

# mkdir -p /data/monitoring/{prometheus-server,grafana}

[/simterm]

Первым запустим сам Prometheus сервер, создаём Compose файл:

version: '3.3'

networks:
  prometheus:

services:
  prometheus:
    image: prom/prometheus
    volumes:
      - /data/monitoring/prometheus-server/:/prometheus/
    networks:
      - prometheus
    restart: always

Запускаем его:

[simterm]

# docker-compose -f prometheus-server.yml up -d

[/simterm]

С хоста проверяем:

[simterm]

$ curl -s prometheus-server.local:9090/metrics | head -5
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 1.1956e-05
go_gc_duration_seconds{quantile="0.25"} 1.4028e-05
go_gc_duration_seconds{quantile="0.5"} 1.9393e-05

[/simterm]

Grafana

В этот же compose файл добавляем Grafana:

version: '3.3'

networks:
  prometheus:

services:

  prometheus:
    image: prom/prometheus
    ports:
      - 9090:9090
    volumes:
      - /data/monitoring/prometheus-server:/prometheus
    networks:
      - prometheus
    restart: always

  grafana:
    image: grafana/grafana
    ports:
      - 3000:3000
    volumes:
      - /data/monitoring/grafana:/var/lib/grafana
    depends_on:
      - prometheus
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=password
      - GF_SECURITY_ADMIN_USER=admin
    networks:
      - prometheus 
    restart: always

Запускаем:

[simterm]

# docker-compose -f prometheus-server.yml up -d

[/simterm]

Проверяем данные в каталогах:

[simterm]

root@prometheus-server:/home/setevoy# ls -l /data/monitoring/prometheus-server/ 
total 8
-rw------- 1 nobody nogroup    2 Dec  6 06:51 lock
drwxr-xr-x 2 nobody nogroup 4096 Dec  6 06:51 wal
root@prometheus-server:/home/setevoy# ls -l /data/monitoring/grafana/
total 116
-rw-r--r-- 1 _apt crontab 109568 Dec  6 06:51 grafana.db
drwxr-xr-x 2 _apt crontab   4096 Dec  6 06:51 plugins

[/simterm]

Проверяем Grafana:

[simterm]

$ curl -s prometheus-server.local:3000
<a href="/login">Found</a>.

[/simterm]

И проверяем в браузере:

Настройка NGINX

Создаём файл настроек для NGINX/etc/nginx/conf.d/prometheus-server.local.conf:

upstream prometheus {
    server 127.0.0.1:9090;
}

upstream grafana {
    server 127.0.0.1:3000;
}

server {

    server_name prometheus-server.local;

    access_log /var/log/nginx/prometheus-server.local-access.log;
    error_log /var/log/nginx/prometheus-server.local-error.log notice;

    root /var/www/prometheus-server.local;

    location / {
        proxy_redirect          off;
        proxy_set_header        Host            $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://grafana$request_uri;
    }

    location /prometheus {
        proxy_redirect          off;
        proxy_set_header        Host            $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://prometheus$request_uri;
    }
}

Перезапускаем NGINX:

[simterm]

# nginx -t && systemctl reload nginx.service
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

[/simterm]

Проверяем:

[simterm]

$ curl -IL prometheus-server.local
HTTP/1.1 302 Found
Server: nginx/1.10.3
Date: Wed, 06 Dec 2017 12:09:40 GMT
Content-Type: text/plain; charset=utf-8
Connection: keep-alive
Location: /login
Set-Cookie: grafana_sess=46ed2a5654376404; Path=/; HttpOnly
Set-Cookie: redirect_to=%252F; Path=/

HTTP/1.1 200 OK
Server: nginx/1.10.3
Date: Wed, 06 Dec 2017 12:09:40 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Set-Cookie: grafana_sess=8058cc8cff393de5; Path=/; HttpOnly

[/simterm]

Что бы получить доступ к Prometheus – обновляем его параметры в Compose файле и добавляем два параметра – --config.file и --web.external-url:

...
  prometheus:
    image: prom/prometheus
    ports:
      - 9090:9090
    volumes:
      - /data/monitoring/prometheus-server:/prometheus
    networks:
      - prometheus
    restart: always
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--web.external-url=http://prometheus-server.local/prometheus'
...

Перезапускаем сервисы, проверяем доступ к Prometheus:

[simterm]

$ curl -L prometheus-server.local/prometheus/
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Prometheus Time Series Collection and Processing Server</title>
...

[/simterm]

конфиг prometheus.yml

Добавляем файл настроек для Prometheus.

Создаём файл на хосте, и мапим его в контейнер.

Добавляем каталог:

[simterm]

# mkdir /etc/prometheus

[/simterm]

Создаём файл /etc/prometheus/prometheus.yml:

global:
  scrape_interval:     15s
  evaluation_interval: 15s
  external_labels:
      monitor: 'monitoring'

scrape_configs:

  - job_name: 'prometheus'

    static_configs:
      - targets: ['localhost:9090']

Пока мы тут собираем метрики только с самого Prometheus сервера, позже добавим сбор с node-exporter и cAdvisor.

Обновляем Compose файл – добавляем маппинг файла в контейнер:

...
  prometheus:
    image: prom/prometheus
    ports:
      - 9090:9090
    volumes:
      - /data/monitoring/prometheus-server:/prometheus
      - /etc/prometheus/:/etc/prometheus/
...

Перезапускаем сервисы, и получаем ошибку 404 в Targets:

Собственно, если проверить:

[simterm]

# curl http://127.0.0.1:9090/metrics
404 page not found

[/simterm]

То ошибка воспроизводится.

Почему? Потому что в NGINX путь проксируется через location /prometheus:

...
    location /prometheus {
        proxy_redirect          off;
        proxy_set_header        Host            $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://prometheus$request_uri;
    }
...

Соответственно, что бы получить доступ к метрикам самого Prometheus сервера – необходимо добавить этот location в URL:

[simterm]

# curl -s http://127.0.0.1:9090/prometheus/metrics | head -5
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 1.0783e-05
go_gc_duration_seconds{quantile="0.25"} 1.4825e-05
go_gc_duration_seconds{quantile="0.5"} 1.6093e-05

[/simterm]

Что бы реализовать это обновление URL с метриками – используем relabeling.

Обновляем /etc/prometheus/prometheus.yml и добавляем relabel_configs:

global:
  scrape_interval:     15s
  evaluation_interval: 15s
  external_labels:
      monitor: 'monitoring'

scrape_configs:

  - job_name: 'prometheus'

    static_configs:
      - targets:
        - 127.0.0.1:9090

    relabel_configs:
      - target_label: __metrics_path__
        replacement: /prometheus/metrics

Тут мы меняем значение __metrics_path__ со значения по умолчанию (/metrics) на /prometheus/metrics. Хорошая схема того, как применяются лейблы есть тут>>>.

Перезапускаем – всё ОК:

Другой способ переопределить __metrics_path__ – указать его в labels самого target, а не выносить в relabel_configs:

global:
  scrape_interval:     15s
  evaluation_interval: 15s
  external_labels:
      monitor: 'monitoring'

scrape_configs:

  - job_name: 'prometheus'

    static_configs:
      - targets:
        - 127.0.0.1:9090
        labels:
          __metrics_path__: /prometheus/metrics

node-exporter

Прежде чем приступить к добавлению дашбордов в Grafana – добавим node-exporter в стек Prometheus, что бы получать метрики о работе самого хоста мониторинга.

Возвращемся к compose-файлу, и добавляем експортёр:

...
  node-exporter:
    image: prom/node-exporter
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command: 
      - '--path.procfs=/host/proc' 
      - '--path.sysfs=/host/sys'
      - --collector.filesystem.ignored-mount-points
      - "^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)"
    ports:
      - 9100:9100
    networks:
      - prometheus
    restart: always

Перезапускаем сервисы, проверяем:

[simterm]

# curl -s localhost:9100/metrics  | head
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0
go_gc_duration_seconds{quantile="0.75"} 0
go_gc_duration_seconds{quantile="1"} 0
go_gc_duration_seconds_sum 0
go_gc_duration_seconds_count 0
# HELP go_goroutines Number of goroutines that currently exist.

[/simterm]

Заодно – обновим имена контейнеров в prometheus-server.yml, полностью сейчас он выглядит так:

version: '3.3'

networks:
  prometheus:

services:

  prometheus-server:
    image: prom/prometheus
    ports:
      - 9090:9090
    volumes:
      - /data/monitoring/prometheus-server:/prometheus
      - /etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    depends_on:
      - node-exporter
    networks:
      - prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--web.external-url=http://prometheus-server.local/prometheus'
    restart: always        

  grafana:
    image: grafana/grafana
    ports:
      - 3000:3000
    volumes:
      - /data/monitoring/grafana:/var/lib/grafana
    depends_on:
      - prometheus-server
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=password
      - GF_SECURITY_ADMIN_USER=admin
    networks:
      - prometheus 
    restart: always        

  node-exporter:
    image: prom/node-exporter
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command: 
      - '--path.procfs=/host/proc' 
      - '--path.sysfs=/host/sys'
      - --collector.filesystem.ignored-mount-points
      - "^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)"
    ports:
      - 9100:9100
    networks:
      - prometheus
    restart: always

Обновляем /etc/prometheus/prometheus.yml и добавляем ещё один таргет в job-name "prometheus":

global:

  scrape_interval:     15s
  evaluation_interval: 15s
  external_labels:
      monitor: 'monitoring'

scrape_configs:

  - job_name: 'prometheus-server'

    static_configs:
      - targets:
        - prometheus-server:9090
        labels:
          __metrics_path__: /prometheus/metrics
          name: prometheus-server
      - targets: 
        - node-exporter:9100
        labels:
          name: node-exporter

Запускаем стек – проверяем:

[simterm]

# docker-compose -f prometheus-server.yml up -d
Starting setevoy_node-exporter_1 ... 
Starting setevoy_node-exporter_1 ... done
Creating setevoy_prometheus-server_1 ... 
Creating setevoy_prometheus-server_1 ... done
Recreating setevoy_grafana_1 ... 
Recreating setevoy_grafana_1 ... done

[/simterm]

Настройка Grafana

Основные моменты описаны в посте Prometheus: Ansible, NGINX и Grafana dashboard – и тут особо ничего не меняется (кроме того, что в текущем примере не используется HTTP авторизация на NGINX).

Добавляем data source:

В качестве URL указываем имя сервиса из нашего Compose файла – контейнер с Grafana разрезолвит его в IP контейнера с Prometheus.

Добавляем дашборд, например Prometheus system:

Проверяем:

Всё хорошо.

cAdvisor

Возвращаемся к Prometheus.

Далее – добавим cAdvisor для получения метрик из Docker.

Примечание: Docker недавно включил поддержку метрик Prometheus, но в настоящий момент эта возможность ещё “Warning: The available metrics and the names of those metrics are in active development and may change at any time.”, потому на момент написания поста – используем cAdvisor.
См. https://docs.docker.com/engine/admin/prometheus/

Обновляем compose файл, добавляем контейнер с cAdvisor:

...
  cadvisor:
    image: google/cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - 8080:8080
    networks:
      - back-tier
    restart: always
    deploy:
      mode: global

Перезапускаем стек, проверяем:

[simterm]

# curl -s localhost:8080/metrics | head
# HELP cadvisor_version_info A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision.
# TYPE cadvisor_version_info gauge
cadvisor_version_info{cadvisorRevision="17543be",cadvisorVersion="v0.25.0",dockerVersion="17.11.0-ce",kernelVersion="4.9.0-4-amd64",osVersion="Alpine Linux v3.4"} 1
# HELP container_cpu_system_seconds_total Cumulative system cpu time consumed in seconds.
# TYPE container_cpu_system_seconds_total counter
container_cpu_system_seconds_total{id="/"} 97.88
container_cpu_system_seconds_total{id="/docker"} 13.87
container_cpu_system_seconds_total{id="/init.scope"} 0.36
container_cpu_system_seconds_total{id="/system.slice"} 38.49
container_cpu_system_seconds_total{id="/system.slice/avahi-daemon.service"} 0.91

[/simterm]

cAdvisor так же имеет собственный вебинтерфейс, открываем в браузере http://prometheus-server.local:8080/containers/:

Обновляем /etc/prometheus/prometheus.yml, добавляем ещё один таргет – cadvisor:8080:

global:

  scrape_interval:     15s
  evaluation_interval: 15s
  external_labels:
      monitor: 'monitoring'

scrape_configs:

  - job_name: 'prometheus-server'

    static_configs:
      - targets:
        - prometheus-server:9090
        labels:
          __metrics_path__: /prometheus/metrics
          name: prometheus-server
      - targets: 
        - node-exporter:9100
        labels:
          name: node-exporter
      - targets:
        - cadvisor:8080
        labels:
          name: cAdvisor

Перезапускаем, проверяем:

Добавляем ещё один дашбоард в Grafana, например – Docker and system monitoring:

Alertmanager

Теперь добавляем Alertmanager.

Документация – тут>>>.

Сздаём каталог для настроек:

[simterm]

# mkdir /etc/alertmanager

[/simterm]

Создаём файл настроек /etc/alertmanager/config.yml:

global:
  smtp_smarthost: 'smtp.sendgrid.net:25'
  smtp_from: 'root@localhost'
  smtp_auth_username: 'username'
  smtp_auth_password: 'password'
route:
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 30s
  repeat_interval: 1h
  receiver: jm-alerts

  routes:
  - match:
      job: prometheus
    receiver: jm-alerts
    repeat_interval: 1h

receivers:
- name: 'jm-alerts'
  email_configs:
  - to: '[email protected]'

Обновляем prometheus-server.yml:

...
  alertmanager:
    image: prom/alertmanager
    ports:
      - 9093:9093
    volumes:
      - /etc/alertmanager/:/etc/alertmanager/
    networks:
      - prometheus
    restart: always
    command:
      - '-config.file=/etc/alertmanager/config.yml'
      - '-storage.path=/alertmanager'

В файл настроек Prometheus добавляем alerting (до Prometheus 1.4 алертменеджер указывался через --alermanager.url):

global:

  scrape_interval:     15s
  evaluation_interval: 15s
  external_labels:
      monitor: 'monitoring'

scrape_configs:

  - job_name: 'prometheus-server'

    static_configs:
      - targets:
        - prometheus-server:9090
        labels:
          __metrics_path__: /prometheus/metrics
          name: prometheus-server
      - targets: 
        - node-exporter:9100
        labels:
          name: node-exporter
      - targets:
        - cadvisor:8080
        labels:
          name: cAdvisor

alerting:
  alertmanagers:
    - static_configs:
      - targets: 
        - alertmanager:9093

В каталоге /etc/prometheus/ создаём файл alert.rules:

groups:
- name: example
  rules:

  - alert: high_load
    expr: node_load1 > 0.0
    for: 1s
    labels:
      severity: page
    annotations:
      summary: "Instance {{ $labels.instance }} under high load"
      description: "{{ $labels.instance }} of job {{ $labels.job }} is under high load."

expr: node_load1 > 0.0 в течении 1 секунды (for: 1s) – используем 0.0 Load Avarage для проверки, потом можно указать адекватное значение.

Документация по правилам – тут>>>.

Обновляем файл настроек Prometheus/etc/prometheus/prometheus.yml – добавляем rule_files и путь (относительно самого prometheus.yml) к файлу alert.rules:

global:

  scrape_interval:     15s
  evaluation_interval: 15s
  external_labels:
      monitor: 'monitoring'
  rule_files:
    - "alert.rules" 
...

Запускаем, проверяем:

(мне нравится этот “Firing!” 🙂 )

И проверяем логи:

alertmanager_1       | level=error ts=2017-12-07T12:29:31.665200988Z caller=notify.go:302 component=dispatcher msg=”Error on notify” err=”dial tcp 159.122.219.43:25: getsockopt: connection refused”
alertmanager_1       | level=error ts=2017-12-07T12:29:31.665591597Z caller=dispatch.go:266 component=dispatcher msg=”Notify for alerts failed” num_alerts=1 err=”dial tcp 159.122.219.43:25: getsocko
pt: connection refused”

Упс… Это “приколы” сети в офисе – все почтовые порты закрыты. Но Alertmanager письма вроде отправляет – всё хорошо.

Alert для Docker сервисов

Раз всё работает (ну, почту ещё всё же проверить) – попробуем добавить правило для отправки уведомления при падении конкретного контейнера, например nginx_service.

Запускаем новый контейнер:

[simterm]

# docker run -tid -p 8081:80 --name nginx_service nginx
65d38787c356c846bb635f4bd66c6fa96e41e4a08a0b6d48116996cbf70f88e8

[/simterm]

Обновляем /etc/prometheus/alert.rules:

...
  - alert: nginx_service_down
    expr: absent(container_last_seen{exported_name="nginx_service"})
    for: 1s
    annotations:
      summary: "Instance {{ $labels.instance }} is down"
      description: "{{ $labels.instance }} of job {{ $labels.job }} is down."
...

Проверяем алерты:

Всё гуд…

Убиваем контейнер nginx_service:

[simterm]

# docker kill nginx_service
nginx_service

[/simterm]

Ждём до 15 секунд (scrape_interval), и получаем алерт:

Мониторинг удалённого хоста

В целом на самом сервере мониторинга всё готово.

Последний штрих – добавить мониторинг удалённой ВМ и сервисов на ней.

На виртуалке prometheus_client – создаём compose файл prometheus-client.yml с сервисами:

version: '3.3'

networks:
  nginx:
  monitoring:

services:

  node-exporter:
    image: prom/node-exporter
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command: 
      - '--path.procfs=/host/proc' 
      - '--path.sysfs=/host/sys'
      - --collector.filesystem.ignored-mount-points
      - "^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)"
    ports:
      - 9100:9100
    networks:
      - monitoring
    restart: always

  cadvisor:
    image: google/cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - 8080:8080
    networks:
      - monitoring
    restart: always

  nginx:
    image: nginx
    ports:
      - 80:80
    networks:
      - nginx
    restart: always

Запускаем:

[simterm]

# docker-compose -f prometheus-client.yml up -d
Starting setevoy_node-exporter_1 ... 
Starting setevoy_nginx_1 ... 
Starting setevoy_node-exporter_1
Starting setevoy_cadvisor_1 ... 
Starting setevoy_nginx_1
Starting setevoy_nginx_1 ... done

[/simterm]

Возвращаемся к файлу /etc/prometheus/prometheus.yml на хосте мониторинга и добавляем ещё одну job:

...
scrape_configs:

  - job_name: 'prometheus-server'

    static_configs:
      - targets:
        - prometheus-server:9090
        labels:
          __metrics_path__: /prometheus/metrics
          name: prometheus-server
      - targets:
        - node-exporter:9100
        labels:
          name: node-exporter
      - targets:
        - cadvisor:8080
        labels:
          name: cAdvisor

  - job_name: 'prometheus-client'

    static_configs:
      - targets:
        - 10.11.100.167:9100
        labels:
          name: client-node-exporter
      - targets:
        - 10.11.100.167:8080
        labels:
          name: client-cAdvisor
...

Перезапускаем Prometheus стек, проверяем:

В /etc/prometheus/alert.rules добавляем алерт ClientInstanceDown:

groups:

- name: server
  rules:

  - alert: high_load
    expr: node_load1 > 0.0
    for: 1s
    labels:
      severity: page
    annotations:
      summary: "Instance {{ $labels.instance }} under high load"
      description: "{{ $labels.instance }} of job {{ $labels.job }} is under high load."

  - alert: nginx_service_down
    expr: absent(container_last_seen{exported_name="nginx_service"})
    for: 1s
    annotations:
      summary: "Instance {{ $labels.instance }} is down"
      description: "{{ $labels.instance }} of job {{ $labels.job }} is down."

- name: client
  rules:

  - alert: ClientInstanceDown
    expr: up{job="prometheus-client"} == 0
    for: 1s
    annotations:
      summary: "Instance {{ $labels.instance }} is down"
      description: "{{ $labels.instance }} of job {{ $labels.job }} is down."

Проверяем:

Останавливаем полностью вторую виртуалку:

[simterm]

$ VBoxManage controlvm prometheus-client poweroff soft
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

[/simterm]

И смотрим алерты:

В целом – на этом всё.

Ссылки по теме

Примечание: в большинстве ссылок используется синтаксис для Prometheus 1.*, тогда как в этом посте используется Prometheus 2.* – имейте ввиду.

Prometheus

Monitoring Docker Services with Prometheus

Prometheus Monitoring with Grafana

Scraping application metrics with Prometheus

Monitoring with Prometheus

Monitoring a Docker Swarm Cluster with Prometheus (наверно – лучший пост по теме, который я нагугливал)

How to Setup Monitoring for Docker Containers using Prometheus

Bringing the light of monitoring with Prometheus

Monitoring in Docker Stacks – It’s that easy with Prometheus!

Docker Container and Host Monitoring, Logging (& Alerting) in a Box

Life of a Label

Prometheus relabeling tricks

Configuring Prometheus Alertmanager

Примеры файлов

vegasbrianc/prometheus/prometheus.yml

vegasbrianc/prometheus/docker-compose.yml

prometheus/prometheus/conf.good.yml

prometheus/alertmanager/simple.yml

Grafana

Dashboards