Add prometheus_grafana test

This commit is contained in:
Manuel Vergara 2024-08-09 01:20:19 +02:00
parent 17a7e04180
commit 40fad6bae8
8 changed files with 381 additions and 9 deletions

View File

@ -0,0 +1,19 @@
# Usar imagen de python 3.9 slim
FROM python:3.9-slim
# Establece el directorio de trabajo
WORKDIR /app
# Copia el archivo requirements.txt e instala las dependencias
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copia el código fuente a /app
COPY app app
# Variables de entorno
ENV PYTHONUNBUFFERED 1
ENV PYTHONPATH=/app
# Comando para ejecutar la aplicación
CMD ["python", "app/main.py"]

View File

@ -1 +1,251 @@
# Prometheus - Grafana (próximamente)
# Configuración de Grafana con Prometheus para proyectos Python usando Docker
En este artículo, cubriremos cómo configurar el monitoreo de servicios para proyectos Python con Prometheus y Grafana utilizando contenedores Docker.
El monitoreo de servicios nos permite analizar eventos específicos en nuestros proyectos, tales como llamadas a bases de datos, interacción con API, seguimiento del rendimiento de recursos, etc. Puedes detectar fácilmente comportamientos inusuales o descubrir pistas útiles detrás de los problemas.
## Escenario de Caso Real
Teníamos un servicio temporal que redirigía las solicitudes entrantes de sitios web específicos hasta que Google dejara de indexar estas páginas web. Utilizando el monitoreo de servicios, podemos ver fácilmente el conteo de redirecciones de forma regular. En un momento determinado en el futuro, el número de redirecciones disminuirá, lo que significa que el tráfico se ha migrado al sitio web objetivo, y ya no necesitaremos que este servicio esté en funcionamiento.
## Configuración de contenedores Docker
Vamos a ejecutar todos nuestros servicios localmente en contenedores Docker. En las grandes empresas, existe un servicio global para Prometheus y Grafana que incluye todos los proyectos de monitoreo de microservicios. Probablemente ni siquiera necesites escribir ningún pipeline de despliegue para las herramientas de monitoreo de servicios.
### Archivo docker-compose.yml
Comencemos creando un archivo `docker-compose.yml` con los servicios necesarios:
```yaml
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ${PWD}/prometheus.yml:/etc/prometheus/prometheus.yml
restart: unless-stopped
networks:
- monitoring-net
healthcheck:
test: ["CMD", "wget", "--spider", "http://localhost:9090/-/healthy"]
interval: 1m30s
timeout: 30s
retries: 3
start_period: 30s
grafana:
hostname: grafana
image: grafana/grafana:latest
container_name: grafana
ports:
- 3001:3000
restart: unless-stopped
networks:
- monitoring-net
healthcheck:
test: ["CMD", "wget", "--spider", "http://localhost:3000/api/health"]
interval: 1m30s
timeout: 30s
retries: 3
start_period: 30s
app:
build:
context: .
dockerfile: Dockerfile
depends_on:
- prometheus
ports:
- "8080:8080"
networks:
- monitoring-net
command: ["python3", "app/main.py"]
networks:
monitoring-net:
driver: bridge
```
El punto más importante de la configuración anterior es montar el archivo `prometheus.yml` desde nuestra máquina local al contenedor Docker. Este archivo incluye la configuración para obtener datos (métricas) de nuestro servicio de aplicación o proyecto Python. Sin el archivo, no podrás ver las métricas personalizadas que incluye tu proyecto.
Por lo tanto, crea un nuevo archivo llamado `prometheus.yml` en el nivel raíz de tu proyecto.
### Archivo prometheus.yml
```yaml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'app'
static_configs:
- targets: ['app:8080']
```
Ahora, Prometheus obtendrá datos de nuestro proyecto.
Todas las demás configuraciones en el archivo de composición son autoexplicativas y no son muy críticas, como mencionamos para Prometheus.
## Crear un nuevo proyecto Python
Ahora, vamos a crear una aplicación Python muy sencilla que creará una métrica para rastrear el tiempo empleado y las solicitudes realizadas. Crea una nueva carpeta llamada `app` en el nivel raíz del proyecto. También incluye `__init__.py` para marcarla como un paquete Python.
A continuación, crea otro archivo llamado `main.py` que contendrá la lógica principal del programa, como se muestra a continuación:
### Archivo app/main.py
```python
from prometheus_client import start_http_server, Summary, Counter, Gauge, Histogram
import random
import time
# Create metrics to track time spent, requests made, and other events.
REQUEST_TIME = Summary('request_processing_seconds', 'Time spent processing request')
UPDATE_COUNT = Counter('update_count', 'Number of updates')
ACTIVE_REQUESTS = Gauge('active_requests', 'Number of active requests')
REQUEST_LATENCY = Histogram('request_latency_seconds', 'Request latency in seconds')
# Decorate function with metrics.
@REQUEST_TIME.time()
@REQUEST_LATENCY.time()
def process_request(t):
"""A dummy function that takes some time."""
ACTIVE_REQUESTS.inc()
time.sleep(t)
ACTIVE_REQUESTS.dec()
def main():
# Start up the server to expose the metrics.
start_http_server(8000)
print("[*] Starting server on port 8000...")
# Generate some requests.
while True:
msg = random.random()
process_request(msg)
update_increment = random.randint(1, 100)
UPDATE_COUNT.inc(update_increment)
print(f'[+] Processing request: {msg:.4f} | Updates: {update_increment}')
time.sleep(random.uniform(0.5, 2.0)) # Random delay between requests
if __name__ == '__main__':
main()
```
Aquí, estamos utilizando un paquete de Python llamado `prometheus_client` para interactuar con Prometheus. Permite fácilmente la creación de diferentes tipos de métricas que nuestro proyecto requiere.
El código anterior se copió de la documentación oficial de `prometheus_client`, que simplemente crea una nueva métrica llamada `request_processing_seconds` que mide el tiempo empleado en esa solicitud en particular. Cubriremos otros tipos de métricas más adelante en este artículo.
Ahora, vamos a crear un `Dockerfile` y un `requirements.txt` para construir nuestro proyecto.
### Archivo Dockerfile
```dockerfile
# Usa la imagen base oficial de Python
FROM python:3.9-slim
# Establece el directorio de trabajo
WORKDIR /app
# Copia los archivos de requerimientos
COPY requirements.txt .
# Instala las dependencias
RUN pip install --no-cache-dir -r requirements.txt
# Copia el código de la aplicación
COPY app/ /app
# Expone el puerto de la aplicación
EXPOSE 8000
# Comando por defecto para ejecutar la aplicación
CMD ["python", "main.py"]
```
### Archivo requirements.txt
```txt
prometheus_client
```
Ahora estamos listos para construir y ejecutar los servicios.
## Ejecución de los servicios
Para ver todo en acción, ejecuta los siguientes comandos:
```bash
docker-compose up -d --build
```
Esto levantará todos los servicios definidos en `docker-compose.yml`, compilando la imagen de la aplicación en el proceso.
## Configuración de Grafana
En esta sección, usaremos Prometheus como fuente de datos para mostrar métricas en gráficos de Grafana.
1. Navega a `http://localhost:3001` para ver la página de inicio de sesión de Grafana y utiliza `admin` tanto para el nombre de usuario como para la contraseña. Luego, requerirá agregar una nueva contraseña, y puedes mantenerla igual ya que estamos probando localmente.
2. Después de iniciar sesión correctamente, deberías ver el panel predeterminado de Grafana. Luego selecciona **Data Sources** en la página.
![](https://res.cloudinary.com/practicaldev/image/fetch/s--dckjv7Wt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.thepylot.dev/content/images/size/w1000/2022/06/Screen-Shot-2022-06-11-at-16.51.10.png)
3. A continuación, selecciona Prometheus como fuente de datos:
![](https://res.cloudinary.com/practicaldev/image/fetch/s--v5aNeycU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.thepylot.dev/content/images/size/w1000/2022/06/Screen-Shot-2022-06-11-at-16.53.47.png)
4. Luego requerirá la URL en la que se está ejecutando el servicio de Prometheus, que será el nombre del servicio de Docker que creamos `http://prometheus:9090`.
![](https://res.cloudinary.com/practicaldev/image/fetch/s--cSw8NHIy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.thepylot.dev/content/images/size/w1000/2022/06/Screen-Shot-2022-06-11-at-16.56.09.png)
5. Finalmente, haz clic en el botón **Save & Test** para verificar la conexión de la fuente de datos.
![](https://res.cloudinary.com/practicaldev/image/fetch/s--i4CVmg76--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%
2Cw_800/https://www.thepylot.dev/content/images/size/w1000/2022/06/Screen-Shot-2022-06-11-at-16.56.55.png)
¡Genial! Ahora nuestro Grafana está listo para ilustrar las métricas que provienen de Prometheus.
## Creación de un nuevo dashboard en Grafana
1. Navega a `http://localhost:3001/dashboards` para crear un nuevo dashboard y agregar un nuevo panel. Haz clic en **New Dashboard** y luego en **Add New Panel** para la inicialización.
![](https://res.cloudinary.com/practicaldev/image/fetch/s--yZiKAdWz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.thepylot.dev/content/images/size/w1000/2022/06/Screen-Shot-2022-06-11-at-17.02.21.png)
2. A continuación, seleccionamos código dentro del panel de consultas y escribimos `request_processing_seconds`. Podrás ver 3 tipos diferentes de sufijos con los datos de tus métricas personalizadas. Prometheus simplemente aplica diferentes tipos de cálculos a tus datos de manera predeterminada.
3. Selecciona una de las opciones y haz clic en **Run Query** para verla en el gráfico.
![](https://res.cloudinary.com/practicaldev/image/fetch/s--E8k1_d3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.thepylot.dev/content/images/size/w1000/2022/06/Screen-Shot-2022-06-11-at-17.14.32.png)
Finalmente, podemos ver las métricas de nuestro proyecto ilustradas muy bien por Grafana.
## Otras métricas
Hay muchos tipos de métricas disponibles según lo que requiera el proyecto. Si queremos contar un evento específico, como actualizaciones de registros en la base de datos, podemos usar `Counter()`.
Si tenemos una cola de mensajes como Kafka o RabbitMQ, podemos usar `Gauge()` para ilustrar el número de elementos que esperan en la cola.
Intenta agregar otra métrica en `main.py` como se muestra a continuación y aplica los mismos pasos para conectar Prometheus con Grafana:
### Ejemplo de una nueva métrica con Counter
```python
UPDATE_COUNT = Counter('update_count', 'Number of updates')
# Dentro de tu función de procesamiento
update_increment = random.randint(1, 100)
UPDATE_COUNT.inc(update_increment)
```
No olvides construir nuevamente la imagen de Docker para todos los servicios:
```bash
docker-compose up -d --build
```
---

View File

@ -0,0 +1,42 @@
from prometheus_client import start_http_server, Summary, Counter, Gauge, Histogram
import random
import time
# Create metrics to track time spent, requests made, and other events.
REQUEST_TIME = Summary('request_processing_seconds',
'Time spent processing request')
UPDATE_COUNT = Counter('update_count', 'Number of updates')
ACTIVE_REQUESTS = Gauge('active_requests', 'Number of active requests')
REQUEST_LATENCY = Histogram(
'request_latency_seconds', 'Request latency in seconds')
# Decorate function with metrics.
@REQUEST_TIME.time()
@REQUEST_LATENCY.time()
def process_request(t):
"""A dummy function that takes some time."""
ACTIVE_REQUESTS.inc()
time.sleep(t)
ACTIVE_REQUESTS.dec()
def main():
# Start up the server to expose the metrics.
start_http_server(8000)
print("[*] Starting server on port 8000...")
# Generate some requests.
while True:
msg = random.random()
process_request(msg)
update_increment = random.randint(1, 100)
UPDATE_COUNT.inc(update_increment)
print(
f'[+] Processing request: {msg:.4f} | Updates: {update_increment}')
time.sleep(random.uniform(0.5, 2.0)) # Random delay between requests
if __name__ == '__main__':
main()

View File

@ -0,0 +1,50 @@
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ${PWD}/prometheus.yml:/etc/prometheus/prometheus.yml
restart: unless-stopped
networks:
- monitoring-net
healthcheck:
test: ["CMD", "wget", "--spider", "http://localhost:9090/-/healthy"]
interval: 1m30s
timeout: 30s
retries: 3
start_period: 30s
grafana:
hostname: grafana
image: grafana/grafana:latest
container_name: grafana
ports:
- 3001:3000
restart: unless-stopped
networks:
- monitoring-net
healthcheck:
test: ["CMD", "wget", "--spider", "http://localhost:3000/api/health"]
interval: 1m30s
timeout: 30s
retries: 3
start_period: 30s
app:
build:
context: .
dockerfile: Dockerfile
depends_on:
- prometheus
ports:
- "8080:8080"
networks:
- monitoring-net
command: ["python3", "app/main.py"]
networks:
monitoring-net:
driver: bridge

View File

@ -0,0 +1,10 @@
global:
scrape_interval: 15s # when Prometheus is pulling data from exporters etc
evaluation_interval: 30s # time between each evaluation of Prometheus' alerting rules
scrape_configs:
- job_name: app # your project name
static_configs:
- targets:
- app:8000

View File

@ -0,0 +1 @@
prometheus-client

View File

@ -7,10 +7,10 @@
</div> </div>
| Nombre | Descripción | Nivel | | Nombre | Descripción | Nivel |
| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ---------- | | ----------------------------------------------------------------------- | ----------------------------------------------------- | ---------- |
| [redis](./01_redis_flask_docker/) | Despliegue de un contenedor de redis y flask | Básico | | [redis](./01_redis_flask_docker/) | Despliegue de un contenedor de redis y flask | Básico |
| [rabbit](./02_rabbitmq/README.md) | Despliegue de distintas arquitecturas para rabbitmq | Intermedio | | [rabbit](./02_rabbitmq/README.md) | Despliegue de distintas arquitecturas para rabbitmq | Intermedio |
| [Apache Kafka](./03_kafka/README.md) | Despliegue de Apache Kafka con productor y consumidor | Intermedio | | [Apache Kafka](./03_kafka/README.md) | Despliegue de Apache Kafka con productor y consumidor | Intermedio |
| [Elastic stack](./04_elastic_stack/README.md) | Despliegue de Elastic Stack | Básico | | [Elastic stack](./04_elastic_stack/README.md) | Despliegue de Elastic Stack | Básico |
| Prometheus Grafana (proximamente) <!-- [Prometheus Grafana](./05_prometheus_grafana/README.md) --> | Despliegue de un contenedor de Prometheus Grafana | Básico | | [Prometheus Grafana](./05_prometheus_grafana/README.md) | Despliegue de un contenedor de Prometheus Grafana | Básico |
| SonarQube (proximamente) <!-- [SonarQube](./06_sonarqube/README.md) --> | Despliegue de un contenedor de SonarQube | Básico | | SonarQube (proximamente) <!-- [SonarQube](./06_sonarqube/README.md) --> | Despliegue de un contenedor de SonarQube | Básico |