Aller au contenu

Logs collector & aggregator avec Vector.dev

Vector est un tool de data pipeline. En quelques mots, il te va te permettre de récupérer pleins d'infos utiles, que cela soit des métriques, logs applicatif/d'erreur/d'infos, etc. Afin de les renvoyer vers une database afin d'y être stocker, et pourquoi pas exposer via des dashboard Grafana ou Datadog afin d'en créer de la valeurs, de te permettre de comprendre ce qui se passe dans ton cluster, et en cas de problémes, que celui-ci te soit remonter de façon simple et visuel sans devoir y mettre les mains dans le code afin de créer une alerte à tes équipes sous la forme que tu souhaites.

Installation

  • A la main façon kubectl
  • ArgoCD ou FluxCD

Principes d'une pipeline

Il est important de comprendre les concepts de bases d'une configuration d'une pipeline sous Vector, qui est composé de 3 principaux elements :

  1. Source
  2. Transform
  3. Sink

Source

Vector va pouvoir ingérer des données. Que cela soit des métriques ou des logs, que cela viennent directement de kubernetes, de tes services applicatifs, ou d'autres services tiers, on appelle cela une source


Example d'une configuration :

# vector-configmap.yml
sources:
    exemple_prometheus:
        endpoints:
        - http://prometheus-server.monitoring.svc.cluster.local:9090/federate
        query:
            "match[]":
            - '{job=~".+"}'
        scrape_interval_secs: 30
        type: prometheus_scrape
Ici une première source example, exemple_prometheus, on imagine dans ton cluster k8s que tu aies un server prometheus qui s'occupe de scrap certains de tes pods applicatifs qui ont l'annotation adéquate de Prometheus pour être scrap. On va taper sur l'endpoint /federate du service qui gère ton prometheus (port 9090) pour récup les métriques voulues, une fois toutes les 30 secondes. Attention, son endpoint /metrics ne renverrait que les métriques internes de Prometheus, pas celles de ses cibles.

Transform

Une fois que tu ingéres des données dans Vector, provenant de multiples sources, tu vas avoir un sacré tas de données en tout genre. On appelle un transform, toute étape qui permet de réaliser :

  • supprimer des champs dans tes métriques/logs
  • les aggreger, faire toute opération mathématiques que tu souhaites
  • les filtrer, router vers des structures plus complexe
  • et bien d'autres opérations :)


Example d'une configuration pour un filter :

1
2
3
4
5
6
7
8
9
# vector-configmap.yml
transforms:
    example_filter:
        type: filter
        condition:
            type: vrl
            source: .name == "ma_metrique_voulu"
        inputs:
        - exemple_prometheus
Ici dans cette example, on à une étape de transformation, example_filter, qui va aller tester chacune de mes métriques provenant de ma source exemple_prometheus, afin de savoir si la props name vaut ma_metrique_voulu. Si c'est true, la métrique est gardé, dans le cas contraire celle-ci est supprimé depuis cet étape là. Tu peux avoir pleins d'autres types, comme la route qui te permet selon des conditions de splitter tes logs dans des composants séparé, un remap qui te permet de faire sur les props de tes logs des suppressions, des reformatages, etc.

Sink

Maintenant que tu as customisé tes données comme tu l'entends, tu va pouvoir les redirigerer vers toute sorte de sortie, appelées sink, comme par example :

  • exporter les métriques vers un endpoint Datadog pour faire des dashboard
  • exporter les logs applicatifs vers une database comme VictoriaLogs ou Grafana Loki
  • exporter des erreurs qui parte dans un PagerDuty pour de l'alerting
  • etc.


Example d'une configuration :

1
2
3
4
5
6
7
8
9
# vector-configmap.yml
sinks:
    example_output:
        type: prometheus_remote_write
        endpoint: "http://<vm-service>.<vm-namespace>.svc.cluster.local:8428/api/v1/write"
        healthcheck:
          enabled: false
        inputs:
        - "example_filter"
Ici on récupère la sortie du composant example_filter, et l'on va l'envoyer vers une instance VictoriaMetrics qui tourne dans notre cluster.

Architecture Vector

Tu peux avoir plusieurs types d'architecture pour ton installation de Vector dans ton cluster. Je te fais plus bas quelques mots sur ces différentes architecture et use case que tu peux rencontrer. Je te met ici si tu veux les consulter plus en détails.

