Ajout du monitoring automatique de vos applications locales avec Monday

Ajouter le moitoring de vos applications avec Monday

Si vous ne connaissez pas encore Monday, je vous invite à vous rendre sur https://github.com/eko/monday pour en apprendre plus dans un premier temps.

Rapidement, c'est un outil open-source que j'ai développé qui permet aux développeurs travaillant sur plusieurs micro-services à la fois de lancer des projets, ensemble d'applications lancées localement et de simuler l'exécution d'autres en faisant du port-forwarding depuis un environnement Kubernetes, une connexion SSH ou simplement en faisant du proxy TCP.

Monday schema

À mon sens il manquait une fonctionnalité qui me semble intéressante pour les développeurs : pouvoir avoir accès à du monitoring de leur application directement en local.

Pour la plupart des clients avec lesquels j'ai pu travailler jusqu'à maintenant, j'ai beaucoup utilisé Prometheus comme serveur de stockage des métriques temporelles et Grafana pour la visualisation.

J'ai donc dans cet article écrit un exemple permettant de lancer cette stack technique de monitoring mais l'important pour moi sur Monday étant de laisser le plus possible la main aux développeurs et ainsi leur permettre d'implémenter la solution qu'ils désirent.

Aussi, il me semble intéressant de partager avec vous les étapes de réflexion pour la mise en place de cette fonctionnalité, permettant de :

  • Faire évoluer l'outil avec de nouvelles fonctionnalités,
  • Garder un comportement ouvert, ne fermant pas la porte aux développeurs pour d'autres intégrations.

Pré-requis pour l'exécution de Grafana et Prometheus

Après un rapide état des lieux du projet, pour pouvoir ajouter Grafana et Prometheus et avoir du monitoring automatique, à tout moment, en fonction des différentes grappes de service que je souhaitais lancer, il me manquait quelques fonctionnalités essentielles.

Avant de commencer, un petit rappel sur le fonctionnement de Prometheus et Grafana avec ce petit schema :

Grafana and Prometheus

  • Prometheus va venir récupérer les métriques des applications que nous allons déclarer dans son fichier de configuration,
  • Grafana va venir intérroger la base de données timeseries Prometheus pour récupérer les métriques et les afficher sur des dashboard que vous aurez créés.

Lancer des applications de manière globale

Jusqu'ici, un projet est déclaré comme suit :

projects:
 - name: project-a
   local:
    - *service-a-local
   forward:
    - *service-b-forward
 - name: project-b
   local:
    - *service-b-local
   forward:
    - *service-c-forward

Si j'avais voulu ajouter Grafana et Prometheus, j'aurais dû les ajouter pour les deux projets, cette première pull request m'a donc permis d'ajouter la notion de globalité sur les applications locales et de forward, ainsi, je peux maintenant déclarer à la racine de la configuration YAML :

local:
  - *grafana-global
  - *prometheus-global
forward:
  - *graylog-forward-kubernetes

Simple, efficace, des applications locales ou des port-forward peuvent désormais être effectués dans tous les cas.

Pouvoir générer des fichiers de configuration

Grafana et Prometheus pouvant maintenant être exécutés, il fallait maintenant générer les fichiers de configuration suivants :

  • Prometheus : répertorier les applications pour lesquelles les métriques doivent être récupérées (scrapping),
  • Grafana : déclarer l'URL du serveur Prometheus comme source de données (datasource).

Ces deux besoins représentent en fait un seul besoin : pouvoir déclarer pour une application locale des fichiers, et pouvoir générer dynamiquement ces fichiers à partir des valeurs fournies dans la configuration de l'utilisateur.

Le package text/template de Go m'a été très utile pour cette fonctionnalité, comme vous pouvez le voir dans la pull request suivante.

Il permet en effet l'utilisation d'une syntaxe permettant de parcourir un objet Go ou encore d'ajouter des fonctions pouvant être utilisées dans le template.

Pour écrire un template, rien de plus simple :

content := `
{{- range $app := .Applications }}
Application: {{ $app.Name }}
{{- end }}
`
t := template.Must(template.New("/my/output/file").Parse(content))
_ = t.Execute(f, project) // project est ici la struct représentant le projet courant

Ainsi, pour le projet project-a donné plus haut, la sortie dans le fichier /my/output/file ici correspondant au nom donné à mon application locale service-a :

Application: Service A

Cette fonctionnalité mise en place, nous sommes donc maintenant capable de déclarer, pour des applications locales, une section files permettant de générer les fichiers de configuration, comme celui de Prometheus par exemple :

