DataDome

Comment DataDome a développé un exportateur de métriques personnalisé pour GitHub Actions

Table des matières

Ces dernières années, GitHub Actions s’est imposé comme un standard incontournable pour l’automatisation, l’intégration continue (CI) et la livraison continue (CD).

Depuis plus de quatre ans, GitHub permet aux utilisateurs de gérer leur CI/CD au sein de leurs propres infrastructures cloud grâce aux exécuteurs auto-hébergés. Cette approche nous a permis de réduire les coûts liés à l’exécution des GitHub Actions, tout en gardant un contrôle total sur l’infrastructure, renforçant ainsi la sécurité de la solution.

Dans cet article, nous allons expliquer comment DataDome a développé un exportateur Prometheus sur mesure pour gérer l’infrastructure des exécuteurs GitHub Actions auto-hébergés à grande échelle. Après une brève présentation de notre infrastructure d’exécuteurs GitHub (ou runners), nous nous pencherons sur l’importance de la surveillance de l’infrastructure déployée pour fournir une visibilité sur la santé et les performances des runners.

Chez DataDome, nous gérons :

  • des centaines de dépôts GitHub,
  • des centaines d’exécutions de workflows GitHub chaque jour,
  • différents types d’exécuteurs prenant en charge diverses charges de travail,
  • une multitude de contrôles pour évaluer la qualité des livraisons, y compris des tests de performance automatisés, des tests de non-régression, ainsi que des contrôles de conformité.

GitHub Actions est indéniablement une solution centrale pour garantir un niveau de qualité constant lors des déploiements en production.

Les exécuteurs auto-hébergés GitHub chez DataDome

Lorsque l’on recherche une infrastructure de runners évolutive, le choix est clair entre deux frameworks populaires :

Nous avons choisi la deuxième solution en toute confiance pour plusieurs raisons. D’une part, elle nous a permis de migrer nos CI existantes avec des coûts d’ingénierie réduits. De plus, nous avons pu exploiter le module open-source des runners auto-hébergés de Philips, qui offre d’importantes capacités de personnalisation.

Cette flexibilité nous a conduits à établir les objectifs suivants :

  • réduire au maximum les coûts d’infrastructure liés aux exécuteurs auto-hébergés ;
  • utiliser des exécuteurs éphémères pour plus d’efficacité,
  • optimiser la réactivité de la solution.

Pour répondre à ces exigences, notre équipe technique a évalué l’utilisation de GitHub Actions. Cela nous a permis de pré-approvisionner des exécuteurs afin de réduire les temps d’attente pour l’exécution de GitHub Actions. Nous réduisons également le nombre de runners pré-approvisionnés pendant les périodes de faible demande, tout en conservant la capacité de déclencher des exécuteurs à la demande. Cela nous permet de déployer facilement des centaines d’exécuteurs par jour.

Graphique du nombre de runners dans GitHub Actions

Runners auto-hébergés et surveillance de GitHub Actions

Il est crucial de surveiller en temps réel l’infrastructure pour garantir une utilisation optimale et assurer la disponibilité continue pour nos équipes techniques.

Sans mesures précises, gérer un volume important de GitHub Actions devient rapidement complexe. Plusieurs raisons justifient la surveillance de l’utilisation des GitHub Actions : détecter les échecs de CI/CD, optimiser l’exécution des tâches ou encore garantir la fiabilité des livraisons. C’est réalisable dans l’interface utilisateur de GitHub si vous n’avez que quelques GitHub Actions, mais cela devient un défi sans les métriques et le suivi appropriés avec un grand volume de GitHub Actions.

Notre première approche a été d’explorer les exportateurs Prometheus existants, spécialisés dans le suivi de l’utilisation de GitHub Actions. Nous recherchions un exportateur capable de collecter les mesures nécessaires pour chaque catégorie d’exécuteur :

  • état du runner (inactif, actif, hors-ligne) : pour avoir une vue d’ensemble de la charge de travail disponible et de la capacité d’exécution ;
  • durée des workflows et des tâches : pour mesurer le temps d’exécution et identifier des leviers d’optimisation des GitHub Actions ;
  • durée de mise en route : pour évaluer le temps d’attente avant que les tâches GitHub ne soient prises en charge par les exécuteurs auto-hébergés.

Limitations des exportateurs Prometheus existants

GitHub ne propose pas d’exportateur officiel pour Prometheus, mais la communauté en a développé plusieurs, chacun avec ses forces et ses faiblesses. Cependant, aucun de ces outils n’a pleinement satisfait nos exigences. Même les options les plus avancées présentaient des lacunes dans deux domaines critiques :

  • pas de mesure de la durée de mise en route des runners, nous laissant sans visibilité sur la manière dont l’infrastructure réagit aux pics de charge ;
  • notre organisation GitHub, avec ses nombreux dépôts, générait un grand volume de requêtes vers l’API GitHub, ce qui entraînait une saturation du quota d’appels, rendant l’exportateur quasiment inutilisable.

