En anteriores posts hemos estado hablado sobre Haproxy como herramienta esencial para proteger y controlar el acceso y el buen funcionamiento de nuestras arquitecturas. Pero cómo tenerlo controlado y de qué manera podemos monitorizar su funcionamiento era una pequeña espina que me quedaba para completar esta serie de posts relacionados con Haproxy.
Una de las características incluidas en las nuevas versiones 2.x de Haproxy es la capacidad de monitorizar el funcionamiento de esta herramienta mediante Prometheus al traer integrado en su código un exportador de métricas compatible con la arquitectura Prometheus.
Prometheus es un sistema open-source de monitorización y alertas inicialmente desarrollado por SoundCloud y que actualmente forma parte como proyecto de la Cloud Native Computing Foundation. De hecho, es el segundo proyecto hospedado en esta fundación después de Kubernetes.
La mayoría de componentes de Prometheus están desarrollados en el lenguaje Go, lo que hace fácil crear binarios estáticos que podamos integrar con nuestras aplicaciones.
Sobre la integración de Haproxy y Prometheus, con la inestimable ayuda de Grafana, hablaremos hoy en este post.
Comencemos.
Desplegando Haproxy
La instalación de Haproxy es bastante fácil, basta agregar los repositorios necesarios para nuestra distribución e instalar el paquete. En caso de utilizar distribuciones basadas en Debian/Ubuntu, como es nuestro caso, el proceso se simplifica accediendo a la url <https://haproxy.debian.net> y seleccionando nuestra distribución y versión de la misma.
Hacemos esto porque las versiones incluidas en Debian/Ubuntu como paquete oficial aún están en la versión 1.8.x y nosotros queremos probar la flamante 2.x que incluye el exportador de métricas de Prometheus.
Siguiendo las instrucciones provistas en la url anterior, tendremos que hacer lo siguiente en consola:
# Agregamos la llave pública del repositorio haproxy.debian.net curl https://haproxy.debian.net/bernat.debian.org.gpg | \ apt-key add - # Agregamos una nueva fuente o repositorio a nuestra configuración apt echo deb http://haproxy.debian.net buster-backports-2.0 main | \ tee /etc/apt/sources.list.d/haproxy.list # Actualizamos la lista de paquetes incluyendo el nuevo repositorio apt-get update # Instalamos la versión 2.0.x incluída en el repositorio para nuestra distribución apt-get install haproxy=2.0.\*
Esto nos dejará instalado el paquete Haproxy 2.0.12 en una Debian 10 que utilizaremos como máquina para este post.
Configurando Haproxy para habilitar el exportador de métricas de Prometheus
Como hablábamos anteriormente, el código de Haproxy en sus versiones 2.x ya trae integrado el exportador de métricas como servicio, así que simplemente tendremos que editar nuestro `haproxy.cfg` para habilitarlo.
Podemos comprobar si nuestra versión trae integrado el exportador de la siguiente forma:
root@haproxy:~# haproxy -vv |grep Prometheus Built with the Prometheus exporter as a service
Y para habilitarlo tenemos que agregar un nuevo `frontend` a nuestra configuración, como ejemplo:
frontend stats bind *:8404 option http-use-htx http-request use-service prometheus-exporter if { path /metrics } stats enable stats uri /stats stats refresh 10s
Esto habilitará en el puerto definido (`*:8404`) y en el path `/metrics` nuestro conjunto de métricas de la aplicación. También configurará el path `/stats` las métricas habituales de Haproxy. Aunque no son objeto de explicación de este post, son también una buena fuente de información acerca del funcionamiento de Haproxy.
Una vez hecho esto, sólo tenemos que consultar la url de nuestro haproxy en ese puerto y los distintos paths expuestos para obtener estadísticas de uso de Haproxy, aunque nuestra fuente de información será ese `/metrics` que vamos a aprovechar con Prometheus y Grafana.
Pasemos a configurar ambos paquetes.
Desplegando Prometheus y Node exporter
Desplegaremos Prometheus y Grafana en la misma máquina virtual donde está instalado Haproxy en este post. Aunque lo ideal es colocar este conjunto de herramientas en una máquina virtual aparte.
Vamos a desplegar también `Node Exporter`, que es el agente compatible con Prometheus para métricas básicas del sistema (cpu/disco/memoria/etc) y nos permitirá tener información genérica del funcionamiento tanto de la instalación de Haproxy como la del propio host que hospeda la solución Prometheus/Grafana.
Desplegando Node Exporter
Desplegaremos primero Node Exporter de la siguiente forma:
# Creamos los usuarios para prometheus y node exporter useradd --no-create-home --shell /usr/bin/nologin prometheus useradd --no-create-home --shell /bin/false node_exporter # Creamos directorios de trabajo mkdir /etc/prometheus mkdir /var/lib/prometheus # Cambiamos permisos chown prometheus:prometheus /etc/prometheus chown prometheus:prometheus /var/lib/prometheus # Descargamos Node Exporter wget https://github.com/prometheus/node_exporter/releases/download/v0.18.1/node_exporter-0.18.1.linux-amd64.tar.gz # Descomprimimos, movemos a directorio y ajustamos permisos de Node Exporter tar zxvf node_exporter-0.18.1.linux-amd64.tar.gz cp node_exporter-0.18.1.linux-amd64/node_expoter /usr/local/bin chown node_exporter:node_exporter /usr/local/bin/node_exporter # Creamos una nueva Unit de SystemD para ejecutar Node Exporter como servicio vim /etc/systemd/system/node_exporter.service # Agregamos la definición de la unidad Description=Node Exporter Wants=network-online.target After=network-online.target User=node_exporter Group=node_exporter Type=simple ExecStart=/usr/local/bin/node_exporter WantedBy=multi-user.target # Recargamos las definiciones de SystemD systemctl daemon-reload # Arrancamos Node Exporter systemctl start node_exporter # Y por último verificamos que funciona correctamente y habilitamos el demonio para que arranque con el sistema systemctl status node_exporter ● node_exporter.service - Node Exporter Loaded: loaded (/etc/systemd/system/node_exporter.service; disabled; vendor preset: enabled) Active: active (running) since Wed 2019-12-25 22:41:23 CET; 5s ago Main PID: 7049 (node_exporter) Tasks: 5 (limit: 1148) Memory: 6.5M CGroup: /system.slice/node_exporter.service └─7049 /usr/local/bin/node_exporter systemctl enable node_exporter
Desplegando Prometheus
Continuamos con la instalación de Prometheus:
# Descargamos el paquete Prometheus wget https://github.com/prometheus/prometheus/releases/download/v2.15.1/prometheus-2.15.1.linux-amd64.tar.gz # Descomprimimos tar zxvf prometheus-2.15.1.linux-amd64.tar.gz cd prometheus-2.15.1.linux-amd64 # Copiamos la consola de Prometheus y el binario del mismo Prometheus al path cp ./prometheus /usr/local/bin/ cp ./promtool /usr/local/bin/ cp -r ./consoles /etc/prometheus cp -r ./console_libraries /etc/prometheus # Ajustamos permisos chown prometheus:prometheus /usr/local/bin/prometheus chown prometheus:prometheus /usr/local/bin/promtool chown -R prometheus:prometheus /etc/prometheus/consoles chown -R prometheus:prometheus /etc/prometheus/console_libraries
Y pasamos a cambiar la configuración de Prometheus que reside en `/etc/prometheus/prometheus.yml`:
global: scrape_interval: 15s evaluation_interval: 15s rule_files: scrape_configs: - job_name: 'prometheus' scrape_interval: 5s static_configs: - targets: - job_name: 'node_exporter' scrape_interval: 5s static_configs: - targets:
Hemos agregado dos `jobs` de Prometheus, uno que chequeará el puerto en el que corre Prometheus (`:9090`) y otro para el Node Exporter (`:9100`). Estos dos `jobs` se chequearán cada 5 segundos. Esa será nuestra resolución de monitorización.
Por último, ajustamos los permisos del fichero mediante el comando: `chown prometheus:prometheus /etc/prometheus/prometheus.yml`.
Es hora de arrancar Prometheus y comprobar su funcionamiento:
sudo -u prometheus /usr/local/bin/prometheus --config.file /etc/prometheus/prometheus.yml --storage.tsdb.path /var/lib/prometheus/ --web.console.templates=/etc/prometheus/consoles --web.console.libraries=/etc/prometheus/console_libraries level=info ts=2019-12-25T22:04:51.754Z caller=main.go:294 msg="no time or size retention was set so using the default time retention" duration=15d level=info ts=2019-12-25T22:04:51.754Z caller=main.go:330 msg="Starting Prometheus" version="(version=2.15.1, branch=HEAD, revision=8744510c6391d3ef46d8294a7e1f46e57407ab13)" level=info ts=2019-12-25T22:04:51.754Z caller=main.go:331 build_context="(go=go1.13.5, user=root@4b1e33c71b9d, date=20191225-01:04:15)" level=info ts=2019-12-25T22:04:51.754Z caller=main.go:332 host_details="(Linux 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u2 (2019-11-11) x86_64 haproxy (none))" level=info ts=2019-12-25T22:04:51.754Z caller=main.go:333 fd_limits="(soft=1024, hard=1048576)" level=info ts=2019-12-25T22:04:51.754Z caller=main.go:334 vm_limits="(soft=unlimited, hard=unlimited)" level=info ts=2019-12-25T22:04:51.758Z caller=main.go:648 msg="Starting TSDB ..." level=info ts=2019-12-25T22:04:51.769Z caller=web.go:506 component=web msg="Start listening for connections" address=0.0.0.0:9090 level=info ts=2019-12-25T22:04:51.770Z caller=head.go:584 component=tsdb msg="replaying WAL, this may take awhile" level=info ts=2019-12-25T22:04:51.771Z caller=head.go:632 component=tsdb msg="WAL segment loaded" segment=0 maxSegment=0 level=info ts=2019-12-25T22:04:51.772Z caller=main.go:663 fs_type=EXT4_SUPER_MAGIC level=info ts=2019-12-25T22:04:51.773Z caller=main.go:664 msg="TSDB started" level=info ts=2019-12-25T22:04:51.773Z caller=main.go:734 msg="Loading configuration file" filename=/etc/prometheus/prometheus.yml level=info ts=2019-12-25T22:04:51.776Z caller=main.go:762 msg="Completed loading of configuration file" filename=/etc/prometheus/prometheus.yml level=info ts=2019-12-25T22:04:51.776Z caller=main.go:617 msg="Server is ready to receive web requests."
Ahí tenemos nuestro `Server is ready to receive web request` que esperábamos. Lo que significa que, si visitamos con el navegador la url de nuestro Prometheus (`http://172.26.13.251:9090`, en nuestro caso), debemos ver su interfaz web.
Ahora tenemos que configurar una `Unit` de SystemD para que Prometheus arranque con el sistema:
# Editamos el fichero del servicio de Prometheus vim /etc/systemd/system/prometheus.service # Agregamos la definición del servicio Description=Prometheus Monitoring Wants=network-online.target After=network-online.target User=prometheus Group=prometheus Type=simple ExecStart=/usr/local/bin/prometheus \ --config.file /etc/prometheus/prometheus.yml \ --storage.tsdb.path /var/lib/prometheus/ \ --web.console.templates=/etc/prometheus/consoles \ --web.console.libraries=/etc/prometheus/console_libraries ExecReload=/bin/kill -HUP $MAINPID WantedBy=multi-user.target # Recargamos la definición de servicios de SystemD systemclt daemon-reload # Habilitamos el servicio systemctl enable prometheus # Iniciamos el servicio systemctl start prometheus # Y comprobamos que está funcionando correctamente systemctl status prometheus ● prometheus.service - Prometheus Monitoring Loaded: loaded (/etc/systemd/system/prometheus.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2019-12-25 23:12:25 CET; 3s ago Main PID: 7373 (prometheus) Tasks: 7 (limit: 1148) Memory: 25.9M CGroup: /system.slice/prometheus.service └─7373 /usr/local/bin/prometheus --config.file /etc/prometheus/prometheus.yml --storage.tsdb.path /var/lib/prometheus/ --web.cons
Desplegando Grafana
Grafana es la herramienta de facto para analizar y monitorizar que usaremos junto a Prometheus (almacenaje y recolección de métricas) y así completar nuestro stack de Monitorización.
Para desplegarlo, nos descargaremos el paquete para la distribución Debian de la siguiente forma:
# Instalamos paquetes necesarios apt-get install fontconfig-config fonts-dejavu-core libfontconfig1 # Descargamos la última versión de Grafana e instalamos wget https://dl.grafana.com/oss/release/grafana_6.5.2_amd64.deb dpkg -i grafana_6.5.2_amd64.deb # Habilitamos el servicio y lo ejecutamos systemctl daemon-reload && systemctl enable grafana-server && systemctl start grafana-server
Ya tenemos disponible Grafana corriendo en el puerto `:3000` de nuestro host Prometheus. Una vez disponible, nos conectaremos con las credenciales por defecto `user: admin` y `password: admin` y cambiaremos la contraseña por una más compleja.
Configurando Prometheus como fuente de datos de Grafana
Nos queda configurar Grafana para que consulte la base de datos de Prometheus en busca de métricas.
Lo haremos agregando un Data Source de tipo Prometheus ubicado en la url `http://localhost:9090`.
Agregando Dashboards a nuestro Grafana
Para terminar de completar la instalación de Grafana vamos a agregar un Dashboard con las métricas del propio host que hospeda Prometheus y Grafana. Buscaremos en la web de Grafana Dashboards y el dashboard con id:1860 será el que elegiremos.
Puedes ver cómo queda en nuestra instalación aquí:
Configurando Prometheus para que recoja las métricas de nuestro Haproxy
Todavía no tenemos el trabajo de Prometheus definido que se encargará de ir a por las métricas de Haproxy. Para realizar esta tarea tenemos que modificar el fichero de configuración de Prometheus alojado en `/etc/prometheus/prometheus.yml` de la siguiente forma:
# Editamos el fichero vim /etc/prometheus/prometheus.yml # Agregamos lo siguiente con cuidado de respetar la sintaxis del fichero YAML - job_name: 'haproxy_exporter' scrape_interval: 5s static_configs: - targets: # Recargamos la configuración systemctl restart prometheus
Y procedemos a agregar el Dashboard relacionado con Haproxy de la web de Grafana Dashboards (o a construir el nuestro propio, según la necesidad que tengamos). El id del dashboard que vamos a utilizar es el 10225.
Para ello nos vamos al Grafana en el icono de «Dashboards» -> «Manage» -> «Import» y ahí colocaremos el ID del dashboard que vamos a usar. También podemos organizarlos por carpetas según nuestra organización.
Podemos ver cómo queda dicho dashboard en la siguiente imagen:
Como podéis ver en la captura, nos está mostrando el número de `frontends` que están en estado activo y un montón de métricas más que podremos explorar dentro de nuestro Dashboard.
De esta manera podemos explorar todas las métricas que expone nuestro Haproxy.
Queda para otros posts la gestión de alertas mediante `AlertManager` o la creación de dashboards personalizados mediante PromQL, el lenguaje de consultas que utiliza internamente Prometheus.