Перебирал несколько ролей в Ansible Galaxy для установки и настройки Prometheus — но в конце-концов решил делать всё по-своему.
Будем использовать Docker Compose, который будет запускать сам Prometheus и node_exporter.
Содержание
Роль Docker Compose
Начнём с добавления роли docker-compose.
В корне репозитория создаём каталог roles/docker-compose/tasks:
[simterm]
$ mkdir -p roles/docker-compose/tasks
[/simterm]
Создаём файл roles/docker-compose/tasks/main.yml:
- name: Installing docker compose
pip:
name: docker-compose
state: present
pip устанавливается из роли common:
[simterm]
$ cat roles/common/tasks/main.yml
- name: Update APT
apt:
update_cache: yes
- name: Install python-apt
package:
name: python-apt
state: latest
- name: Install python-pip
package:
name: python-pip
state: latest
[/simterm]
Добавляем вызов docker-compose в provision.yml, сейчас полностью он выглядит так:
- hosts: all
become:
true
roles:
- role: common
- role: jnv.unattended-upgrades
unattended_mail: [email protected]
# - role: jaywink.letsencrypt
# letsencrypt_domain: "{{ inventory_hostname }}"
# letsencrypt_email:[email protected]
# letsencrypt_request_www: false
# letsencrypt_pause_services: nginx
- role: nginx
nginx_allow_kiev_ip: 194.***.***.45
nginx_allow_berlin_ip: 37.***.***.130
- role: mongrelion.docker
- role: docker-compose
Роль letsencrypt закомментирована, что бы не вызывать её каждый раз, т.к. Lets Encrypt перестанет выполнять авторизацию вообще с сообщением «Error creating new cert :: too many certificates already issued for exact set of domains«.
Есть повод переписать и эту роль, и добавить проверку наличия сертификата перед тем, как вызывать certbot-auto.
Пушим:
[simterm]
$ git add provision.yml && git commit -m "docker compose install" && git push
[/simterm]
Запускаем Jenkins:
... TASK [docker-compose : Installing docker compose] ****************************** sudo -H -S -n changed: [dev.monitoring.domain.ms] PLAY RECAP ********************************************************************* dev.monitoring.domain.ms : ok=25 changed=5 unreachable=0 failed=0 [Pipeline] } [Pipeline] // stage [Pipeline] } $ docker stop --time=1 17711b30159a4f21ec5dce3cb5e7d03dabf5b0c4afa0c178e8df97d3290b126d $ docker rm -f 17711b30159a4f21ec5dce3cb5e7d03dabf5b0c4afa0c178e8df97d3290b126d [Pipeline] // withDockerContainer [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline Finished: SUCCESS
Проверяем на сервере:
[simterm]
root@jm-monitoring-dev-vm:~# docker-compose --version docker-compose version 1.16.1, build 6d1ac219
[/simterm]
Роль Prometheus сервера
Следующим шагом — создадим свою роль для установки и запуска Prometheus сервера.
Создаём каталоги:
[simterm]
$ mkdir -p roles/prometheus/{tasks,handlers,files,vars}
[/simterm]
files
В каталог files добавим compose-файл для запуска.
Создаём roles/prometheus/files/docker-compose.yml (v2, т.к. Ansible модуль docker_service 3 версию (пока) не поддерживает):
version: '2'
services:
prometheus:
image: prom/prometheus
expose:
- 9090
ports:
- 9090:9090
vars
Перед тем, как создать tasks — добавим несколько переменных в файл roles/prometheus/vars/main.yml:
prometheus_user: prometheus prometheus_group: prometheus prometheus_home: /opt/prometheus
tasks
Переходим к tasks, для запуска Docker Compose используем docker_service модуль.
Потребуется:
- создать пользователя
- создать каталог для файлов Prometheus
- скопировать
docker-compose.yml - запустить контейнер
Создаём roles/prometheus/tasks/main.yml:
- name: Create Prometheus user
user:
name: "{{ prometheus_user }}"
shell: /bin/false
groups: "{{ prometheus_group }}"
- name: Create Prometheus Opt directory
file:
path: "{{ prometheus_home }}"
state: directory
owner: "{{ prometheus_user }}"
group: "{{ prometheus_group }}"
mode: 0775
recurse: yes
- name: Copy compose file
copy:
src: files/docker-compose.yml
dest: "{{ prometheus_home }}/docker-compose.yml"
owner: "{{ prometheus_user }}"
group: "{{ prometheus_group }}"
- name: Start Prometheus service
docker_service:
project_src: "{{ prometheus_home }}"
Добавляем роль в provision.yml:
...
- role: prometheus
Вроде всё ОК — сохраняем, пушим:
[simterm]
$ git status roles/prometheus/
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
roles/prometheus/files/
roles/prometheus/tasks/
roles/prometheus/vars/
$ git add -A && git commit -m "prometheus role" && git push
[/simterm]
Запускаем Jenkins:
... TASK [prometheus : Create Prometheus user] ************************************* ok: [dev.monitoring.domain.ms] sudo -H -S -n TASK [prometheus : Create Prometheus Opt directory] **************************** sudo -H -S -n ok: [dev.monitoring.domain.ms] TASK [prometheus : Copy compose file] ****************************************** sudo -H -S -n sudo -H -S -n ok: [dev.monitoring.domain.ms] TASK [prometheus : Start Prometheus service] *********************************** sudo -H -S -n changed: [dev.monitoring.domain.ms] PLAY RECAP ********************************************************************* dev.monitoring.domain.ms : ok=5 changed=1 unreachable=0 failed=0 [Pipeline] } [Pipeline] // stage [Pipeline] } $ docker stop --time=1 980dfa37ed7ce303810a73b2c5389d5dd1cd97696e63fd0aa0ee0bd73d52a36e $ docker rm -f 980dfa37ed7ce303810a73b2c5389d5dd1cd97696e63fd0aa0ee0bd73d52a36e [Pipeline] // withDockerContainer [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline Finished: SUCCESS
Проверяем на сервере:
[simterm]
root@jm-monitoring-dev-vm:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 78c35a2e8fc4 prom/prometheus "/bin/prometheus -..." About a minute ago Up 8 seconds 0.0.0.0:9090->9090/tcp prometheus_prometheus_1
[/simterm]
Файл настроек:
[simterm]
root@jm-monitoring-dev-vm:~# docker exec -ti 78c35a2e8fc4 cat /etc/prometheus/prometheus.yml
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Attach these labels to any time series or alerts when communicating with
# external systems (federation, remote storage, Alertmanager).
external_labels:
monitor: 'codelab-monitor'
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first.rules"
# - "second.rules"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: 'prometheus'
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ['localhost:9090']
[/simterm]
Каталог:
[simterm]
root@jm-monitoring-dev-vm:~# ls -l /opt/prometheus/ total 4 -rwxrwxr-x 1 prometheus prometheus 120 Sep 29 11:48 docker-compose.yml
[/simterm]
Пользователь:
[simterm]
root@jm-monitoring-dev-vm:~# id prometheus uid=999(prometheus) gid=998(prometheus) groups=998(prometheus)
[/simterm]
Готово.
Продолжаем.
Роль node_exporter
node_exporter можно запустить либо как сервис на хост-системе, либо — контейнером из того же docker-compose.yml, который используется для запуска самого Prometheus, используя образ node-exporter.
Пример запуска контейнером можно посмотреть тут>>>, но т.к. всё-таки он не относится к самому стеку prometheus-сервера, а является «внешним» сервисом (как по мне, ибо экспортёров будет много) — то пока запустим его сервисом на хосте.
Для node_exporter — вполне работает вариант из Ansible Galaxy — UnderGreen.prometheus-node-exporter.
Обновляем requirements.yml:
- src: jnv.unattended-upgrades - src: mongrelion.docker - src: jaywink.letsencrypt - src: UnderGreen.prometheus-node-exporter
И provision.yml:
...
- role: UnderGreen.prometheus-node-exporter
prometheus_node_exporter_config_flags:
'web.listen-address': '127.0.0.1:9100'
'log.level': 'info'
Сохраняем, запускаем Jenkins билд, проверяем метрики node_exporter на сервере:
[simterm]
root@jm-monitoring-dev-vm:~# 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]
Добавление target
Теперь переходим к настройке самого Prometheus.
Что бы получать метрики с node_exporter — нам надо добавить новый target в конфиг prometheus.yml.
В каталоге roles/prometheus/files/ создаём файл prometheus.yml, и в него добавляем таргет localhost:9100:
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
monitor: 'jm-dev-monitor'
rule_files:
# - "first.rules"
# - "second.rules"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- targets: ['localhost:9100']
Далее — это конфиг необходимо скопировать на сервер мониторинга.
В roles/prometheus/vars/main.yml добавляем переменную prometheus_home:
... prometheus_configs: /etc/prometheus
В roles/prometheus/tasks/main.yml добавляем создание директории для файлов настроек Prometheus и копирование файла prometheus.yml, содержимое tasks/main.yml сейчас получается следующим:
- name: Create Prometheus user
user:
name: "{{ prometheus_user }}"
shell: /bin/false
groups: "{{ prometheus_group }}"
- name: Create Prometheus Opt directory
file:
path: "{{ prometheus_home }}"
state: directory
owner: "{{ prometheus_user }}"
group: "{{ prometheus_group }}"
mode: 0775
recurse: yes
- name: Create Prometheus config directory
file:
path: "{{ prometheus_configs }}"
state: directory
owner: "{{ prometheus_user }}"
group: "{{ prometheus_group }}"
mode: 0775
recurse: yes
- name: Copy Prometheus config
copy:
src: files/prometheus.yml
dest: "{{ prometheus_configs }}/prometheus.yml"
owner: "{{ prometheus_user }}"
group: "{{ prometheus_group }}"
- name: Copy compose file
copy:
src: files/docker-compose.yml
dest: "{{ prometheus_home }}/docker-compose.yml"
owner: "{{ prometheus_user }}"
group: "{{ prometheus_group }}"
- name: Start Prometheus service
docker_service:
project_src: "{{ prometheus_home }}"
Теперь — надо запамить prometheus.yml в контейнер при запуске.
Prometheus по умолчанию ищет файл в /etc/prometheus — добавляем в docker-compose.yml новый volume:
...
volumes:
- /etc/prometheus/:/etc/prometheus/
Что бы Prometheus мог обращаться к localhost хоста как localhost саого контейнера — устанавливает тип сети host (см. network_mode)
В результате docker-compose.yml получается сейчас таким:
version: '2'
services:
prometheus:
network_mode: "host"
image: prom/prometheus
expose:
- 9090
ports:
- 9090:9090
volumes:
- /etc/prometheus/:/etc/prometheus/
Вроде ОК — пушим, запускаем билд Jenkins и проверяем targets:
Метрики в graphs:
В целом — на это пока всё.
Далее надо будет:
- обновить Azure Resource group — добавить подключение диска, в котором будут хранится данные Prometheus
- добавить Grafana
- добавить и настроить Alertmanager
- cAdvisor или
container-exporterдля мониторинга Docker на самом хосте мониторинга - и наконец-то начать подключать внешние хосты сервисы под мониторинг
Вроде всё…