<: &prometheus-global
  name: prometheus
  ...
  files:
    - type: content
      to: ~/.monday/prometheus-2.22.1.darwin-amd64/prometheus.yml
      content: | # Prepare the Prometheus configuration with all services that have to be scrapped from monday
        global:
          scrape_interval:     15s
          evaluation_interval: 15s
        scrape_configs:
          {{- range $app := .Applications }}
          {{- if $app.Monitoring }}
          - job_name: '{{ $app.Name }}'
            static_configs:
              - targets: ['{{ $app.Hostname }}:{{ $app.Monitoring.Port }}']
            metrics_path: {{ $app.Monitoring.URL }}
          {{- end }}
          {{- end }}

La même fonctionnalité est utilisée pour créer les configurations Grafana nécessaires.

Mise en place du monitoring

Nous avons maintenant toutes les fonctionnalités nécessaires !

La dernière pull request consistait uniquement à ajouter dans les entrées de configuration YAML une section monitoring (utilisée dans le template de configuration Prometheus juste avant) afin de pouvoir déclarer pour chaque application, sur quel hostname / port et URL Prometheus doit venir chercher les données.

Sur une application, il nous faut donc simplement ajouter les sections suivantes :

<: &service-a-local
  name: Service A
  ...
  hostname: service-a.svc.local
  monitoring:
    port: 8001
    url: /metrics

Notez qu'il est aussi possible de spécifier cette configuration sur une application de type forward, car après tout vous pouvez aussi accéder à leurs métriques, même si elles ne sont pas directement exécutées chez vous, pourquoi se priver ?

Voici donc les configurations complètes pour Grafana et Prometheus permettant d'ajouter le monitoring à vos micro-services en local :

Configuration Monday pour Prometheus

# Defines Prometheus server setup steps and configuration files
<: &prometheus-global
  name: prometheus
  path: ~/.monday/prometheus-2.22.1.darwin-amd64
  hostname: "prometheus.svc.local"
  setup:
    commands:
      - mkdir -p ~/.monday/download
      - curl -Lo ~/.monday/download/prometheus.tar.gz https://github.com/prometheus/prometheus/releases/download/v2.22.1/prometheus-2.22.1.darwin-amd64.tar.gz
      - tar -xzvf ~/.monday/download/prometheus.tar.gz --directory ~/.monday/
      - rm -rf ~/.monday/download/prometheus*
  run:
    command: ./prometheus
  files:
    - type: content
      to: ~/.monday/prometheus-2.22.1.darwin-amd64/prometheus.yml
      content: | # Prepare the Prometheus configuration with all services that have to be scrapped from monday
        global:
          scrape_interval:     15s
          evaluation_interval: 15s
        scrape_configs:
          {{- range $app := .Applications }}
          {{- if $app.Monitoring }}
          - job_name: '{{ $app.Name }}'
            static_configs:
              - targets: ['{{ $app.Hostname }}:{{ $app.Monitoring.Port }}']
            metrics_path: {{ $app.Monitoring.URL }}
          {{- end }}
          {{- end }}

Configuration Monday pour Grafana

# Defines Grafana setup steps and configuration files
<: &grafana-global
  name: grafana
  path: ~/.monday/grafana-7.1.5
  hostname: "grafana.svc.local"
  setup:
    commands:
      - mkdir -p ~/.monday/download
      - curl -Lo ~/.monday/download/grafana.tar.gz https://dl.grafana.com/oss/release/grafana-7.1.5.darwin-amd64.tar.gz
      - tar -xzvf ~/.monday/download/grafana.tar.gz --directory ~/.monday/
      - rm -rf ~/.monday/download/grafana*
  run:
    command: ./bin/grafana-server web
  files:
    - type: content
      to: ~/.monday/grafana-7.1.5/conf/provisioning/datasources/prometheus.yml
      content: | # Specify the Prometheus datasource in Grafana
        apiVersion: 1
        datasources:
          - name: prometheus
            type: prometheus
            access: proxy
            url: http://prometheus.svc.local:9090
    - type: content
      to: ~/.monday/grafana-7.1.5/conf/provisioning/dashboards/monday.yml
      content: | # In case you want to provision some dashboards, specify the path
        apiVersion: 1
        providers:
          - name: 'monday'
            orgId: 1
            folder: ''
            type: file
            disableDeletion: false
            editable: true
            options:
              path: $HOME/.monday/grafana-7.1.5/conf/provisioning/dashboards
    - type: copy # In case you want to prepare a Grafana dashboard that will be provisionned with Grafana
      from: ~/.monday/grafana-dashboard.json
      to: ~/.monday/grafana-7.1.5/conf/provisioning/dashboards/dashboard.json

Note : si vous êtes sous linux, pensez à modifier darwin en linux.

Conclusion

Notez qu'avec la déclaration des étapes de setup, un développeur de l'équipe aura simplement à copier ces nouvelles configurations et à la fois Prometheus et Grafana seront automatiquement installés et exécutés lorsqu'il utilisera Monday.

Il pourra alors accéder à son interface Grafana en se rendant sur http://grafana.svc.local:3000 et, si besoin, Prometheus via http://prometheus.svc.local:9090.