Argo Events est un framework d'automatisation de workflow qui tourne au sein de Kubernetes. Il permet de déclencher des réactions (Triggers) à des évènements (Events), via un certain nombre de conditions (portées par des Sensors).

Cette mécanique repose sur un EventBus de votre choix.

Dans cet article d’introduction, nous allons nous intéresser à l’architecture de ce projet, aux objets qu’il crée au sein d’un cluster Kubernetes, et à la manière dont nous allons pouvoir les utiliser afin de bâtir des architectures complexes.

💡
Nous sommes convaincus que la connaissance d’un outil passe par sa pratique. Cet article se concentre uniquement sur les mécanismes internes de l’outil et des problématiques qu’il adresse. Il est accompagné d’une démonstration en ligne, qui vous permet de tester l’outil dans des conditions réelles, à votre rythme, en évitant des copier / coller et des aller-retours entre fenêtres.
👉
Pour la démonstration live, suivez le lien !

Sommaire :

ArgoEvents, une implémentation de Cloud Events

L’informatique moderne est majoritairement asynchrone. Cela lui permet d’encaisser des charges de travail toujours plus importantes, mais aussi de réaliser des architectures massivement découplées, agrégeant de petites unités d'œuvre, plus faciles à développer et maintenir dans le temps.

Chorégraphier les interventions de ces différents services peut être une réelle gageure. C’est d’autant plus dur à accepter que les grands acteurs du Cloud proposent nativement cette mécanique événementielle au sein de leurs architectures et offrent des solutions toutes intégrées et simples à mettre en œuvre.

Heureusement, et comme souvent, l’Open Source n’est jamais loin derrière.
Argo Events, qui s’installe au sein d’un cluster Kubernetes, est le projet qui permet d’apporter la puissance des architectures évènementielles dans votre système, qu’il repose intégralement sur Kubernetes ou pas.

C’est un premier pas vers une implémentation de référence d’une norme en cours d’écriture, Cloud Events, qui vise à unifier les données et métadonnées associées aux événements dans le monde du Cloud Native.
Comme l’ensemble de la suite Argo, ce framework est open-source et indépendant des autres produits de la suite (Argo CD, Workflow et Rollout), bien qu’il y soit très bien intégré.

ArgoEvents en un coup d'œil

Argo Events est composé d’un ensemble de Custom Resource Definitions (CRD) qui se déploient au sein de votre cluster. Ces CRDs permettent de décrire, sous forme d’objets K8s, les trois ressources que l’utilisateur est amené à manipuler :

  • EventSource, les évènements déclencheurs.
  • Sensor, qui est chargé d’intercepter les événements et éventuellement de les filtrer selon des règles simples
  • Trigger, les actions déclenchées en réaction à un évènement.

Ces trois objets sont interconnectés à l’aide d’un EventBus (bus de messages). Par défaut, Argo Events repose sur NATS Streaming. C’est le bus d'évènements mis en avant par la CNCF.
Le framework est extensible, afin de le brancher le bus avec lequel l’utilisateur est plus à l’aise. Pour l’utilisateur, le bus d'évènements est totalement transparent ; il ne manipule que des objets K8S (EventSources, Sensors et Triggers).

En plus des CRDs et du bus, Argo Events déploie deux ensembles de composants :

  • la sécurité, avec des ServiceAccounts et des ClusterRoles
  • les controllers, pour orchestrer les objets créés par l’utilisateur : l’EventSourceController, le SensorController et l’ EventBusController.

Enfin, Argo Events peut aussi bien manipuler des évènements internes à son cluster K8S qu’externes. Il peut donc servir de moteur évènementiel (à une architecture multicloud par exemple).

Allons un peu plus en détail sur les objets fournis par défaut.

Les EventSources, classés par type

La liste ne cesse de croître et à l’heure de l’écriture de cet article, il existe plus de 25 évènements distincts gérés de manière native.
Le framework étant extensible et connaissant un succès fulgurant, cette liste croît de semaine en semaine.

Les évènements de type Pub/Sub

