24 juin 2020

Cabourotte: un outil de monitoring pour tester l'état de vos services

J’ai décidé aujourd’hui de sortir et d’annoncer une première version de mon nouveau projet Open Source: Cabourotte. Cet outil permet de réaliser périodiquement différents types de healthchecks sur vos services, et bien plus encore !

Le besoin

On a généralement d’une manière ou une autre des healthchecks qui s’exécutent sur nos applications pour vérifier si elles fonctionnent correctement ou non.

Ces healthchecks peuvent par exemple être réalisés par vos outils de service discovery ou de déploiements comme Consul ou Kubernetes qui tout deux exécutent des healthchecks locaux sur les applications gérées, ou par des outils de monitoring.

Mais par expérience, un healthcheck exécuté par un agent tournant sur le même serveur que l’application n’est pas suffisant. Le réseau, de plus en plus complexe dans nos environnements actuels, n’est pas fiable.

Qui vous dit que vos services sont joignables depuis l’entièreté de votre infrastructure, ou depuis un autre pays ou continent ? Peut être que certains serveurs n’arrivent plus à accéder (pendant un temps limité ou non) à certain services suite par exemple à un changement de topologie réseau.

C’est pour vérifier cela que j’ai écrit Cabourotte. Cet agent, léger, écrit en Go, est capable aujourd’hui d’exécuter différents types de healthchecks (TCP, HTTP(s), DNS) et de reporter le résultat de ces healthchecks de différentes manières.
D’autres fonctionnalités que je décrirai dans la suite de cet article sont aussi présentes.

Les binaires de la première release sont trouvables sur Github.

Configuration

Je vais répéter un peu le README dans cet article, donc n’hésitez pas à le consulter pour avoir un complément d’information.

Les healthchecks peuvent se configurer de deux manières:

  • Soit via un fichier de configuration YAML.

  • Soit via une API.

Les deux systèmes n’entrent pas en conflit, il est possible de définir des healthchecks des deux manières sans problème sur la même instance du daemon.

Prenons par exemple ce fichier de configuration:

http:
  host: "127.0.0.1"
  port: 9013
dns_checks:
  - name: "mcorbin-dns-check"
    description: "dns healthcheck example"
    domain: "mcorbin.fr"
    interval: 5s
http_checks:
  - name: "mcorbin-http-check"
    description: "http healthcheck example"
    valid_status:
      - 200
      - 201
    target: "mcorbin.fr"
    port: 443
    protocol: "https"
    path: "/"
    timeout: 5s
    interval: 10s
tcp_checks:
  - name: "mcorbin-tcp-check"
    description: "tcp healthcheck example"
    target: "mcorbin.fr"
    port: 443
    timeout: 2s
    interval: 10s
exporters:
  http:
    - host: "127.0.0.1"
      port: 9595
      path: "/"
      protocol: "http"

Je définis ici l’IP et le port de l’API exposée par le daemon (en passant, mTLS est supporté pour le serveur HTTP), puis définit trois healthchecks:

  • Un healthcheck de type DNS sur mcorbin.fr qui s’exécutera toutes les 5 secondes

  • Un healthcheck de type HTTP (une requête GET) sur le même site toutes les 10 secondes. Là aussi, mTLS est supporté. Les status HTTP attendus sont configurables, et je prévois d’ajouter dans le futur la possibilité d’exécuter des requêtes de différents types (POST, PUT…​), de configurer les headers, paramètres…​ pour ce type de healthcheck.

  • Un healthcheck de type TCP, là aussi toutes les 10 secondes.

Au démarrage, ces healthchecks vont commencer à s’exécuter. Par défaut, le résultat de chaque healthcheck est:

  • Loggé dans stdout, par exemple {"level":"info","ts":1592948336.1519916,"caller":"exporter/root.go:115","msg":"Healthcheck successful","name":"mcorbin-dns-check","date":"2020-06-23 23:38:56.151955119 +0200 CEST m=+4605.356906567"}

  • Disponible sur le endpoint /metrics: ce endpoint contient, en plus de métriques génériques au format Prometheus sur l’application et ses composants, le résultat (sous forme de counter prometheus) de chaque healthcheck, par status (success ou failure). Le temps d’exécution de chaque healthcheck par status est aussi disponible (ce qui permet donc de monitorer également la latence).
    Cela vous permettra de configurer des alertes et de créer des graphes sur ses healthchecks très facilement.

  • Récupérable via l’API, mais j’en parlerai un peu plus loin.