Face à ces contraintes, nous avons décidé de développer notre propre exportateur.

Conception d’un exportateur Prometheus personnalisé

Notre exportateur sur mesure collecte des données sur les runners et l’exécution des GitHub Actions en effectuant des appels à l’API REST de GitHub. Il est basé sur le célèbre package Python prometheus-client.

Optimisation des requêtes via le filtrage des dépôts

Étant donné le grand nombre de dépôts GitHub chez DataDome, nous avons rapidement été confrontés aux limites de taux imposées par GitHub. En effet, GitHub applique deux types de limites de taux pour les appels à son API REST :

  • la limite de taux primaire : limite à 12 500 le nombre de requêtes par heure, ce seuil variant en fonction du nombre d’utilisateurs et de dépôts dans l’organisation ;
  • la limite de taux secondaire : limite le nombre de demandes simultanées envoyées à l’API de GitHub. Cela réduit les possibilités pour les exportateurs multithreads.

Pour contourner ces limitations, nous avons mis en place un filtrage efficace des dépôts, réduisant ainsi le nombre de requêtes tout en conservant une surveillance précise et complète.

Ces limitations nous ont obligés à adopter une approche optimisée pour les requêtes envoyées à l’API GitHub, tout en fournissant des mesures suffisantes pour une analyse correcte de l’utilisation de l’exécuteur auto-hébergé chez DataDome.

Chaque dépôt GitHub génère potentiellement un certain nombre de requêtes pour récupérer des informations liées à chaque flux de travail et à chaque tâche, ce qui représente une source importante de requêtes à l’API de GitHub. Par conséquent, nous avons décidé de ne recueillir que les métriques de GitHub Actions sur :

  • les dépôts privés : les exécuteurs auto-hébergés ne doivent pas être utilisés sur des dépôts publics ;
  • les dépôts non archivés : ces dépôts ne sont pas pertinents pour de telles mesures ;
  • les dépôts actifs au cours de la dernière semaine : pour ne cibler que les dépôts ayant une activité récente.

Grâce à ce filtrage, nous avons réduit le nombre de dépôts à surveiller de plus de 400 à 70, réduisant ainsi le nombre de requêtes à l’API de GitHub de plus de quatre fois.

Collecte des informations pertinentes sur les runs et jobs

Après avoir affiné la liste des dépôts pertinents, nous devons collecter des métriques sur les workflows GitHub qui leur sont associés.

L’API GitHub fournit de nombreuses données, mais nous nous concentrons sur la collecte des informations relatives à l’exécution des jobs et aux exécuteurs qui leur sont associés, afin de suivre au mieux leur performance et utilisation.

Pour ce faire, nous récupérons la liste des flux de travail associés à chaque dépôt. Ensuite, pour chacun d’entre eux, nous recherchons les exécutions associées (car les workflows peuvent être relancés, en totalité ou en partie, depuis l’interface GitHub). Enfin, nous extrayons les informations sur les jobs à partir de chaque exécution de run.

{
"id": 399444496,
"run_id": 29679449,
[...]
"status": "completed",
"conclusion": "success",
"started_at": "2020-01-20T17:42:40Z",
"completed_at": "2020-01-20T17:44:39Z",
"name": "build",
"steps": [
{
"name": "Set up job",
"status": "completed",
"conclusion": "success",
"number": 1,
"started_at": "2020-01-20T09:42:40.000-08:00",
"completed_at": "2020-01-20T09:42:41.000-08:00"
}
[...]
],
"check_run_url": "https://api.github.com/repos/octo-org/octo-repo/check-runs/399444496",
"labels": [
"self-hosted",
],
"runner_id": 1,
"runner_name": "my runner",
"runner_group_id": 2,
"runner_group_name": "my runner group",
"workflow_name": "CI",
"head_branch": "main"
}

Informations complémentaires sur GitHub

En plus des métriques déjà collectées, nous obtenons également :

  • l’état (actif, inactif, hors ligne) de chaque exécuteur enregistré dans notre organisation GitHub ;
  • l’utilisation de la facturation de notre organisation GitHub ;
  • le nombre de requêtes effectuées vers l’API GitHub.

Ces mesures finales nous offrent une vue précise des exécuteurs déployés à tout moment et nous permettent de surveiller l’utilisation de notre quota pour les exécuteurs hébergés par GitHub.

