Aller au contenu

Collecte de métriques avec Prometheus (Agent mode)

Si tu souhaites collecter les métriques de tes services qui tournent dans un cluster Kubernetes, Prometheus (projet CNCF gradué) est la solution la plus commune.

Introduction

Je t'ai déjà présenté Vector.dev, développé par Datadog, qui est une meirveille permettant de la collecte de log, de métriques de sources variés. Un cas typique d'usage que Vector gère moins naturellement est la collecte de métriques pour des deploiement d'application en mode Daemonset.

Je te montre ici comment utiliser Prometheus en remplacement pour ce genre d'usage.

Pourquoi Prometheus ?

Cas d'usage et faiblesse de Vector

Il se peut que tu deploies dans ton cluster des services en mode Daemonset. Ceux-ci on pour propriété de tourner une instance sur l'ensemble des noeux de ton cluster. Ce qui est pratique par exemple pour des services qui te remontent des métriques, telle que cAdvisor, Node-Exporter, etc. Ainsi cela te permet de monitorer les noeuds de ton cluster et de te remonter des informations bien utiles quant à son utilisation.

Tu souhaites donc avoir un agent qui tourne et qui puissent récolter ces métriques sur l'ensemble des noeuds. Chose facile quand tu as un seul noeud et une seule instance qui tourne avec Vector, mais qui demande une configuration manuelle par node (agent Vector + IP du node) si tu en as une multitude

Comment peut on donc addresser l'ensemble des instances de notre service qui tournent sur des noeuds différents ?

Prometheus & CRD

Kubernetes utilise des objets natif à lui. Exemple avec un Pod.

Prometheus peut aller collecter les métriques de nos applications qui tournent en Daemonset via des objets à lui. Ceux-ci vont pouvoir être compris de Kubernetes via une CRD installé avec Prometheus.

Note

CRD, pour Custom Ressource Definition. Cela permet de décrire de nouvelles ressources dans Kubernetes

PodMonitor & ServiceMonitor

Prometheus va déclarer deux nouvelles ressources :

  • PodMonitor: permet de target un ensemble de pods
  • ServiceMonitor: permet de target unensemble de Service, et donc de pods

Ainsi le système de tracking des pods que l'on souhaite scrapper repose sur l'activation d'une de ces 2 CRD sur notre service qui expose des métriques.

Installation

Je te propose de l'installer via un Helm Chart, avec ArgoCD, sur ton cluster. Il existe une multitude de Prometheus, livré seul, via un opérateur, ou encore avec toute une stack all-in-one avec une Time-Series database du style Mimir.

Ici je voudrais te montrer Prometheus en tant que simple collecteur de métriques. A toi de choisir ensuite une TSDB pour les stocker, que cela soit avec VictoriaMetrics, Mimir, Thanos, Cortex, etc.

Et pour avoir Prometheus qui soit juste un simple forwarder de métriques, on doit activer le mode Agent. Il est stable depuis Prometheus 3.0 (flag --agent) et utilisable avec n'importe quel mode d'installation ; ici on l'active via le chart de l'opérateur.

Let's go pour le chart kube-prometheus-stack. Je te montre pas en détails, claquer un Helm Chart reste très simple à faire.

Configuration et optimisation

On va devoir configurer les values de notre chart. Ce chart propose de base de monitorer pas mal de chose dont on s'en tape un peu. Prometheus peu très vite être un service consommateur en CPU mais surtout en mémoire, donc autant bien maitriser et scrapper seulement les choses dont on a besoin.

Faisons un peut de netoyage en désactivant le self monitoring de l'opérateur :

1
2
3
4
5
6
7
8
9
"defaultRules" = {
    create = false
}

prometheusOperator = {
    serviceMonitor = {
        selfMonitor = false
    }
}


On desactive les CRD pour les composants de base :

kubernetesServiceMonitors = {
    enabled = true
}

alertmanager = {
    enabled = false
}

grafana = {
    enabled = false
}

kubeStateMetrics = {
    enabled = false
}

kubeApiServer = {
    enabled = false
}

kubeEtcd = {
    enabled = false
}