Aggregator

Pour des uses cases les plus simples, ou tu souhaites manipuler peu de data, opte pour l'architecture en aggregator. Tu vas avoir des pods centralisés (un StatefulSet avec le rôle Aggregator du chart Helm, une seule replica par défaut mais scalable) qui traitent toutes les données

Agent

Pour une utilisation un peu plus intensive, passe en mode Agent. Tu vas avoir un pod par node qui tourne (daemonset)

Unified

C'est le paradigme le plus conseillé. Haute disponibilité et resilience, tu vas utiliser les 2 modes précédents:

  • Chaque node aura un vector-agent qui tourne et qui va traiter les datas de son côté. Il va s'occuper de récuperer les données de son environement, les filtrer au maximum afin d'optimiser la suite.
  • Un vector-aggregator (StatefulSet, à passer à plusieurs replicas pour la haute disponibilité) qui tournera. Il va prendre en entrée, les données qui seront les outputs des pods des vector-agent. Il s'occupera comme son nom l'indique, d'aggreger toute ces données et de faire les différents outputs vers les services concernés.


Question

Mais comment envoyer des logs d'un vector-agent vers un vector-aggregator ?


Example d'une configuration d'un vector-agent :

1
2
3
4
5
6
7
# vector-agent-configmap.yml
sinks:
    vector_aggregator:
        address: vector-aggregator-headless.<vector-namespace>:9000
        inputs:
        - une_datasource
        type: vector


Example d'une configuration d'un vector-aggregator :

1
2
3
4
5
# vector-aggregator-configmap.yml
sources:
    vector_agent:
        address: 0.0.0.0:9000
        type: vector


Libre à toi pour vector-agent d'y ajouter les datasources que tu souhaites parser. Ainsi que pour vector-aggregator d'y faire les remaps que tu souhaites et de les envoyer vers un sink final.

Quid de la meilleure data pipeline ? Vector VS Prometheus

Je parle qu'en bon de Vector. Comme quoi il outpass la concurrence en étant :

  • plus simple d'utilisation
  • plus optimisé en CPU et memoire
  • multitude de sources (data input)
  • modification des données
  • multitude de sinks (data output)
  • racheté par Datadog, c'est pas n'importe qui qui suit ce projet 😉

Ce qui fait de lui un outils extremement complet. Mais attention à ne pas le remplacer partout dans votre collectes de logs et métriques. Un cas bien précis est moins naturel à gérer avec lui, nous allons voir ça en détails.

Cas N°1 : scrap d'un service avec une seule replica (Deployment, StatefulSet) - Vector win

On a vu plus haut le cas d'un service qui expose des métriques via un endpoint façons prometheus sur le /metrics. Pour ce genre de cas, on a aucuns soucis avec Vector il peut aller le scrap directement pour récuperer les données. Cela marche bien pour des services tel que kube state metrics, ou un service à toi particulier avec un seul replica. Attention en revanche si ton service scale : en passant par le Service Kubernetes, chaque scrape tombe sur une replica au hasard, et tu mélanges alors les séries de plusieurs instances.

Cas N°2 : scrap d'un DaemonSet - avantage Prometheus

Mais quid d'un service, comme cAdvisor ou node-exporter, qui tourne avec une instance sur chaque node de ton cluster, donc en mode daemonset ? Passer par le Service ne fonctionne pas, pour la même raison que plus haut.

La solution avec Vector est de le déployer en mode Agent (un pod par node), et de faire scraper à chaque agent l'instance de son propre node. Pour cela, injecte l'IP du node dans le pod Vector via la downward API (valueFrom.fieldRef.fieldPath: status.hostIP dans une variable NODE_IP), puis utilise-la dans la source : endpoints: ["http://${NODE_IP}:9100/metrics"]. Ça fonctionne, mais c'est à configurer à la main pour chaque exporter.


Prometheus, lui, gère ce cas nativement grâce à la découverte de services Kubernetes et à ses CRD (custom ressource definition) : les PodMonitor ou ServiceMonitor ciblent automatiquement chaque pod derrière un Service, et donc chaque instance de cAdvisor qui tourne sur l'ensemble du cluster.

Attention donc au cas d'usage que vous rencontrez dans votre propre cas. A vous de coupler ces deux outils afin d'optimiser cout des ressources et fonctionnalités.