Implementation de la stack de monitoring (Prometheus, Grafana, Alert Manager) dans des conteneur Docker … Partie 3

Nous avons vu dans la première partie de cette série comment mettre en place le monitoring avec prometheus et dans la seconde comment consulter ses dashboard en utilisant le populaire outil grafana. Dans cet article nous allons parler du dernier élément(tout aussi important et vital que les 2 premiers) de la stack qui n’est autre que l’alerting.

En effet, c’est bien beau d’avoir un monitoring en place et de belles visualisations pour suivre l’activité, mais il faut absolument rajouter à cela un système qui va vous alerter immédiatement lorsqu’un problème va se produire. Une mise en place et une gestion efficace des alertes est donc primordiale en production.

Alertmanager est un module de prometheus qui a justement pour but d’adresser la partie alerting. Il fonctionne en liaison avec prometheus car en fait les règles et les seuils d’alertes sont définis dans prometheus et lorsqu’une alerte est déclenchée cette dernière est envoyée par prometheus vers l’instance alert manager. Dans alert manager elle va subir un ensemble de traitements internes à travers un pipeline jusqu’à l’envoi ou pas vers un ou plusieurs canaux de notification (Email, slack, sms, etc).

Le pipeline en question va réaliser les opération ci-dessous :

  • Le Groupage : Les alertes peuvent être regroupées en une seule notification afin d’éviter d’envoyer de nombreuses notifications pour le même problème. Par exemple une alerte de saturation mémoire sur plusieurs vms, une seule alerte peut être envoyée contenant la liste des vms impactée.
  • La mise en silence : Il est possible de muter temporairement une alerte si on ne veut plus recevoir de notification sur le problème. Par exemple un problème connu et qui sera réglé à une date ultérieure.
  • L’inhibition qui va désactiver la notification pour des problèmes dont une alerte relative a deja été envoyée. Par exemple si on a une alerte concernant un datacenter devient inaccessible, alors alertmanager peut inhiber toutes les autres alertes issues des vm de ce datacenter vu que le problème réel est du fait qu’il soit inaccessible.
  • Envoi de la notification : Le dernier traitement de la chaîne est l’envoi de la notification vers les destinataire définis sur un ou plusieurs canaux configurés.

Installation

Nous allons voir maintenant comment rapidement déployer une instance d’alert manager sur docker.

Installer alert manager

  • Créer un dossier qui va contenir la configuration
  • Créer le fichier de configuration pour alert manager, vous pouvez vous inspirer de celui ci-dessous qui envoi les notifications par mail et contient une configuration basique de pipeline.

$vim config.yml

global:

  # The smarthost and SMTP sender used for mail notifications.

  smtp_smarthost: ‘smtp.host’

  smtp_from: ‘mail from’

  smtp_auth_username: smtpuser

  smtp_auth_password: ‘smtppassword’

# The root route on which each incoming alert enters.

route:

  # The root route must not have any matchers as it is the entry point for

  # all alerts. It needs to have a receiver configured so alerts that do not

  # match any of the sub-routes are sent to someone.

  receiver: ‘team-admins’

  # The labels by which incoming alerts are grouped together. For example,

  # multiple alerts coming in for cluster=A and alertname=LatencyHigh would

  # be batched into a single group.

  group_by: [‘alertname’, ‘cluster’]

  # When a new group of alerts is created by an incoming alert, wait at

  # least ‘group_wait’ to send the initial notification.

  # This way ensures that you get multiple alerts for the same group that start

  # firing shortly after another are batched together on the first

  # notification.

  group_wait: 30s

  # When the first notification was sent, wait ‘group_interval’ to send a batch

  # of new alerts that started firing for that group.

  group_interval: 5m

  # If an alert has successfully been sent, wait ‘repeat_interval’ to

  # resend them.

  repeat_interval: 3h

  # All the above attributes are inherited by all child routes and can 

  # overwritten on each.

  # The child route trees.

  routes:

  – match:

      severity: critical

    receiver: team-admins

# Inhibition rules allow to mute a set of alerts given that another alert is

# firing.

# We use this to mute any warning-level notifications if the same alert is

# already critical.

inhibit_rules:

– source_match:

    severity: ‘critical’

  target_match:

    severity: ‘warning’

  # Apply inhibition if the alertname is the same.

  equal: [‘alertname’]

receivers:

– name: ‘team-admins’

  email_configs:

  – to: ‘admin@example.com’

  • Editer votre fichier docker-config.yml

$vim docker-config.yml

version: ‘3.2’

services:

  alertmanager:

    image: prom/alertmanager

    ports:

    – ‘9093:9093’

    volumes:

    – ‘.config.yml:/etc/alertmanager/config.yml’

    restart: always

    command:

    – ‘–config.file=/etc/alertmanager/config.yml’

    – ‘–storage.path=/alertmanager’

  • Demarrer alert manager