Ce sont les plus nombreux. Ils sont déclenchés généralement lors de l’arrivée d’un message dans une file. Ces mécanismes sont souvent à la base de toute architecture asynchrone, il est donc normal que cette population soit sur-représentée.

De manière générale, l’EventSource contient les informations nécessaires à la connexion au bus (host, login, mot de passe), la file à surveiller et, de manière optionnelle, un filtre qui permet de ne déclencher l’évènement que lorsque certaines conditions sont réunies. Ce filtre prend la forme d’une expression booléenne qui peut aller piocher ses informations dans le message ou dans ses métadonnées.

Nous noterons que les EventSources de type Pub/Sub couvrent aussi bien les grands projets Open Source (MQTT, Kafka, NATS…) que les produits propriétaires des Cloud Providers publics (AWS SQS, Google Pub/Sub, Azure Events Hub…).

Les évènements de type Fichier

Seconde catégorie par le nombre, les évènements de type fichier, qui sont déclenchés sur réception, modification ou suppression d’un fichier dans un file system.
Là encore, les sources sont variées et vont du classique File System physique à des FS plus spécifiques, comme le BlockStorage (avec Minio, et donc plus globalement S3) ou HDFS.

Les Hooks sur le SCM

Argo Events s’inscrit dans la galaxie Argo; en particulier le pionnier du GitOps, ArgoCD. Il est donc naturel que celui-ci puisse réagir à des évènements se produisant dans un Source Control. Nous retrouvons sans surprise tous les protagonistes de l’écosystème Git : GitHub, GitLab, Bitbucket…

Les évènements génériques

Dernière catégorie, probablement la plus flexible, les évènements paramétrables.
Utiliser des crons (via des éléments de type Calendar), des webhooks, écouter les évènements du cluster (K8s Resources) ou développer des sources spécifiques (via l’évènement générique), l’extensibilité du framework devrait faire le bonheur de tous.

Certains éditeurs comme Slack et Stripe proposent déjà la documentation pour leurs propres Webhook.

Les Sensors

Du côté des Sensors, l’implémentation va droit au but : le CRD est unique quel que soit l'évènement capté et les possibilités de personnalisation sont assez limitées.
Attention, un Sensor ne peut pas être déployé sans au minimum un Trigger. Et qu’un Sensor peut contenir plusieurs Triggers ! Il est donc possible de très facilement implémenter le pattern FanOut (où un même déclencheur provoque plusieurs réactions en parallèle).

Les Sensors portent optionnellement des filtres sur les évènements qu’ils captent et cette logique peut être assez poussée, même si la syntaxe et la grammaire sont rudimentaires. Ces filtres portent sur les évènements entrants.

Les Sensors peuvent aussi transmettre à leurs Triggers tout ou partie du message véhiculé par l'évènement ou son contexte. Il est ainsi possible de transmettre par exemple le nom du fichier à l'origine d’un évènement “Création dans S3”. Les contenus peuvent être transformés à la volée, en utilisant LUA ou jq.

Plus ces filtres et ces transformations seront poussées, plus complexes seront les objets Sensors et plus délicat sera le maintien en condition opérationnelle de l’ensemble. Il est donc préférable de traiter les logiques métier dans des conteneurs spécialisés plutôt que via la configuration d’ArgoEvents.

Les Triggers

Dernier élément de la chaîne : les Triggers, qui déclenchent les actions. Là encore, Argo Events est bien fourni mais aussi extensible.

À l’origine, le premier Trigger était un Trigger Argo Workflows, afin d’être en mesure de déclencher un pipeline de traitement depuis n’importe quel évènement.

Depuis, la base de code s’est considérablement enrichie et nous retrouvons dans les Triggers le pendant des EventSources :

  • Des Triggers qui émettent des messages dans une file : Kafka, NATS, Pulsar et Azure Events Hub.
  • Des Triggers qui déclenchent des appels HTTP
  • Des Triggers qui déclenchent des fonctions : OpenWhisk et AWS Lambda
  • Des Triggers qui pilotent la création d’objets K8s.

En pilotant la création d’objet K8s, il est bien sûr facile de créer un Trigger qui réalise un traitement métier complexe ou tout autre besoin pour compléter la chaîne. Ces Triggers peuvent aussi être directement codés dans Argo.