Ces informations sont cruciales pour nous, car notre plan d’abonnement inclut 3 000 minutes de temps de calcul. Bien que nous puissions migrer l’ensemble de nos workflows GitHub vers des exécuteurs auto-hébergés, nous choisissons, pour optimiser les coûts, d’utiliser les runners hébergés par GitHub pour les GitHub Actions non critiques et à exécution rapide.

Mesures disponibles

Notre exportateur Prometheus expose les mesures suivantes :

# HELP runner_nb_idle Number of idle runners
# TYPE runner_nb_idle gauge
runner_nb_idle{runner_label="self-hosted-runner"} 9.0
# HELP runner_nb_busy Number of busy runners
# TYPE runner_nb_busy gauge
runner_nb_busy{runner_label="self-hosted-runner"} 4.0
# HELP runner_nb_offline Number of offline runners
# TYPE runner_nb_offline gauge
runner_nb_offline{runner_label="self-hosted-runner"} 0.0
# HELP runner_workflow_queued Number of queued workflow
# TYPE runner_workflow_queued gauge
runner_workflow_queued{repository="DataDome/repository"} 3.0
# HELP runner_workflow_job_duration Number of queued workflow
# TYPE runner_workflow_job_duration gauge
runner_workflow_job_duration{id="12345678910",job_name="job1",repository="DataDome/repository",runner="self-hosted-runner"} 22.0
# HELP runner_warm_up_duration Number of queued workflow
# TYPE runner_warm_up_duration gauge
runner_warm_up_duration{job_id="123456789",label="self-hosted-runner"} 6.0
# HELP runner_collection_duration Cumulated collection duration
# TYPE runner_collection_duration gauge
runner_collection_duration{duration="runners"} 0.566448450088501
runner_collection_duration{duration="repositories"} 5.607841968536377
runner_collection_duration{duration="workflow_runs"} 22.287299394607544
runner_collection_duration{duration="workflow_jobs"} 0.7833900451660156
# HELP runner_app_api_rate_limit Number of call made to API for GH app. Reset every hour
# TYPE runner_app_api_rate_limit gauge
runner_app_api_rate_limit{app_id="123456"} 3537.0
# HELP github_hosted_runners_minutes_used Number of minutes used by GitHub-hosted runners across the organization
# TYPE github_hosted_runners_minutes_used gauge
github_hosted_runners_minutes_used{duration="github_hosted_runners_usage"} 35696.0

Grâce à ces données, nous avons conçu des tableaux de bord détaillés dans Grafana pour surveiller l’utilisation et l’infrastructure de nos exécuteurs auto-hébergés.

Visualisation des métriques dans Grafana

Ces tableaux de bord sont organisés en plusieurs catégories. Tout d’abord, nous avons mis en place des panneaux offrant une vue d’ensemble de l’utilisation des GitHub Actions chez DataDome.

Ensuite, nous présentons les détails spécifiques à chaque catégorie de runner, y compris le nombre de jobs en cours d’exécution et, surtout, la durée de mise en route des GitHub Actions sur chaque catégorie d’exécuteur.

Détails d'utilisation des runners dans Grafana

Pour une analyse plus approfondie, certains panneaux affichent la durée complète d’exécution des jobs, permettant ainsi de mieux comprendre la performance des dépôts GitHub Actions.

Durée d'exécution des jobs dans Grafana

Enfin, certains panneaux sont conçus pour afficher les détails de l’utilisation actuelle de la facturation et des GitHub Actions en cours sur les exécuteurs hébergés par GitHub, permettant ainsi de suivre efficacement la transition vers les exécuteurs auto-hébergés.

Utilisation de la facturation et actions en cours dans Grafana

 

Enseignements & prochaines étapes

Le déploiement des exécuteurs auto-hébergés GitHub a rendu indispensable la mise en place d’un suivi rigoureux. En raison du nombre élevé de dépôts dans notre organisation GitHub, aucun exportateur Prometheus existant ne répondait entièrement à nos besoins.

Le principal défi dans la création de notre exportateur personnalisé a été de collecter les mesures à un rythme soutenu sans dépasser les limites de requêtes imposées par l’API REST de GitHub. Nous avons relevé ce défi en appliquant un filtrage strict des dépôts à surveiller et en optimisant le nombre de requêtes envoyées à l’API GitHub pour éviter la saturation.

Pour la suite, nous allons améliorer la surveillance des résultats des GitHub Actions afin de détecter rapidement les problèmes d’exécution. De plus, nous finaliserons la migration des derniers jobs restants, toujours exécutés sur des runners GitHub hébergés, vers nos exécuteurs auto-hébergés.