kubeScheduler = {
    enabled = false
}

nodeExporter = {
    enabled = false
}

kubeControllerManager = {
    enabled = false
}

coreDns = {
    enabled = false
}

kubeDns = {
    enabled = false
}

kubeProxy = {
    enabled = false
}


Le plus important maintenant est d'activer le mode Agent. On desactive le self monitoring. On définit un interval à laquelle on va scrapper nos applications par l'intermédiaire de nos CRD. Enfin, on défini un sink vers ou envoyer nos données scrappés. Je te montre un exemple de sink vers Grafana Mimir, et un second vers un Vector si tu souhaites faire de la customisation plus poussée de tes métriques.

prometheus = {
    serviceMonitor = {
        selfMonitor = false
    },
    agentMode = true
    prometheusSpec = {
        replicaExternalLabelNameClear    = true,
        prometheusExternalLabelNameClear = true,
        scrapeInterval                   = "60s",
        remoteWrite = [
            {
                url = "http://mimir-distributed-nginx.<mon_namespace>.svc.cluster.local/api/v1/push"
            },
            {
                url = "http://vector-aggregator-headless.<mon_namespace>:9090"
            }
        ]
    }
}

Target les CRDS de nos applications via Labels

On a maintenant un Prometheus qui tourne via un opérateur, en mode Agent qui target les CRDs.

On doit activer les PodMonitor ou les ServiceMonitor des services que l'on souhaite scrapper. Mais en plus de cela, on va devoir ajouter un Label sur ceux-ci afin qu'ils soit bien targetable. Pour cela je te montre un exemple :

prometheus = {
    monitor = {
        enabled = true
        additionalLabels = {
            // Label obligatoire pour être scrappé : la valeur est le nom de ta release Helm kube-prometheus-stack
            "release" = "<nom-de-ta-release>"
        }
        // Interval de scrapping
        interval = "60s",
        // Permet de customiser les metriques
        metricRelabelings = [
            {   // Exemple de ne garder que certaines métrics basé sur leurs noms
                sourceLabels = ["__name__"],
                regex        = "(metrics_1|metrics_...)",
                action       = "keep"
            }
        ],
        // Permet de customiser les labels des métriques
        relabelings = [
            {   // Exemple d'échange de nom de label
                sourceLabels = ["__meta_kubernetes_pod_node_name"]
                action       = "replace"
                targetLabel  = "new_label"
            }
        ]
    }
}

Tip

Fais bien attention : de base avec cette stack, le label release doit valoir le nom de ta release Helm kube-prometheus-stack (par exemple kube-prometheus-stack si tu l'as nommée ainsi) pour être target par ton agent Prometheus. Pour sélectionner tous les ServiceMonitor/PodMonitor sans ce label, mets serviceMonitorSelectorNilUsesHelmValues = false et podMonitorSelectorNilUsesHelmValues = false dans prometheusSpec.

Tips pour cAdvisor via Kubelet

Petite astuce dont je ne savait pas, est que Kubernetes fait tourner un cAdvisor de base via son kubelet. Pas besoin d'installer ce service soit même tu peux aller le scrapp directement comme ceci:

kubelet = {
    enabled = true
    serviceMonitor = {
        cAdvisor     = true
        probes       = false
        resource     = false
        resourcePath = "/metrics/resource"

        // concerne que cAdvisor
        cAdvisorMetricRelabelings = [
            { 
                // Si tu souhaites keep seulement quelques metrics de cAdvisor
                sourceLabels = ["__name__"],
                regex        = "(metrics_1|metrics_2|metrics_...)",
                action       = "keep"
            },
            { 
                // Si tu veux drop certains label histoire de ne garder que les essentiels
                regex  = "(label_1|label_2|label_...)"
                action = "labeldrop"
            }
        ],
        // concerne tout kubelet
        metricRelabelings = [
            { 
                // Permet de ne garder que les metrics de cAdvisor et non du kubelet
                sourceLabels = ["__metrics_path__"]
                regex        = "/metrics/cadvisor"
                action       = "keep"
            }
        ]
    }
}