ArgoEvents en action, par l’exemple

Maintenant que nous avons décortiqué le fonctionnement de base, projetons-nous dans une mise en œuvre fictive.

Imaginons que le Ministère des Transports veuille migrer la totalité de l’infrastructure des contrôles de vitesse sur un Cloud de Confiance. Imaginons que ce Cloud de Confiance ne bénéficie pas (encore) d’un moteur évènementiel tel que celui d’AWS.

Nous allons utiliser Argo Events pour :

  • Découper les traitements en unité d'œuvre simple
  • Permettre une mise à l’échelle facile
  • Favoriser des traitements locaux, par exemple par région

L’élément central de notre architecture est un cluster Kubernetes, qui héberge Argo Events et l’ensemble de nos traitements.

Décomposons la séquence d’évènements qui a eu lieu lorsqu’un contrevenant est flashé. Tout ce qui va suivre est totalement fictif, bien qu'inspiré de faits réels.

Le radar stocke, en local, la photo incriminante, ainsi que les métadonnées associées (heure, lieu, vitesse).
Argo Events possède un EventSource de type File sur le FileSystem du radar. Cet EventSource est associé à un Sensor, qui va déclencher deux flux de traitements.

Flux de traitement de l’image

  1. Un premier traitement (sous forme de Trigger K8s qui déclenche un conteneur ad-hoc) rapatrie l’image depuis le radar et la stocke dans un Bucket Minio RAW.
  2. Cette création de fichier est à l’origine d’un autre Event, qui télécharge l’image, la formate et tente d’isoler la plaque d’immatriculation.
  3. Cette plaque est ensuite passée à une application d’OCR qui en reconnaît les caractères. Un autre bucket Minio pourrait stocker toutes les photos alternatives, pour historisation et reprise sur incident.
  4. La plaque reconnue est émise dans une file de messages.
  5. Nous pouvons ensuite aller lire les informations du registre des cartes grises via un appel HTTP, et confronter le modèle et la marque du véhicule à celles reconnues par un algorithme d’intelligence artificielle, lui aussi déclenché par l’arrivée d’une image dans un bucket (si d’autres traitements en micro services vous viennent à l’idée, utilisez la zone commentaire du blog :))

Flux de traitement des métadonnées

Le second flux, en mode FanOut, pourrait être consacré au traitement des métadonnées, avec une orchestration plus tournée vers les files de messages.

  1. Un premier pod pourrait analyser les conditions de circulation (météo, pollution, présence de travaux) pour déterminer la limite de vitesse effective au moment du flash.
  2. Un autre conteneur peut appliquer les corrections en fonction des marges d’erreur.
  3. Un Sensor peut utiliser en filtre l’écart entre la vitesse constatée et la vitesse réglementée pour orienter le traitement vers une amende classique ou vers un délit, etc.

Traitement final

Enfin, une fois la chaîne d’image résolue et la chaîne des métadonnées terminées, le Sensor final peut réaliser un FanIn (par exemple sur deux files de messages) et procéder au post traitement (émission d’une contravention, mise sous pli, signalement au fichier des conducteurs pour un retrait de point, etc.)

Mais tout cela n’est bien sûr que fiction :)

En conclusion

Argo Events est l’outil que j’attendais depuis longtemps. Disposer de la puissance d’une orchestration d’évènements dans un monde Kubernetes, Open Source ou multicloud (voire une joyeuse combinaison des trois) est un atout architectural certain.

Les esprits chagrins argueront que réaliser une telle architecture, où l’ensemble de la chorégraphie est extrinsèque (et donc par nature difficile à debugger et à documenter), est inutilement dangereux. J’ai tendance, par choix, à privilégier dans mes designs la composition de multiples services à taille raisonnable. Et pour cela, Argo Events est exactement l’outil dont j’ai besoin.

Références

La documentation officielle de Argo Events.

Le pattern Fan Out / Fan In.

Quelques patterns d’architecture, spécialisés sur AWS mais dont vous imaginerez facilement les équivalents.