$docker-compose up -d

  • Vérifier que votre conteneur est bien en cours d’exécution 

Reconfigurer prometheus

  • Revenez sur votre dossier d’installation prometheus et créer un fichier alerts.yml qui va contenir les règles. Inspirez-vous du fichier ci-dessous pour vos tests, ce sont des règles compatibles avec le node-exporter qui a été installé dans la première partie.

$vim alerts.yml

groups:

  – name: default

    rules:

    – alert: InstanceDown

      expr: up == 0

      for: 5m

      labels:

        severity: critical

      annotations:

        summary: “Instance {{ $labels.instance }} down”

        description: “{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes.”

  – name: nodeExporter

    rules:

    – alert: OutOfMemory

      expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “Out of memory (instance {{ $labels.instance }})”

        description: “Node memory is filling up (< 10% left)\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: UnusualNetworkThroughputIn

      expr: sum by (instance) (irate(node_network_receive_bytes_total[2m])) / 1024 / 1024 > 100

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “Unusual network throughput in (instance {{ $labels.instance }})”

        description: “Host network interfaces are probably receiving too much data (> 100 MB/s)\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: UnusualNetworkThroughputOut

      expr: sum by (instance) (irate(node_network_transmit_bytes_total[2m])) / 1024 / 1024 > 100

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “Unusual network throughput out (instance {{ $labels.instance }})”

        description: “Host network interfaces are probably sending too much data (> 100 MB/s)\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: UnusualDiskReadRate

      expr: sum by (instance) (irate(node_disk_read_bytes_total[2m])) / 1024 / 1024 > 50

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “Unusual disk read rate (instance {{ $labels.instance }})”

        description: “Disk is probably reading too much data (> 50 MB/s)\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: UnusualDiskWriteRate

      expr: sum by (instance) (irate(node_disk_written_bytes_total[2m])) / 1024 / 1024 > 50

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “Unusual disk write rate (instance {{ $labels.instance }})”

        description: “Disk is probably writing too much data (> 50 MB/s)\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: OutOfDiskSpace

      expr: node_filesystem_free_bytes{mountpoint =”/rootfs”} / node_filesystem_size_bytes{mountpoint =”/rootfs”} * 100 < 20

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “Out of disk space (instance {{ $labels.instance }})”

        description: “Disk is almost full (< 10% left)\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: OutOfInodes

      expr: node_filesystem_files_free{mountpoint =”/rootfs”} / node_filesystem_files{mountpoint =”/rootfs”} * 100 < 20

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “Out of inodes (instance {{ $labels.instance }})”

        description: “Disk is almost running out of available inodes (< 10% left)\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: UnusualDiskReadLatency

      expr: rate(node_disk_read_time_seconds_total[1m]) / rate(node_disk_reads_completed_total[1m]) > 100

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “Unusual disk read latency (instance {{ $labels.instance }})”

        description: “Disk latency is growing (read operations > 100ms)\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: UnusualDiskWriteLatency

      expr: rate(node_disk_write_time_seconds_total[1m]) / rate(node_disk_writes_completed_total[1m]) > 100

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “Unusual disk write latency (instance {{ $labels.instance }})”

        description: “Disk latency is growing (write operations > 100ms)\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: HighCpuLoad

      expr: 100 – (avg by(instance) (irate(node_cpu_seconds_total{mode=”idle”}[5m])) * 100) > 80

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “High CPU load (instance {{ $labels.instance }})”

        description: “CPU load is > 80%\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

    – alert: SystemdServiceCrashed

      expr: node_systemd_unit_state{state=”failed”} == 1

      for: 5m

      labels:

        severity: warning

      annotations:

        summary: “SystemD service crashed (instance {{ $labels.instance }})”

        description: “SystemD service crashed\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}”

  • Modifier le fichier de configuration prometheus pour inclure le fichier des alertes

# Alertmanager configuration

alerting:

  alertmanagers:

  – static_configs:

    – targets:

      – :9093

# Load rules once and periodically evaluate them according to the global ‘evaluation_interval’.

rule_files:

  – ‘alerts.yml’

  • Monter le fichier alerts.yml dans le conteneur prometheus en éditant le fichier docker-compose et rajoutant la ligne ci-dessous

– ‘./alerts.yml:/etc/prometheus/alerts.yml’

  • Relancer votre conteneur prometheus

$docker-compose up -d

Voila ! désormais vous serez notifié en temps réel en cas de problème. 

Cela conclut la série d’articles sur la mise en place assez simplement d’un système de monitoring gratuit et opensource pour votre infrastructure.

Bien Sûr il ne s’agit que d’une introduction, n’hésitez pas a vous référez à la documentation des divers produits pour plus d’informations et aussi d’éventuelles nouvelles fonctionnalités.

Partager:

Facebook
Twitter
LinkedIn