Cabourotte peut également exporter les résultats au fil de l’eau dans des exporters.
Dans ce fichier de configuration, je passe le résultat des healthchecks à un exporter HTTP (le seul disponible actuellement). La cible recevra le résultat de chaque healthcheck. D’autres exporters, comme Kafka, seront rajoutés dans le futur.

Le memory store

Comme dit précédemment, le status des healthchecks est récupérable via l’API. En effet, le dernier résultat de chaque healthcheck est récupérable sur le endpoint /result, et /result/<healthcheck-name> pour un healthcheck spécifique.

Les résultats vieux de plus de 120 secondes sont automatiquement supprimés de ce store.

L’API

L’API permet:

  • De récupérer la liste des healthchecks actuellement configurés.

  • D’ajouter, mettre à jour, supprimer des healthchecks.

  • Comme dit précédemment, de récupérer le résultat des healthchecks.

  • Un endpoint /health (ou /healthz) permet de savoir si le daemon est démarré.

One-Off checks

L’API permet de créer des healthchecks de type "One-Off".

Que celui qui n’a jamais fait un netcat ou un curl pour tester la connexion entre deux machines me jette la première pierre.
Lorsqu’un healthcheck est créé via l’API avec l’option one-off à true, le healthcheck est immédiatement exécuté et le résultat retourné dans la réponse HTTP (et le healthcheck ne sera pas exécuté périodiquement).

Cela permet d’exécuter rapidement des healthchecks si besoin est. Un exemple où j’exécute deux healthchecks de type DNS en one-off via l’API, un en succès et un en erreur:

mathieu@mathieu:~$ curl -H "Content-Type: application/json" 127.0.0.1:9013/healthcheck/dns -d '{"name":"mcorbin-dns-check","description":"dns healthcheck example","domain":"mcorbin.fr","interval":"5s","one-off":true}'

{"message":"One-off healthcheck mcorbin-dns-check successfully executed"}

mathieu@mathieu:~$ curl -H "Content-Type: application/json" 127.0.0.1:9013/healthcheck/dns -d '{"name":"mcorbin-dns-check","description":"dns healthcheck example","domain":"doesnotexist.mcorbin.fr","interval":"5s","one-off":true}'

{"message":"Execution of one off healthcheck mcorbin-dns-check failed: Fail to lookup IP for domain: lookup doesnotexist.mcorbin.fr on 192.168.1.1:53: no such host"}

Hot Reload

Le daemon se reload sur un SIGHUP.

Les healthchecks en cours configurés via API, ou via le YAML et non modifiés continuent de fonctionner comme rien n’était.
Les healthchecks modifiés, supprimés, ou ajoutés sont gérés comme attendus.

Le serveur HTTP est aussi redémarré proprement en cas de changement de configuration. Les exporters sont eux stoppés et relancés, mais je prévois d’améliorer ce point dans le futur (pour ne pas stopper un exporter si cela n’est pas nécessaire).

Conclusion

Le projet permet déjà de réaliser un certain nombre de choses.

Gardez en tête que c’est la toute première release, que j’ai écris le projet assez rapidement sur mon temps libre, et que je prévois encore un certain nombre de refactoring dans le code.

Mais je suis globalement assez content de l’état actuel du projet et j’espère que vous trouverez cela également intéressant.

J’aimerai ajouter d’autres types de checks (validité de certificats et expiration par exemple), et peut être écrire une CLI pour intéragir avec le projet.

J’aimerai également dans le futur intégrer le daemon avec des outils comme Consul ou Kubernetes (via un Operator ?) pour pouvoir automatiquement détecter les applications à monitorer. C’est d’ailleus pour cela que le daemon supporte dès maintenant une API pour configurer les healthchecks en plus du fichier de configuration YAML.

Imaginez si vous pouviez automatiquement exécuter des healthchecks d’un peu partout avec une configuration totalement automatisée. Peut être un jour ?

Plus d’infos dans les semaines à venir !

Tags: devops cloud
Top of page