<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Prometheus on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/prometheus/</link><description>Recent content in Prometheus on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr-fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Fri, 11 Oct 2024 10:00:00 +0200</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/prometheus/index.xml" rel="self" type="application/rss+xml"/><item><title>Optimisation des ressources Kubernetes avec l’autoscaling horizontal des pods via des custom metrics et le Prometheus Adapter</title><link>https://blog.zwindler.fr/2024/10/11/optimisation-ressources-kubernetes-autoscaling-horizontal-custom-metrics-prometheus-adapter/</link><pubDate>Fri, 11 Oct 2024 10:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2024/10/11/optimisation-ressources-kubernetes-autoscaling-horizontal-custom-metrics-prometheus-adapter/</guid><description>&lt;img src="https://blog.zwindler.fr/2024/10/prom-adapter-diagram.webp" alt="Featured image of post Optimisation des ressources Kubernetes avec l’autoscaling horizontal des pods via des custom metrics et le Prometheus Adapter" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Note : cet article a été co-écrit avec mon ex-collègue &lt;a class="link" href="https://www.linkedin.com/in/gaby-fulchic-857799139/" target="_blank" rel="noopener"
&gt;Gaby Fulchic, alias Weeking&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Si vous avez vécu dans une grotte ces 10 dernières années et que vous n&amp;rsquo;avez jamais entendu parler de Kubernetes, eh bien&amp;hellip; je vous invite à consulter &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=kubernetes" target="_blank" rel="noopener"
&gt;mes autres articles sur le sujet&lt;/a&gt; xD.&lt;/p&gt;
&lt;p&gt;Dans cet article, j&amp;rsquo;ai eu envie de creuser une fonctionnalité qui existe depuis un moment, mais dont j&amp;rsquo;ai rarement eu besoin : les &lt;strong&gt;HorizontalPodAutoscalers&lt;/strong&gt;, en particulier via l&amp;rsquo;usage de custom metrics.&lt;/p&gt;
&lt;p&gt;Prêt à scaler ? C&amp;rsquo;est parti !&lt;/p&gt;
&lt;h2 id="cest-quoi-diantre-que-lautoscaling-horizontal-des-pods-hpa-"&gt;C&amp;rsquo;est quoi diantre que l’autoscaling horizontal des pods (HPA) ???
&lt;/h2&gt;&lt;p&gt;L&amp;rsquo;HorizontalPodAutoscaler est une fonctionnalité de Kubernetes. Elle permet de spécifier, pour des métriques données sur un groupe de Pods, d&amp;rsquo;essayer d&amp;rsquo;atteindre des valeurs cibles. L&amp;rsquo;utilisation la plus basique de cette fonctionnalité est, vous l&amp;rsquo;aurez deviné, de &amp;ldquo;scaler&amp;rdquo; des Pods en fonction de métriques basiques, par exemple la consommation CPU.&lt;/p&gt;
&lt;p&gt;Comme tout dans Kubernetes, il s’agit d’une API (actuellement &lt;code&gt;autoscaling/v2&lt;/code&gt;). La manière la plus simple d’interagir avec elle est de créer un fichier manifest YAML où vous décrivez l’état souhaité de votre application en fonction de la charge.&lt;/p&gt;
&lt;p&gt;Par défaut, seules des métriques simples, la consommation CPU et mémoire (celles collectées par &lt;code&gt;metrics-server&lt;/code&gt;) sont disponibles afin de spécifier les règles de scaling.&lt;/p&gt;
&lt;p&gt;Un exemple simple pourrait ressembler à ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;autoscaling/v2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;HorizontalPodAutoscaler&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;myapp-hpa&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mynamespace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;maxReplicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;cpu&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;averageUtilization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Utilization&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;minReplicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;apps/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Deployment&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;myapp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note : Les spécifications HPA peuvent être incroyablement plus complexes et puissantes, car l&amp;rsquo;API s&amp;rsquo;est considérablement enrichie au fil des années. N&amp;rsquo;hésitez pas à aller lire la documentation officielle ;-).&lt;/p&gt;
&lt;p&gt;Sur la base de l&amp;rsquo;exemple précédent, une fois le manifest appliqué, Kubernetes tentera de maintenir une utilisation moyenne du CPU autour de 50 % sur tous les pods &amp;ldquo;myapp&amp;rdquo; et ajoutera des replicas si la consommation moyenne de CPU dépasse ce seuil. Dès que la consommation CPU descend en dessous de la cible, Kubernetes réduit le nombre de replicas, jusqu&amp;rsquo;à atteindre le nombre minimal si nécessaire.&lt;/p&gt;
&lt;p&gt;Bon, ça, c&amp;rsquo;est la théorie. Mais d&amp;rsquo;expérience, l&amp;rsquo;utilisation de HPA de cette manière présente des limites :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Les applications modernes ont souvent des caractéristiques de performance complexes qui sont imparfaitement décrites par l’utilisation du CPU et de la RAM seules. Par exemple, une application peut être limitée par les entrées/sorties (I/O). D’autres facteurs comme la latence des requêtes, des métriques métier ou des indicateurs sur des dépendances externes (le nombre de messages dans une queue, par exemple) peuvent fournir une meilleure base pour les décisions de scaling.&lt;/li&gt;
&lt;li&gt;L’utilisation du CPU peut également être très élevée lors du « boot » d’un nouveau pod, ce qui peut entraîner plus de scaling que nécessaire (on, parle de boot storm sur les infrastructures plus classiques, je trouve le terme approprié).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;L&amp;rsquo;HorizontalPodAutoscaler réagit aux métriques récupérées à un moment donné, ce qui signifie qu&amp;rsquo;il peut y avoir un décalage entre le pic de la métrique et la réponse de scaling. Cela peut entraîner une dégradation temporaire des performances. Trouver des métriques permettant d’anticiper le besoin de scaling plutôt que de réagir après une dégradation est donc l&amp;rsquo;objectif à garder en tête pour améliorer la fiabilité de nos apps.&lt;/p&gt;
&lt;p&gt;Pour pallier ces limitations, Kubernetes permet l’utilisation de &lt;strong&gt;custom metrics&lt;/strong&gt; offrant une plus grande flexibilité et un meilleur contrôle sur le comportement du scaling des applications. C&amp;rsquo;est là qu&amp;rsquo;interviennent des outils comme Prometheus et le Prometheus Adapter, qui vont nous permettre des stratégies d’autoscaling plus adaptées / efficaces.&lt;/p&gt;
&lt;h2 id="prometheus-et-les-métriques-via--metrics"&gt;Prometheus et les métriques via &lt;code&gt;/-/metrics&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;Comme Kubernetes, Prometheus est un autre des grands projets sous l&amp;rsquo;égide de la CNCF. C&amp;rsquo;est un outil de collecte de métriques, qui dispose d&amp;rsquo;une base de données de séries temporelles (TSDB) optimisée pour stocker des métriques d&amp;rsquo;infrastructure et d&amp;rsquo;un langage de requête permettant des analyses profondes faciles, mais puissantes de ces métriques. Là aussi, j&amp;rsquo;ai déjà écrits &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=prometheus" target="_blank" rel="noopener"
&gt;plusieurs articles sur le sujet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;En général, on classe les outils de supervision dans deux grandes catégories. Ceux qui reçoivent les métriques des clients qui les « push » et ceux qui « pull » périodiquement les métriques des applications elles-mêmes. Prometheus utilise la stratégie de &amp;ldquo;pull&amp;rdquo; (la plupart du temps) et, par défaut, il va collecter nos métriques toutes les 30 secondes.&lt;/p&gt;
&lt;p&gt;Cela signifie que vous n&amp;rsquo;avez pas besoin d&amp;rsquo;installer un « agent » sur vos applications MAIS que vous devez spécifier à Prometheus une liste de « cibles » qui exposent des points de terminaison HTTP (vos applications) servant des métriques dans un format spécifique, généralement sur le chemin /-/metrics :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl -n mynamespace port-forward myapp-5584c5c8f8-gbsw8 &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Forwarding from 127.0.0.1:3000 -&amp;gt; &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Forwarding from &lt;span class="o"&gt;[&lt;/span&gt;::1&lt;span class="o"&gt;]&lt;/span&gt;:3000 -&amp;gt; &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# dans un autre terminal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl localhost:3000/-/metrics/ 2&amp;gt; /dev/null &lt;span class="p"&gt;|&lt;/span&gt; head
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# HELP http_request_duration_seconds duration histogram of http responses labeled with: status_code method path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# TYPE http_request_duration_seconds histogram&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http_request_duration_seconds_bucket&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;0.0002&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;200&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/-/health&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http_request_duration_seconds_bucket&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;0.0005&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;200&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/-/health&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="m"&gt;364&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nous pouvons ensuite interroger Prometheus pour obtenir ces métriques en spécifiant le nom de la métrique et en ajoutant des labels pour préciser quel sous-ensemble nous intéresse :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http_request_duration_seconds_bucket&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;kubernetes_namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mynamespace&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;kubernetes_pod_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;myapp-5584c5c8f8-gbsw8&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Je vais partir du principe que vous avez un Prometheus disponible sur votre cluster pour la suite de l&amp;rsquo;article (sinon, allez jeter un œil au &lt;a class="link" href="https://github.com/prometheus-operator/prometheus-operator" target="_blank" rel="noopener"
&gt;Prometheus Operator&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Grâce à Prometheus, nous avons maintenant une multitude de métriques parmi lesquelles choisir afin de prédire si nos applications doivent être mises à l&amp;rsquo;échelle de manière proactive. Cependant, le problème est que nous ne pouvons pas dire au HPA de surveiller directement ces métriques, car le HPA n&amp;rsquo;est pas directement compatible avec le langage de requête Prometheus PromQL.&lt;/p&gt;
&lt;h2 id="prometheus-adapter-à-la-rescousse"&gt;Prometheus Adapter à la rescousse
&lt;/h2&gt;&lt;p&gt;Nous avons donc besoin d&amp;rsquo;un autre outil qui récupérera les métriques depuis Prometheus et les fournira à Kubernetes. Vous avez deviné de quel logiciel il s&amp;rsquo;agit maintenant : &lt;a class="link" href="https://github.com/kubernetes-sigs/prometheus-adapter" target="_blank" rel="noopener"
&gt;&lt;strong&gt;Prometheus Adapter&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On va l&amp;rsquo;installer à partir d&amp;rsquo;une chart Helm hébergée sur le dépôt prometheus-community :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ helm show values prometheus-community/prometheus-adapter &amp;gt; values.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ helm install -n monitoring prometheus-adapter prometheus-community/prometheus-adapter -f values.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl -n monitoring get deployments.apps
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY UP-TO-DATE AVAILABLE AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metrics-server 2/2 &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; 1d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prom-operator-kube-state-metrics 1/1 &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; 1d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prom-operator-operator 1/1 &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; 1d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prometheus-adapter 1/1 &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; 1d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prom-operator-query 3/3 &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; 1d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dans cet exemple, vous pouvez voir que j&amp;rsquo;ai déjà déployé metrics-server et Prometheus en utilisant Prometheus Operator, et que Prometheus Adapter est en cours d&amp;rsquo;exécution.&lt;/p&gt;
&lt;p&gt;Par défaut, Prometheus Adapter sera déployé avec certaines custom metrics que nous pouvons utiliser &amp;ldquo;out of the box&amp;rdquo; pour scaler nos applications plus précisément. Mais dans cet article, nous allons vous montrer comment créer ✨ vos propres ✨ métriques.&lt;/p&gt;
&lt;h2 id="configurer-prometheus-adapter-pour-exposer-des-custom-metrics-via-lapi-server"&gt;Configurer Prometheus Adapter pour exposer des custom metrics via l&amp;rsquo;API Server
&lt;/h2&gt;&lt;p&gt;Au départ, la configuration de Prometheus Adapter ne contient aucune règle. Cela signifie qu&amp;rsquo;aucune métrique personnalisée n&amp;rsquo;est exposée via l&amp;rsquo;API Server au début, et que HPA ne peut pas utiliser de custom metrics.&lt;/p&gt;
&lt;p&gt;Prometheus Adapter fonctionne dans cet ordre :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Découvrir des métriques en contactant Prometheus&lt;/li&gt;
&lt;li&gt;Les associer aux ressources Kubernetes (namespace, pod, etc.)&lt;/li&gt;
&lt;li&gt;Vérifier comment les exposer (si nécessaire, il peut renommer les métriques)&lt;/li&gt;
&lt;li&gt;Vérifier comment interroger Prometheus pour obtenir les valeurs réelles (ex. obtenir un &amp;ldquo;rate&amp;rdquo;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;D&amp;rsquo;abord, nous devons valider l&amp;rsquo;API des custom metrics sur notre cluster. La liste &lt;code&gt;resources&lt;/code&gt; sera vide, mais cela prouve que l&amp;rsquo;API &lt;code&gt;custom.metrics.k8s.io/v1beta1&lt;/code&gt; est accessible.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└─&lt;span class="o"&gt;[&lt;/span&gt;$&lt;span class="o"&gt;]&lt;/span&gt; kubectl get --raw &lt;span class="s2"&gt;&amp;#34;/apis/custom.metrics.k8s.io/v1beta1&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;APIResourceList&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;apiVersion&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;groupVersion&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;custom.metrics.k8s.io/v1beta1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;resources&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Il faut ensuite plusieurs étapes pour que Prometheus Adapter collecte et fournisse des métriques au serveur API de Kubernetes. Toute la configuration de Prometheus Adapter peut être ajustée via le fichier &lt;code&gt;values.yaml&lt;/code&gt; de la chart Helm.&lt;/p&gt;
&lt;p&gt;La première chose à configurer ici est « où » Prometheus Adapter peut contacter Prometheus. Si Prometheus Adapter est exécuté sur le même cluster que la stack Prometheus, vous pouvez utiliser un enregistrement DNS interne (à Kubernetes) comme ci-dessous (voir &lt;a class="link" href="https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/" target="_blank" rel="noopener"
&gt;la documentation Kubernetes DNS pour les services et pods&lt;/a&gt;). Sinon, vous pouvez spécifier une adresse IP (ou un nom DNS) et un numéro de port.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values.yaml &amp;gt; prometheus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;http://prom-operator-query.monitoring.svc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9090&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pour vérifier que Prometheus Adapter peut correctement contacter Prometheus, il vous suffit de vérifier les logs du pod (en utilisant &lt;code&gt;kubectl logs pod/prometheus-adapter-abcdefgh-ijklm&lt;/code&gt; ou tout autre moyen à votre disposition pour lire les logs du pod).&lt;/p&gt;
&lt;p&gt;Une fois cette partie opérationnelle, nous devons ajouter quelques règles à notre Prometheus Adapter.&lt;/p&gt;
&lt;p&gt;Dans cet exemple, j&amp;rsquo;ai choisi d&amp;rsquo;utiliser une métrique appelée ELU (pour « Event Loop Utilization ») collectée à partir d&amp;rsquo;un serveur Node.js. Elle mesure combien de temps la boucle d&amp;rsquo;événements Node.js est occupée à traiter des événements par rapport à l&amp;rsquo;inactivité, et elle est plus représentative de la charge du serveur que le simple pourcentage de CPU.&lt;/p&gt;
&lt;p&gt;Les règles nous permettent de spécifier quoi interroger dans Prometheus. Nous pouvons définir quels labels importer et, si nécessaire, les remplacer pour correspondre aux noms des ressources Kubernetes. Voici les valeurs les plus utiles à spécifier :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;seriesQuery: exécute la requête PromQL, éventuellement filtrée&lt;/li&gt;
&lt;li&gt;resources: associe les labels des séries temporelles aux ressources Kubernetes&lt;/li&gt;
&lt;li&gt;name: expose les séries temporelles avec des noms différents de ceux d&amp;rsquo;origine&lt;/li&gt;
&lt;li&gt;metricsQuery: méthode pour demander à Prometheus d&amp;rsquo;obtenir un taux (&amp;laquo;.GroupBy&amp;raquo; signifie &amp;ldquo;group by Pod&amp;rdquo; par défaut)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values.yaml &amp;gt; rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;seriesQuery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;elu_utilization{kubernetes_namespace!=&amp;#34;&amp;#34;kubernetes_pod_name!=&amp;#34;&amp;#34;}&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;overrides&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;kubernetes_namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="nt"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;namespace&amp;#34;&lt;/span&gt;}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;kubernetes_pod_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="nt"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;pod&amp;#34;&lt;/span&gt;}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;^elu_utilization$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;metricsQuery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;sum(&amp;lt;&amp;lt;.Series&amp;gt;&amp;gt;{&amp;lt;&amp;lt;.LabelMatchers&amp;gt;&amp;gt;}) by (&amp;lt;&amp;lt;.GroupBy&amp;gt;&amp;gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Vous devriez maintenant pouvoir obtenir quelques custom metrics avec des valeurs réelles en accédant au serveur API. Pour tester, nous allons utiliser &lt;code&gt;kubectl&lt;/code&gt; et le paramètre &lt;code&gt;--raw&lt;/code&gt;, qui nous donne plus de contrôle sur les requêtes envoyées au serveur API.&lt;/p&gt;
&lt;p&gt;Voici quelques exemples de commandes que vous pouvez exécuter pour vérifier manuellement que les métriques sont correctement exposées via l&amp;rsquo;API Server :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# lister la découverte des custom metrics&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get --raw &lt;span class="s2"&gt;&amp;#34;/apis/custom.metrics.k8s.io/v1beta1&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# lister les valeurs des custom metrics pour chaque pod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get --raw &lt;span class="s2"&gt;&amp;#34;/apis/custom.metrics.k8s.io/v1beta1/namespaces/&amp;lt;namespace_name&amp;gt;/pods/*/elu_utilization&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Attention : le scaling sera fortement dépendant de l&amp;rsquo;intervalle de scraping de vos métriques et de l&amp;rsquo;intervalle de découverte de votre Prometheus Adapter. La documentation officielle insiste sur le fait que vous pourriez rencontrer des problèmes si vous mettez une valeur trop basse.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You&amp;rsquo;ll need to also make sure your metrics relist interval is at least your Prometheus scrape interval. If it&amp;rsquo;s less than that, you&amp;rsquo;ll see metrics periodically appear and disappear from the adapter.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="comment-cela-va-t-il-fonctionner-"&gt;Comment cela va-t-il fonctionner ?
&lt;/h2&gt;&lt;p&gt;Jusqu&amp;rsquo;à présent, nous avons introduit plusieurs composants qui interagissent entre eux.&lt;/p&gt;
&lt;p&gt;Mais comment tout cela va-t-il fonctionner sous le capot ? Eh bien, rien de mieux qu&amp;rsquo;un diagramme pour expliquer des choses comme celle-ci :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2024/10/prom-adapter-diagram.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prometheus scrape les métriques exposées par notre application&lt;/li&gt;
&lt;li&gt;Prometheus Adapter interroge le serveur Prometheus pour collecter les métriques spécifiques que nous avons définies dans sa configuration&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;HorizontalAutoscaler (le contrôleur qui gère les HPA) interrogera le serveur API pour vérifier périodiquement, si la métrique ELU est dans les limites acceptables&amp;hellip;&lt;/li&gt;
&lt;li&gt;&amp;hellip; qui à son tour demandera à Prometheus Adapter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Créons maintenant notre premier HorizontalPodAutoscaler !&lt;/p&gt;
&lt;h2 id="utilisation-dune-ressource-horizontalpodautoscaler-avec-des-custom-metrics"&gt;Utilisation d&amp;rsquo;une ressource HorizontalPodAutoscaler avec des custom metrics
&lt;/h2&gt;&lt;p&gt;Au début de ce post, nous avons introduit l&amp;rsquo;API HorizontalPodAutoscaler. La ressource elle-même n&amp;rsquo;est pas difficile à utiliser. En gros, HPA prend un déploiement cible à scaler, un nombre minimum de replicas, un nombre maximum de replicas et les métriques à utiliser. Pour la partie métrique, nous allons maintenant utiliser la métrique personnalisée de notre article configurée avec Prometheus Adapter :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;autoscaling/v2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;HorizontalPodAutoscaler&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;maxReplicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;pods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;elu_utilization&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;averageValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;500m&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Utilization&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Pods&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;minReplicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;apps/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Deployment&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;&amp;lt;deployment.apps_name&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lorsque vous configurez une ressource HPA, vous ne définissez que le nom de la métrique. Mais comment HPA peut-il déterminer la bonne métrique des bons pods puisque plusieurs applications peuvent exposer cette même métrique ? Pour comprendre cela, nous pouvons examiner les logs de Prometheus Adapter.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;I0618 12:05:29.149095 1 httplog.go:132] &amp;#34;HTTP&amp;#34; verb=&amp;#34;GET&amp;#34; URI=&amp;#34;/apis/custom.metrics.k8s.io/v1beta1/n
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Comme vous pouvez le voir, un &lt;code&gt;labelSelector&lt;/code&gt; est ajouté à la requête. Et comme vous mentionnez le Deployment dans la référence &lt;code&gt;scaleTargetRef&lt;/code&gt; de HPA, ce dernier utilise la valeur &lt;code&gt;labelSelector&lt;/code&gt; du sélecteur de labels du Deployment. Cela vous permet de cibler les métriques d&amp;rsquo;un Deployment spécifique. Et ces labels existent parce que, lors du scraping des pods avec Prometheus, la découverte des pods Kubernetes et les annotations ajoutent des labels aux métriques.&lt;/p&gt;
&lt;p&gt;Si vous souhaitez utiliser un &lt;code&gt;labelSelector&lt;/code&gt; personnalisé dans la requête, ajoutez le champ &lt;code&gt;metrics.pods.metric.selector&lt;/code&gt; à la ressource HPA.&lt;/p&gt;
&lt;p&gt;Nous avons donc l&amp;rsquo;API des custom metrics, nous avons configuré Prometheus Adapter pour découvrir et exposer certaines métriques, et nous avons créé notre première ressource HPA. Il est maintenant temps de tester le déploiement sous charge et d&amp;rsquo;observer le comportement.&lt;/p&gt;
&lt;p&gt;Pour cela, nous allons vous présenter un outil nommé &lt;a class="link" href="https://github.com/tsenart/vegeta" target="_blank" rel="noopener"
&gt;Vegeta&lt;/a&gt; (it&amp;rsquo;s over 9000!)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Vegeta is a versatile HTTP load testing tool built out of a need to drill HTTP services with a constant request rate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nous allons utiliser Vegeta pour générer une charge sur notre application tout en surveillant les pods de l&amp;rsquo;application et l&amp;rsquo;état de l&amp;rsquo;HPA (avec 3 terminaux ouverts en parallèle) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get hpa/&amp;lt;myhpa&amp;gt; -w -n &amp;lt;mynamespace&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get po -l &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;myapp&amp;gt; -w -n &amp;lt;mynamespace&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vegeta attack &amp;lt;app_endpoint_http&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note : Dans le cas où votre application peut supporter une charge importante et que les paramètres par défaut ne déclenchent pas de scaling, vous pouvez modifier certains paramètres dans la commande Vegeta. Nous recommandons d&amp;rsquo;utiliser les options workers et rate :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ndash;workers : nombre initial de workers (par défaut 10)&lt;/li&gt;
&lt;li&gt;&amp;ndash;rate : nombre de requêtes par unité de temps [0 = infini] (par défaut 50/1s)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lorsque la charge augmente, la valeur de votre métrique personnalisée augmentera également, ce qui devrait à son tour déclencher une montée en charge du déploiement une fois que les seuils sont atteints.&lt;/p&gt;
&lt;h2 id="utilisation-de-prometheus-adapter-en-production"&gt;Utilisation de Prometheus Adapter en production
&lt;/h2&gt;&lt;p&gt;Lorsque Prometheus Adapter devient un composant central de votre architecture, son tuning et sa surveillance deviennent essentiels.&lt;/p&gt;
&lt;p&gt;Si ce composant est HS, votre HPA ne pourra plus réagir. Il y aura deux impacts potentiels : vous utiliserez trop de ressources pour le trafic actuel, ou au contraire, ne pas en avoir assez pour gérer le trafic. Dans tous les cas, vos workloads ne sont pas immédiatement affectés ; ils maintiennent le dernier nombre de replicas calculé par HPA avant la panne.&lt;/p&gt;
&lt;p&gt;Pour éviter que cela ne devienne un SPOF, assurez-vous de mettre plus d&amp;rsquo;une replicas pour Prometheus Adapter. Et je conseille aussi de rajouter un petit PodDisruptionBudget pour éviter les soucis pendant les maintenances de votre cluster.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;L&amp;rsquo;autoscaling horizontal des pods intégré à Kubernetes est un mécanisme standard pouvant potentiellement aider vos apps à gérer efficacement les charges variables. A titre personnel, je trouve le HPA classique, qui utilise les métriques CPU et mémoire, trop limité. Mais avec l&amp;rsquo;intégration des custom metrics avec Prometheus Adapter, on peut rendre ses décisions de scaling plus précises et pertinentes.&lt;/p&gt;
&lt;p&gt;Si l&amp;rsquo;installation de Prometheus Adapter est simple, sa configuration est, je trouve, un peu contre-intuitive, voire complexe, sans pour autant gérer efficacement les scénarios les plus avancés.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est pourquoi je pense que, si vous n&amp;rsquo;avez pas comme impératif de rester sur le standard Kubernetes, vous devriez jeter un oeil (ou attendre mon prochain article ?) à KEDA (Kubernetes Event-Driven Autoscaling), un autre projet open-source qui étend les capacités de HPA en prenant en charge diverses sources d&amp;rsquo;événements et déclencheurs de scaling.&lt;/p&gt;
&lt;p&gt;Bon scaling !&lt;/p&gt;
&lt;h2 id="sources-supplémentaires"&gt;Sources supplémentaires
&lt;/h2&gt;&lt;p&gt;Documentation de Prometheus Adapter :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes-sigs/prometheus-adapter/blob/master/docs/walkthrough.md" target="_blank" rel="noopener"
&gt;Présentation générale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes-sigs/prometheus-adapter/blob/master/docs/config-walkthrough.md" target="_blank" rel="noopener"
&gt;Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Documentation Kubernetes HPA :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/horizontal-pod-autoscaler-v2/#HorizontalPodAutoscaler" target="_blank" rel="noopener"
&gt;HPA API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#configurable-scaling-behavior" target="_blank" rel="noopener"
&gt;Configurable scaling behavior&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Autre :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/tsenart/vegeta" target="_blank" rel="noopener"
&gt;projet Vegeta sur GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://keda.sh/" target="_blank" rel="noopener"
&gt;Site de KEDA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://nodesource.com/blog/event-loop-utilization-nodejs/" target="_blank" rel="noopener"
&gt;NodeSource.com - Introduction to Event Loop Utilization in Node.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Mise en place d’une astreinte OPS – partie 2</title><link>https://blog.zwindler.fr/2020/08/24/mise-en-place-dune-astreinte-ops-partie-2/</link><pubDate>Mon, 24 Aug 2020 06:05:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/08/24/mise-en-place-dune-astreinte-ops-partie-2/</guid><description>&lt;img src="https://blog.zwindler.fr/2020/07/on-call-helmet.webp" alt="Featured image of post Mise en place d’une astreinte OPS – partie 2" /&gt;&lt;h2 id="jpeux-pas-jsuis-dastreinte"&gt;&amp;ldquo;J’peux pas, j’suis d’astreinte&amp;rdquo;
&lt;/h2&gt;&lt;p&gt;Voici la seconde partie de mon (gros) article dédié à la mise en place d’une astreinte, dans le cadre du maintien en conditions opérationnelles d’un service informatique. Dans la première partie (&lt;a class="link" href="https://blog.zwindler.fr/2020/08/17/mise-en-place-dune-astreinte-partie-1/" &gt;disponible ici si vous l’avez loupé&lt;/a&gt;), j’ai introduis ce qu’était réellement une astreinte, pourquoi on en met en place et enfin les textes en vigueur.&lt;/p&gt;
&lt;p&gt;Dans cette deuxième partie, je vais donc rentrer un peu plus dans le concret.&lt;/p&gt;
&lt;p&gt;Pour rappel, il y a 2 ans, j’ai intégré une équipe d’ingénieurs systèmes cloud qui venait de se créer. Quand les premiers produits et les premiers clients sont arrivés en production, le besoin d’assurer la continuité d’activité s’est fait sentir. Et donc, par extension, le besoin d’une astreinte.&lt;/p&gt;
&lt;p&gt;J’ai donc eu la chance de pouvoir participer, étant directement concerné (et surtout un peu renseigné sur le sujet) à l’élaboration de cette astreinte. Ça a été l’occasion de traiter directement les aspects suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;problématiques droit du travail&lt;/li&gt;
&lt;li&gt;organisationnel&lt;/li&gt;
&lt;li&gt;implémentation technique&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="concevoir-son-astreinte"&gt;Concevoir son astreinte
&lt;/h2&gt;&lt;h3 id="comment-organiser-les-astreintes-"&gt;Comment organiser les astreintes ?
&lt;/h3&gt;&lt;p&gt;Après la compensation (récupération ou rémunération), c’est souvent LE gros sujet quand on met en place une astreinte.&lt;/p&gt;
&lt;p&gt;Dans tous les cas, il n’est pas souhaitable de mettre 365j/an une seule et même personne d’astreinte ; il faut définir un roulement.&lt;/p&gt;
&lt;p&gt;Pour le roulement, est-ce qu’une même personne est d’astreinte toute la semaine ? Seulement quelques jours ? Est-ce que tous les jours, on change ?&lt;/p&gt;
&lt;p&gt;Dans le premier cas, les périodes d’astreinte sont plus espacées, mais plus longues (et potentiellement génératrices de plus de fatigue). Dans le dernier, même en cas de semaine chaotique, le changement régulier permet de mieux répartir la fatigue entre astreinteurs, mais on est très souvent d’astreinte (pendant de courtes périodes).&lt;/p&gt;
&lt;p&gt;Est-ce que l’astreinte va concerner une journée complète de 24h, ou au contraire, considère-t-on que la journée l’équipe d’exploitation peut gérer les incidents, et l’astreinte à juste vocation à prolonger les horaires de bureaux ?&lt;/p&gt;
&lt;p&gt;Ces questions ne sont pas anodines.&lt;/p&gt;
&lt;p&gt;Au-delà de l’impact que le fait d’être d’astreinte a sur la vie privée (on ne peut pas faire autant de choses que l’on veut quand on est d’astreinte, c’est pour ça qu’on est compensé&amp;hellip;), cela peut avoir des effets très importants sur l’organisation de l’équipe.&lt;/p&gt;
&lt;h3 id="pourquoi-ça-peut-coincer-"&gt;Pourquoi ça peut coincer ?
&lt;/h3&gt;&lt;p&gt;Pour expliciter un peu où je veux en venir, prenons un exemple. Imaginons qu’une équipe de 4 OPS décide de créer une astreinte informatique 7j/7. Les incidents de la journée sont traités par l’équipe et en dehors des horaires de bureau (18h =&amp;gt; 9h le lendemain), l’astreinteur prend le relais.&lt;/p&gt;
&lt;p&gt;L’astreinteur prend son astreinte le vendredi 18h. Pas de chance, le week end est chaotique ! Des appels ont lieu le samedi et le dimanche, nécessitant des interventions à chaque fois.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/07/astreinte_cas1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;A aucun moment du week end, l’astreinteur n’a eu ses 35h de repos hebdomadaire consécutives.&lt;/p&gt;
&lt;p&gt;Dans ce cas un peu extrême (mais vécu IRL), le code du travail l&amp;rsquo;empêche de reprendre le travail que mardi matin. Son absence lundi provoque un déséquilibre dans l’organisation de l’équipe&amp;hellip;&lt;/p&gt;
&lt;p&gt;Le problème ne se limite évidemment pas au week end. On peut avoir le genre de problèmes si les appels d’astreinte ont lieu la nuit (un à 23h, l’autre à 5h par exemple).&lt;/p&gt;
&lt;p&gt;Et le problème est exacerbé si en plus, les appels continuent de pleuvoir pendant la journée. Dans ce cas, si on continue à avoir des alertes en journée, le compteur de repos n’arrive jamais à 11h.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/07/astreinte_cas2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Quelle que soit l’organisation que vous choisissez, il est dans tous les cas impératif de se débrouiller pour que les appels arrivent le moins souvent possible (travailler pour réduire les alertes intempestives).&lt;/p&gt;
&lt;p&gt;Il n’y a qu’en travaillant sur la réduction du nombre d’incidents qu’on peut réussir à impacter le moins possible l’organisation de l’équipe &amp;ldquo;de jour&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="quel-outillage-pour-réussir-son-astreinte-"&gt;Quel outillage pour réussir son astreinte ?
&lt;/h2&gt;&lt;p&gt;Je n’imagine pas une seule seconde une astreinte où l’on aurait pas &amp;ldquo;le kit de l’astreinteur&amp;rdquo;. Sauf à imposer à l’astreinteur d’être assigné à résidence, ce qui va à l’encontre de la définition de l’astreinte je pense, il est nécessaire pour l’astreinteur OPS d’avoir :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PC portable&lt;/li&gt;
&lt;li&gt;smartphone&lt;/li&gt;
&lt;li&gt;connexion 4G de qualité (je résiste à insérer un troll 5G).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ces 3 items fonctionnent ensemble. Le smartphone permet de recevoir les appels et les alertes automatiques (via la 4G). Le PC portable permet d’y remédier en se connectant rapidement sur l’infra, via le modem 4G du smartphone.&lt;/p&gt;
&lt;p&gt;On pourrait également considérer qu’un astreinteur pouvant être seul, il est nécessaire qu’il dispose d’un &lt;a class="link" href="https://fr.wikipedia.org/wiki/Protection_du_travailleur_isol%C3%A9" target="_blank" rel="noopener"
&gt;PTI/DATI (protection travailleur isolé)&lt;/a&gt;. Ça serait particulièrement vrai dans le cas où l’astreinte nécessite des interventions sur site (en DC par exemple), où un accident, hors des horaires de bureaux, pourrait être dramatique.&lt;/p&gt;
&lt;p&gt;Bon, ça, c’est le strict minimum.&lt;/p&gt;
&lt;p&gt;Si on se contente de ça, on va avoir une astreinte qui subit. Les astreinteurs seront prévenus des incidents par les clients (ou le management) et il sera parfois trop tard pour réparer la situation.&lt;/p&gt;
&lt;p&gt;Mettre en place une astreinte efficace nécessite donc quasi obligatoirement d’avoir une plateforme de supervision la plus complète et la plus pertinente possible&lt;/p&gt;
&lt;h3 id="surveiller-et-alerter-en-cas-de-problème"&gt;Surveiller et alerter en cas de problème
&lt;/h3&gt;&lt;p&gt;D’abord, ça permet de ne plus subir.&lt;/p&gt;
&lt;p&gt;L’astreinteur est prévenu de manière automatique qu’un incident est en cours. Ça permet de retirer un facteur humain dans la chaîne d’intervention (attendre que quelqu’un se plaigne du souci et pense à prévenir la bonne personne) et donc de gagner du temps.&lt;/p&gt;
&lt;p&gt;Parfois, on peut même être prévenu &lt;strong&gt;avant&lt;/strong&gt; la catastrophe (eh, ho, ton disque il est bientôt plein là !).&lt;/p&gt;
&lt;p&gt;On devient donc proactif.&lt;/p&gt;
&lt;p&gt;Ensuite, ça permet, en cas d’incident grave qu’on a pas pu éviter, de savoir exactement ce qui s’est passé et quand. Sans supervision (ou sans métriques pertinentes), impossible de faire un diagnostic correct de ce qui s’est passé et d’engager des actions correctives pour que ça ne se reproduise plus (post-mortem).&lt;/p&gt;
&lt;p&gt;Toute la difficulté de l’exercice repose donc dans l’exhaustivité et la pertinence des métriques MAIS la parcimonie des alertes. Pas assez d’alertes, c’est des clients mécontents, mais trop d’alertes, c’est pire&amp;hellip; l’astreinteur sera sollicité trop souvent&amp;hellip;&lt;/p&gt;
&lt;h3 id="alert-fatigue"&gt;Alert fatigue
&lt;/h3&gt;&lt;p&gt;Au delà de la simple fatigue provoqué par trop d’alertes (et des conséquences que ça peut avoir dans l’équipe comme je l’ai exposé plus haut), ce surplus a un autre effet pervers.&lt;/p&gt;
&lt;p&gt;S’ils sont constamment noyés dans des alertes, les astreinteurs vont s’y habituer et cela va inexorablement les conduire à les ignorer. Ce ne sera pourtant pas par flemme ni par manque de professionnalisme.&lt;/p&gt;
&lt;p&gt;En fait, le phénomène est connu sous le terme d’&amp;ldquo;Alert fatigue&amp;rdquo;, que vous connaissez peut-être mieux depuis votre tendre enfant au travers la fable du garçon criant au loup.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Alarm fatigue or alert fatigue occurs when one is exposed to a large number of frequent alarms (alerts) and consequently becomes desensitized to them. Desensitization can lead to longer response times or missing important alarms. [https://en.wikipedia.org/wiki/Alarm_fatigue](Page wikipedia de l’Alarm fatigue)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Concrètement, dans le cas des alertes automatiques, trop d’alertes risque de conduire le cerveau des administrateurs à ignorer un problème important en pensant que c’ est &amp;ldquo;une erreur normale, habituelle&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Il va donc être crucial de n’alerter l’administrateur en astreinte que quand c’est réellement nécessaire.&lt;/p&gt;
&lt;h2 id="implémenter-lastreinte"&gt;Implémenter l’astreinte
&lt;/h2&gt;&lt;p&gt;Maintenant qu’on a bien les idées claires sur ce qu’on doit mettre en place, je vous présente maintenant des solutions que nous avons envisagé (voire retenu).&lt;/p&gt;
&lt;p&gt;Cela n’a pas vocation a être une réponse universelle, mais ça convient aux besoins et aux contraintes que nous avions.&lt;/p&gt;
&lt;h3 id="lorganisation-de-lastreinte"&gt;L’organisation de l’astreinte
&lt;/h3&gt;&lt;p&gt;L’idée était de trouver un compromis entre :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fatigue&lt;/li&gt;
&lt;li&gt;risque d’absence (à cause du repos quotidien ou hebdomadaire)&lt;/li&gt;
&lt;li&gt;répétitions pas trop régulières&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour toutes les raisons que j’ai cité dans le chapitre sur la conception, le roulement qui nous a paru le plus pertinent, et que nous avons mis en place est le suivant :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/07/astreinte_planning.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Cette organisation permet de garantir que :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;si jamais le repos hebdo n’a pas pu être pris en entier, le changement d’astreinteur le lundi lui permet de se reposer&lt;/li&gt;
&lt;li&gt;les appels en journée ne gênent pas la prise du repos quotidien au cas où il n’a pas pu être pris pendant la nuit précédente&lt;/li&gt;
&lt;li&gt;A 5, on a en moyenne 2 semaines sans aucune astreinte, puis une période de 3 ou 4 jours&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ceci permet de garantir donc à la fois les repos et nous parait être un bon compromis entre fréquence et durée des astreintes.&lt;/p&gt;
&lt;h3 id="les-outils-de-la-chaîne-de-supervision"&gt;Les outils de la chaîne de supervision
&lt;/h3&gt;&lt;p&gt;Le choix de l’outil dépendra obligatoirement du contexte. Si vous travaillez dans une équipe réseau, vous n’aurez pas les mêmes besoins et donc pas les mêmes outils qu’une équipe d’exploitation cloud.&lt;/p&gt;
&lt;p&gt;Sans citer directement le nom des produits que nous utilisons, je vais vous donner une liste des types d’outils que nous avons mis en place :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un groupe de serveurs &lt;a class="link" href="https://blog.zwindler.fr/2020/04/13/decouvrir-prometheus-et-grafana-par-lexemple/" &gt;Prometheus + Thanos&lt;/a&gt; pour collecter et stocker les métriques de nos applications dans Kubernetes, mais aussi des services de notre cloud provider (IaaS, SaaS, DBaaS) et des middlewares que nous gérons nous-même (message brokers, bases NoSQL)&lt;/li&gt;
&lt;li&gt;Un outil d’alerting, AlertManager, le composant d’Alerting de Prometheus&lt;/li&gt;
&lt;li&gt;Une plateforme de visualisation &lt;a class="link" href="https://blog.zwindler.fr/2020/04/13/decouvrir-prometheus-et-grafana-par-lexemple/" &gt;Grafana&lt;/a&gt; qui nous permet de visualiser les métriques provenant de différentes sources (majoritairement Prometheus, mais aussi les métriques du cloud providers)&lt;/li&gt;
&lt;li&gt;Une plateforme pour centraliser les logs des applications (ex. Splunk/&lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=ElasticStack" &gt;ElasticStack&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Un outil de supervision externe (ex. Pingdom/StatusCake) pour visualiser l’accès aux services web que nous exposons sur Internet depuis plusieurs points dans le monde&lt;/li&gt;
&lt;li&gt;Un outil d’APM (Application Performance Monitoring, ex. AppDynamics/Dynatrace) pour valider que le ressenti des utilisateurs ne se dégrade pas (plus pernicieux que la coupure franche)&lt;/li&gt;
&lt;li&gt;Un outil pour communiquer en temps réel avec les équipes (chat+audio+visio, de type Teams/Slack/Discord).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour le dernier point, Slack nous était tellement utile pour gérer les incidents que j’ai même créé un bot pour créer des channels dédiés pour chaque incident et y inviter les personnes concernées (managers, ops, call center). Si ça vous intéresse, &lt;a class="link" href="https://github.com/zwindler/redalert" target="_blank" rel="noopener"
&gt;ça s’appelle redalert, c’est open source&lt;/a&gt; et j’en parle dans cet article :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2020/06/15/redalert-gerer-des-incidents-avec-un-bot-slack/" &gt;redalert : gérer les incidents avec un bot Slack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="one-tool-to-rule-them-all"&gt;One tool to rule them all
&lt;/h3&gt;&lt;p&gt;Comme vous pouvez le voir, ça fait quand même beaucoup de types d’outils différents. Et même si les éditeurs tentent de vous convaincre que vous pouvez tout faire avec un seul outil, c’est probablement faux dès que votre contexte est un peu complexe.&lt;/p&gt;
&lt;p&gt;Cependant, pour éviter de se retrouver avec un trop grand nombre de sources de données distinctes, le mieux est de remonter toutes les alertes vers une seule et même plateforme :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un outil de réponse aux incidents (tel que OpsGenie/PagerDuty par exemple). L’outil de réponse aux incidents permet de gérer les rotations de notre équipe d’astreinte, l’éventuelle escalade, d’avoir des métriques de base sur les incidents, leur provenance et leur durée, etc. Mais le plus important : de notifier la personne d’astreinte sur différents types de canaux (notification push sur smartphone, SMS, appel vocal via TTS, slack, &amp;hellip;), de manière entièrement configurable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cet outil est vraiment la pièce maîtresse, qui apporte la cohérence à tout le reste. Choisissez donc le bien !&lt;/p&gt;
&lt;h2 id="quest-ce-quil-manque-"&gt;Qu’est ce qu’il manque ?
&lt;/h2&gt;&lt;p&gt;Vous aurez très certainement besoin de sortir des informations (dashboards, statistiques) sur les incidents du mois (pour suivre la charge, la fatigue des équipes, gérer la paie si les heures d’intervention sont payées ou récupérées).&lt;/p&gt;
&lt;p&gt;Généralement, on peut utiliser le reporting intégré à l’outil de réponse aux incidents, mais c’est souvent assez pauvre.&lt;/p&gt;
&lt;p&gt;Comme nous voulions pouvoir faire des stats et &amp;ldquo;déclarer&amp;rdquo; les durées des astreintes ainsi que leur nombre aux RHs (pour calculer les récupérations), nous avons pris le parti de tenir à jour nous-même un fichier des interventions.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/07/astreinte_saisie.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Cette feuille de calcul, assez riche (avec beaucoup de macros et de formules magiques), nous permet d’avoir toutes les données pour ensuite calculer tous les indicateurs dont nous avons besoin.&lt;/p&gt;
&lt;p&gt;Actuellement, la seule chose qui pourrait manquer est un outil pour calculer si le repos quotidien/hebdomadaire a été respecté ou non.&lt;/p&gt;
&lt;p&gt;Ceci pourrait être fait via la feuille de calcul (puisqu’on a toutes les infos) mais n’est pas très user friendly (ni trivial à implémenter).&lt;/p&gt;
&lt;p&gt;J’ai demandé sur Twitter s’il existait un outil pour faire ça, mais a priori rien n’existe &amp;ldquo;out of the box&amp;rdquo;&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2021/tweet_astreinte.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="et-vous-vous-faites-comment-"&gt;Et vous, vous faites comment ?
&lt;/h2&gt;&lt;p&gt;Enfin fini ! Je suis bavard, je sais ;). Mais comme vous avez pu le voir, c’est un sujet aussi complet que complexe.&lt;/p&gt;
&lt;p&gt;Cependant, ces deux posts n’étaient que ma vision propre de l’astreinte. Je suis sûr que vous avez vous aussi des besoins et des contraintes différentes.&lt;/p&gt;
&lt;p&gt;Donc vraiment (encore plus que d’habitude) n’hésitez pas à utiliser les commentaires pour donner votre avis et nous parler de votre propre organisation.&lt;/p&gt;
&lt;p&gt;Ça pourra en aider d’autres :).&lt;/p&gt;</description></item><item><title>Superviser votre instance Jitsi avec Prometheus et Grafana</title><link>https://blog.zwindler.fr/2020/06/08/superviser-votre-instance-jitsi-avec-prometheus-et-grafana/</link><pubDate>Mon, 08 Jun 2020 06:35:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/06/08/superviser-votre-instance-jitsi-avec-prometheus-et-grafana/</guid><description>&lt;img src="https://blog.zwindler.fr/2020/04/10participants.webp" alt="Featured image of post Superviser votre instance Jitsi avec Prometheus et Grafana" /&gt;&lt;h2 id="quel-rapport-entre-jitsi-et-prometheus-"&gt;Quel rapport entre Jitsi et Prometheus ?
&lt;/h2&gt;&lt;p&gt;Si vous avez suivi un peu mes articles depuis le début du confinement, vous aurez vu qu’en ce moment je fais du Jitsi (cf &lt;a class="link" href="https://blog.zwindler.fr/2020/03/17/ta-visio-open-source-comme-un-pro-avec-jitsi/" &gt;Ta visio Open Source comme un pro avec Jitsi&lt;/a&gt;) et du Prometheus (cf &lt;a class="link" href="https://blog.zwindler.fr/2020/04/13/decouvrir-prometheus-et-grafana-par-lexemple/" &gt;Découvrir Prometheus et Grafana par l’exemple&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Et ça tombe super bien, car aujourd’hui je vais vous parler des deux !&lt;/p&gt;
&lt;h2 id="lappel-des-chatons"&gt;L’appel des Chatons
&lt;/h2&gt;&lt;p&gt;J’ai pas trop communiqué là dessus, mais lorsque le confinement a commencé, les ENT étant down, beaucoup d’enseignants se sont tournés vers Framasoft, qui héberge entre autre des services d’éditions de texte en collaboratif ainsi que des instances de visio conférences Jitsi.&lt;/p&gt;
&lt;p&gt;Ça a pas mal râlé côté Framasoft car ça fait des années qu’ils expliquent qu’en tant qu’association 1901, ils n’ont ni les moyens ni l’envie de supporter les conséquences des mauvais choix technologiques / budgétaires de l’éducation nationale. (Si vous voyez pas trop où que je veux en venir, allez voir leur site, ils l’expliquent mieux que moi). Et de fermer ces deux services temporairement dans la foulée.&lt;/p&gt;
&lt;p&gt;Suite à quoi, les CHATONS se sont proposés de faire le relais en listant un ensemble de services Jitsi et Etherpad mis à dispositions par des CHATONS et des particuliers (et maintenant plus encore).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/04/framasoft_jitsi_chatons.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;J’ai pas trop communiqué là dessus, mais moi aussi j’ai mis mon instance à dispo.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/04/chaton.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Coucouuuuuu, je suis là !!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="et-alors-des-gens-sen-servent-"&gt;Et alors, des gens s’en servent ?
&lt;/h2&gt;&lt;p&gt;C’est super cool, j’ai mis à dispo une instance jitsi qui a priori a été utile à plusieurs personnes.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/04/jitsi_croixrouge_be.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Mais jusqu’à présent, au delà du trafic CPU/réseau que je vois monter de temps en temps, je n’avais aucune idée de la quantité de conférences qui se tenaient sur mon instance.&lt;/p&gt;
&lt;p&gt;Puis, j’ai vu ce tweet de pyg, qui m’a relancé sur le sujet.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/04/pyg_jitsi.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ouuuaaaah, la classe :D&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A vue de nez, c’est du Grafana. J’ai donc voulu trouver comment brancher Jitsi à ma supervision existante.&lt;/p&gt;
&lt;h2 id="deux-exporters-pour-le-prix-dun"&gt;Deux exporters pour le prix d’un
&lt;/h2&gt;&lt;p&gt;La première chose à faire était donc de trouver un exporter prometheus compatible avec Jitsi, histoire de pouvoir capitaliser sur l’infrastructure (Grafana/Prom) actuelle.&lt;/p&gt;
&lt;p&gt;J’ai trouvé 2 projets en Go :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;jitsi-prom-exporter dont j’ai trouvé la trace sur &lt;a class="link" href="https://community.jitsi.org/t/monitoring-jvb-metrics-prometheus-grafana/19822" target="_blank" rel="noopener"
&gt;le forum de jitsi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/xsteadfastx/jitsiexporter" target="_blank" rel="noopener"
&gt;jitsiexporter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les deux n’étant pas franchement bien documentés (et je suis une quiche en Go), je me suis d’abord orienté vers jitsi-prom-exporter, plus &amp;ldquo;connu&amp;rdquo; (enfin, ça se joue à 10 étoiles sur Github hein&amp;hellip;).&lt;/p&gt;
&lt;p&gt;Mais je n’ai jamais réussi à le compiler (vive le Go) et comme je n’y comprend rien après avoir ragé quelques heures (ma femme confirme) j’ai laissé tombé. [Edit]En vrai j’ai fini par le faire marché avec de l’aide et beaucoup de trial and error mais bon&amp;hellip; Il faut faire &lt;a class="link" href="https://github.com/karrieretutor/jitsi-prom-exporter/issues/3#issuecomment-614512142" target="_blank" rel="noopener"
&gt;ça&lt;/a&gt;, &lt;a class="link" href="https://github.com/karrieretutor/jitsi-prom-exporter/issues/3#issuecomment-614651103" target="_blank" rel="noopener"
&gt;ça&lt;/a&gt; puis &lt;a class="link" href="https://github.com/karrieretutor/jitsi-prom-exporter/issues/3#issuecomment-614909928" target="_blank" rel="noopener"
&gt;ça&lt;/a&gt; [/Edit]&lt;/p&gt;
&lt;p&gt;En revanche, &lt;a class="link" href="https://github.com/xsteadfastx/jitsiexporter" target="_blank" rel="noopener"
&gt;jitsiexporter&lt;/a&gt;, j’ai réussi à le faire fonctionner assez vite ! Et je vous propose qu’on se l’installe ensemble !&lt;/p&gt;
&lt;h2 id="activer-les-statistiques"&gt;Activer les statistiques
&lt;/h2&gt;&lt;p&gt;La première chose à faire et de vérifier dans votre install de Jitsi si l’API REST est activée ou non. Si ce n’est pas le cas, vous pouvez tenter de modifier les propriétés du sip-communicator de videobridge.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ps -ef | grep jvb
jvb 164 1 0 20:09 ? 00:00:56 java -Xmx3072m [...] --apis=rest,
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pour être honnête, je ne suis pas encore bien bien sûr à 100% ce qu’il faut faire pour être sûr que c’est actif. La documentation du projet Github de l’exporter n’est pas hyper claire et j’ai lu pas mal d’instruction contradictoire sur les forums&amp;hellip;&lt;/p&gt;
&lt;p&gt;En fin d’article, je vous ai mis deux liens vers la doc officielle de Jitsi à ce sujet.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;vi /etc/jitsi/videobridge/sip-communicator.properties
[...]
org.jitsi.videobridge.ENABLE_STATISTICS=true
org.jitsi.videobridge.STATISTICS_TRANSPORT=muc,colibri
org.jitsi.videobridge.STATISTICS_INTERVAL=1000
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Une fois que c’est bon, un petit curl` vous permettra de vous assurer que tout va bien.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;curl http://127.0.0.1:8080/colibri/stats
{&amp;#34;inactive_endpoints&amp;#34;:0,&amp;#34;inactive_conferences&amp;#34;:0,&amp;#34;total_ice_succeeded_relayed&amp;#34;:0,&amp;#34;total_loss_degraded_participant_seconds&amp;#34;:0,&amp;#34;bit_rate_download&amp;#34;:0,&amp;#34;muc_clients_connected&amp;#34;:1,&amp;#34;total_participants&amp;#34;:0,...
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="installer-lexporter"&gt;Installer l’exporter
&lt;/h2&gt;&lt;p&gt;Maintenant que notre Jitsi nous donne bien des statistiques en local, on va pouvoir commencer à utiliser un exporter pour consommer les métriques périodiquement et les servir au format Prometheus.&lt;/p&gt;
&lt;h3 id="prérequis-pour-la-compilation"&gt;Prérequis pour la compilation
&lt;/h3&gt;&lt;p&gt;D’abord il nous faut go&amp;hellip; Sur un Ubuntu 18.04 ça donne ça :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository ppa:longsleep/golang-backports
sudo apt update
sudo apt install golang-go git
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="compiler"&gt;Compiler
&lt;/h3&gt;&lt;p&gt;Ensuite, il faut compiler l’exporter. En théorie, comme Go fait des binaires &amp;ldquo;qui marchent partout&amp;rdquo;, vous pouvez compiler l’exporter sur votre poste et envoyer le binaire sur le serveur jitsi. En théorie&amp;hellip;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;su - jvb
mkdir -p go/src &amp;amp;&amp;amp; mkdir -p go/bin
cd go/src
git clone https://github.com/xsteadfastx/jitsiexporter
cd jitsiexporter
go get ./...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si tout se passe bien, un binaire est créé dans &lt;code&gt;~/go/bin&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="tester-lexporter"&gt;Tester l’exporter
&lt;/h2&gt;&lt;p&gt;Maintenant qu’on a un exporter, on va le tester en le lançant à la main, pour valider toute la chaîne. Les paramètres sont assez simples. Il faut renseigner d’un côté l’URL du serveur REST et de l’autre adresse/port sur lesquels on veut que l’exporter accepte les requêtes de Prometheus.&lt;/p&gt;
&lt;p&gt;Par défaut c’est localhost donc il est fort probable que vous vouliez changer ça.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/usr/share/jitsi-videobridge/go/bin/jitsiexporter --url=&amp;#39;http://127.0.0.1:8080/colibri/stats&amp;#39; --host=192.168.1.100 --port=9700
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="un-service-pour-automatiser-le-démarrage-au-démarrage"&gt;Un service pour automatiser le démarrage au&amp;hellip; démarrage
&lt;/h2&gt;&lt;p&gt;Comme d’habitude, une fois qu’on a l’exporter qui marche oneshot, le mieux c’est quand même d’avoir un service systemd` qui va nous faciliter le démarrage/l’extinction du service :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;gt; /etc/systemd/system/jitsiexporter.service &amp;lt;&amp;lt; EOF
[Unit]
Description=Jitsi videobridge Prometheus Exporter
After=jitsi-videobridge2.service
Requires=jitsi-videobridge2.service
[Service]
User=jvb
Restart=on-failure
ExecStart=/usr/share/jitsi-videobridge/go/bin/jitsiexporter --url=&amp;#39;http://127.0.0.1:8080/colibri/stats&amp;#39; --host=192.168.1.100 --port=9700
[Install]
WantedBy=multi-user.target
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;systemctl daemon-reload
systemctl enable jitsiexporter
systemctl start jitsiexporter
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="configurer-prometheus"&gt;Configurer Prometheus
&lt;/h2&gt;&lt;p&gt;Vous l’avez compris, il reste donc maintenant à relier Prometheus à notre exporter pour commencer à scrapper des métriques. Ici, il s’agira donc simplement d’ajouter une nouvelle section &amp;ldquo;job&amp;rdquo; dans notre configuration de Prometheus et à redémarrer pour prise en compte.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;vi /usr/share/prometheus/prometheus.yml
[...]
- job_name: &amp;#39;jitsi&amp;#39;
static_configs:
- targets:
- 192.168.1.100:9700 # jitsiexporter for jitsi videobridge
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;systemctl restart prometheus
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="et-le-résultat-"&gt;Et le résultat ?
&lt;/h2&gt;&lt;p&gt;Bon, faut avouer que c’est pas foufou, j’ai eu quelques conférences en 2 semaines (pas beaucoup plus d’une par jour), mais un joli score tout de même cette conf d’1h30 avec au max 10 personnes !&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/04/10participants.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Vous savez tout ! Have fun :D&lt;/p&gt;
&lt;h2 id="sources-additionnelles"&gt;Sources additionnelles
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/jitsi/jitsi-videobridge/blob/master/doc/statistics.md" target="_blank" rel="noopener"
&gt;Documentation sur les statistiques sur le site de Jitsi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/jitsi/jitsi-videobridge/blob/master/doc/rest.md" target="_blank" rel="noopener"
&gt;Documentation sur l’API REST sur le site de Jitsi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Découvrir Prometheus et Grafana par l’exemple</title><link>https://blog.zwindler.fr/2020/04/13/decouvrir-prometheus-et-grafana-par-lexemple/</link><pubDate>Mon, 13 Apr 2020 06:40:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/04/13/decouvrir-prometheus-et-grafana-par-lexemple/</guid><description>&lt;img src="https://blog.zwindler.fr/2020/01/20200102_084825-2.webp" alt="Featured image of post Découvrir Prometheus et Grafana par l’exemple" /&gt;&lt;h2 id="grafana-et-prometheus"&gt;Grafana et Prometheus
&lt;/h2&gt;&lt;p&gt;Ça fait plusieurs articles que je vous parle de &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=Prometheus" &gt;Prometheus et de Grafana&lt;/a&gt;, notamment pour l’installer. Mais je n’avais pas encore pris le temps de faire un article pour vous montrer comment les utiliser (et pourquoi ces deux outils sont géniaux) !&lt;/p&gt;
&lt;p&gt;Typiquement, ça va nous permettre de réaliser ce genre de dashboard, qui permettra aux équipes (production, dev, voire même équipes fonctionnelles) de voir en un coup d’œil si tout va bien ou au contraire, ce qui va mal.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/01/20200102_084825-2-1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="un-cas-utile"&gt;Un cas utile
&lt;/h2&gt;&lt;p&gt;Et tant qu’à présenter les outils, je me suis dis que j’allais utiliser un des exemples que j’avais eu à mettre en place &lt;em&gt;dans la vraie vie&lt;/em&gt; : tester que mes déploiements Kubernetes respectent bien l’anti-affinité.&lt;/p&gt;
&lt;p&gt;Cet exemple est volontairement &amp;ldquo;un peu complexe&amp;rdquo;, car il a vocation à vous permettre d’appréhender d’un seul coup plusieurs concepts qui seront utiles pour bien débuter dans Grafana et Prometheus. Notamment, la sélection de la bonne métrique, le langage PromQL, l’ajout de variables dans les dashboards, etc.&lt;/p&gt;
&lt;p&gt;Note : Pour ceux qui ne l’ont pas, dans l’orchestrateur de containers Kubernetes, il est possible d’indiquer à l’outil que 2 replicas d’une même application (pour la redondance) ne doivent pas être exécutée sur la même ressource. Ça permet entre autre de garantir qu’il n’y a pas un SPOF au niveau de l’hôte qui exécute les containers alors qu’on croit avoir une application redondante.&lt;/p&gt;
&lt;h2 id="trouver-les-métriques-dans-prometheus"&gt;Trouver les métriques dans Prometheus
&lt;/h2&gt;&lt;p&gt;Je vais partir du principe que vous avez déjà une plateforme opérationnelle, équipée d’un Prometheus et d’un Grafana. Si ce n’est pas le cas, je vous invite à faire une rapide recherche sur votre moteur de recherche préféré ou de &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=prometheus" &gt;consulter mes précédents articles sur le sujet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;La première étape avant de commencer à essayer de monter de beaux dashboards consiste à chercher la métrique qui nous intéresse. Car, il faut bien l’admettre, généralement Prometheus en collecte BEAUCOUP !&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/prometheus_timeseries01.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Rien que Prometheus lui même expose et stocke plus de 700 métriques&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On va donc se connecter sur notre serveur Prometheus, puis requêter l’ensemble des métriques disponibles pour en trouver une qui permette de répondre simplement à notre problème.
Pour reprendre l’exemple que j’ai choisi, je veux :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pour tous les Pods&lt;/li&gt;
&lt;li&gt;m’assurer que plusieurs Pods d’un même déploiement ne sont pas exécuté sur le même serveur&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour ça, j’ai donc besoin d’avoir une métrique qui me permettre d’avoir tous les Pods, un information sur le Deploiement concerné, ainsi que le Node sur lequel le Pod est exécuté.&lt;/p&gt;
&lt;h2 id="container_last_seen"&gt;container_last_seen
&lt;/h2&gt;&lt;p&gt;Il y a probablement plusieurs façon de répondre à cette interrogation, mais une des solutions qui marchent plutôt bien pour moi est d’utiliser la métrique &lt;em&gt;container_last_seen&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;En recherchant des métriques dans la console de Prometheus, j’ai pu remarquer que cette métrique donne, pour tous les containers, la date à laquelle il a été vu pour la dernière fois, ainsi qu’un certain nombre d’information sur chaque container.&lt;/p&gt;
&lt;h2 id="on-valide-sur-un-cas-particulier"&gt;On valide sur un cas particulier
&lt;/h2&gt;&lt;p&gt;Pour vérifier que la métrique que je vous indique répond bien à notre problème, je vous propose de tester avec un exemple.&lt;/p&gt;
&lt;p&gt;La requête PromQL suivante permet d’afficher les containers responsable de la résolution DNS interne de mon Kubernetes (déployé dans le namespace &lt;em&gt;kube-system&lt;/em&gt;) :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/09/prometheus1-1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;container_last_seen{container_name=~&amp;#34;.*dns.*&amp;#34;,namespace=~&amp;#34;kube-system&amp;#34;}
container_last_seen{[...],container_name=&amp;#34;dns&amp;#34;,instance=&amp;#34;node1&amp;#34;,namespace=&amp;#34;kube-system&amp;#34;,pod_name=&amp;#34;coredns-xxxxxxxx-yyyyy&amp;#34;,[...]} 1577569793
container_last_seen{[...],container_name=&amp;#34;dns&amp;#34;,instance=&amp;#34;node2&amp;#34;,namespace=&amp;#34;kube-system&amp;#34;,pod_name=&amp;#34;coredns-xxxxxxxx-zzzzz&amp;#34;,[...]} 1577566730
container_last_seen{[...],container_name=&amp;#34;dns&amp;#34;,instance=&amp;#34;node3&amp;#34;,namespace=&amp;#34;kube-system&amp;#34;,pod_name=&amp;#34;coredns-xxxxxxxx-aaaaa&amp;#34;,[...]} 1577569313
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pour ceux qui débutent en PromQL, il s’agit du langage de requêtage de Prometheus, et qui permet entre autre de filtrer les timeseries affichées en fonction de critères (listés dans la partie entre les accolades).&lt;/p&gt;
&lt;p&gt;Dans les résultats de la requête, on a bien :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le nom de notre Deployment (container_name)&lt;/li&gt;
&lt;li&gt;le nom de l’hôte qui héberge le container (instance)&lt;/li&gt;
&lt;li&gt;le nom du Pod (pod_name)&lt;/li&gt;
&lt;li&gt;le namespace&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="créer-notre-visualisation-dans-grafana"&gt;Créer notre visualisation dans Grafana
&lt;/h2&gt;&lt;p&gt;Maintenant qu’on a trouvé la métriques qui nous intéresse, on peut aller dans Grafana et créer un nouveau Dashboard&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_reate_dashboard.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Puis un nouveau Panel dans notre Dashboard fraîchement créé :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_nouveau_panel.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;A partir de là, on pourrait directement afficher les données de notre métrique, mais ça ne serait pas très informatif. On serait noyé sous une masse de conteneurs, chacun avec leurs variables.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_query.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Bref, on va devoir restreindre tout ça, notamment via des variables, pour que ça devienne exploitable !&lt;/p&gt;
&lt;h2 id="il-y-en-a-beaucoup-trop"&gt;Il y en a beaucoup trop
&lt;/h2&gt;&lt;p&gt;Dans la capture que j’ai faite juste avant, j’ai quand même été obligé de restreindre à un seul namespace, pour ne pas noyer Prometheus et Grafana. Et encore, c’est (toujours) parfaitement inexploitable.&lt;/p&gt;
&lt;p&gt;Clairement, on ne va pas vouloir se contenter d’une sélection &amp;ldquo;statique&amp;rdquo; des namespaces, au risque de devoir faire un &lt;em&gt;graphique&lt;/em&gt; par &lt;em&gt;namespace&lt;/em&gt; Kubernetes (et vous en avez peut être beaucoup).&lt;/p&gt;
&lt;p&gt;On va donc récupérer la liste des namespaces disponibles dans Prometheus et l’afficher dans une liste déroulante dans notre Dashboard. Cette liste permettra de filtrer les données par namespace pour ne pas faire planter Prometheus.&lt;/p&gt;
&lt;h2 id="les-variables-dans-le-dashboard"&gt;Les variables dans le Dashboard
&lt;/h2&gt;&lt;p&gt;Pour se faire, on va devoir de nouveau trouver la valeur la plus adaptée dans notre source de données Prometheus.&lt;/p&gt;
&lt;p&gt;Je ne vais pas vous faire retourner dans Prometheus pour ça, celle que moi j’utilise, c’est celle ci :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kube_namespace_labels{namespace!~&amp;#34;kube-.*|default&amp;#34;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cette requête PromQL permet de lister l’ensemble des namespaces présents dans votre cluster Kubernetes, puis, entre les accolades, de filtrer pour retirer les namespaces respectant les regexp &amp;ldquo;kube-.*&amp;rdquo; et &amp;ldquo;default&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/09/variables2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Pour autant, on est pas encore complètement sorti d’affaire puisqu’on doit maintenant récupérer uniquement la partie rouge dans ma capture d’écran, qui est la liste des noms des namespaces.&lt;/p&gt;
&lt;p&gt;Arrive alors Grafana, qui fournit une fonction supplémentaire label_values, et qui permet, à partir d’une liste des timeseries Prometheus, de récupérer la valeur d’un seul champ de la timeserie :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;label_values(kube_namespace_labels{namespace!~&amp;#34;kube-.*|default&amp;#34;},namespace)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et tant qu’a y être, on va également se garder sous le coude une autre requête, quasiment identique, mais qui va nous permettre d’avoir la liste des déploiements présents dans votre cluster pour un (ou plusieurs) namespaces donnés :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;label_values(kube_deployment_labels{namespace=~&amp;#34;$k8snamespace&amp;#34;}, deployment)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A partir de là, je peux ajouter des Variables dans mon Dashboard. Pour le faire, on doit cliquer sur la roue crantée en haut à droite de notre Dashboard :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_roue_crantee.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Puis ouvrir le menu &amp;ldquo;Variables&amp;rdquo; et ajouter les variables&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_variable_3.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;A partir du moment où votre source de données et votre requête est entrée dans les champs &lt;em&gt;Data source&lt;/em&gt; et &lt;em&gt;query&lt;/em&gt;, Grafana va vous donner un aperçu des valeurs qui seront disponibles (tout en bas du formulaire). Un bon moyen de vérifier que tout est bon avant de passer à l’étape suivante.&lt;/p&gt;
&lt;h2 id="dans-le-dashboard-nos-variables-apparaissent-"&gt;Dans le dashboard, nos variables apparaissent !
&lt;/h2&gt;&lt;p&gt;On sauvegarde et on retourne dans notre Dashboard.&lt;/p&gt;
&lt;p&gt;Si tout s’est bien passé, on a maintenant, en haut de notre Dashboard, plusieurs variables avec des menus déroulant pour les sélectionner.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/09/variables3.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Mais ce n’est pas magique pour autant&amp;hellip;&lt;/p&gt;
&lt;p&gt;Point un peu pénible, on va devoir maintenant modifier toutes nos visualisations (graphiques) pour prendre en compte le fait qu’on ajoute une variable.&lt;/p&gt;
&lt;p&gt;Je ne saurai donc que trop vous conseiller de bien réfléchir à &lt;em&gt;comment&lt;/em&gt; vous allez variabiliser vos Dashboard &lt;em&gt;avant&lt;/em&gt; d’avoir trop de visualisation statiques&amp;hellip;&lt;/p&gt;
&lt;h2 id="ajout-de-la-variable-dans-notre-visualisation"&gt;Ajout de la variable dans notre visualisation
&lt;/h2&gt;&lt;p&gt;On va donc ajouter la variable de manière à rendre nos graphiques dynamiques en fonction des valeurs sélectionnées dans le Dashboard, en modifiant la requête précédente par celle ci :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;container_last_seen{namespace=~&amp;#34;$k8snamespace&amp;#34;,container_name=~&amp;#34;$k8sdeployment.*&amp;#34;,container_name!=&amp;#34;POD&amp;#34;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Qu’est ce qui a changé ?&lt;/p&gt;
&lt;p&gt;Déjà, votre requête devrait répondre beaucoup plus vite ! Et pour cause, on vient non seulement de restreindre à un seul namespace (celui correspondant à la variable Grafana $k8snamespace et non plus la valeur fixe &amp;ldquo;kube-system&amp;rdquo;) mais aussi à un seul Deployment donné (via $k8sdeployment).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: on a également dégagé les containers s’appelant &amp;ldquo;POD&amp;rdquo;, qui vont fausser les statistiques.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Pour autant, notre graphique n’est toujours pas exploitable&amp;hellip; On voit bien qu’il existe 2 Pods pour mon Deployment, et si on cherche bien on pourra voir dans la timeserie sur quel Node chaque replica tourne, mais c’est fastidieux&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_var1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;La valeur de chaque timeserie monte de manière constante. C’est normal, c’est un « uptime »&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="compter-le-nombre-de-pod-par-node"&gt;Compter le nombre de Pod par Node
&lt;/h2&gt;&lt;p&gt;On va s’en sortir en tirant parti d’une autre variable présente dans nos timeseries (qu’on a justement remarqué plus haut) : instance, ainsi que d’une fonction d’aggrégation du PromQL : count.&lt;/p&gt;
&lt;p&gt;Cette variable permet, dans notre requête de savoir sur quel Node Kubernetes se situe notre Pod.&lt;/p&gt;
&lt;p&gt;Voilà ce qu’on obtiendra en modifiant la requête de notre visualisation :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;count(container_last_seen{namespace=~&amp;#34;$k8snamespace&amp;#34;,container_name=~&amp;#34;$k8sdeployment.*&amp;#34;,container_name!=&amp;#34;POD&amp;#34;}) by (instance)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/09/grafana1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Avec restriction sur le déploiement&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Là, c’est encore fastidieux, mais on commence à entrevoir la réponse à notre question initiale.
Dans les derniers graphiques, les couleurs représentent les Nodes Kubernetes, et la valeur numérique le nombre de Pods qui tournent dessus pour un Namespace donné. On voit donc que globalement, pour cet exemple précis, les Pods semblent bien répartis (puisque qu’on sélectionne un seul Deployment, on a bien un Pod par Node).&lt;/p&gt;
&lt;h2 id="et-la-solution-"&gt;Et la solution ?
&lt;/h2&gt;&lt;p&gt;Comment on fait pour voir tous les déploiements d’un coup ? Là, ça commence à devenir un peu plus touchy.&lt;/p&gt;
&lt;p&gt;En vrai, la solution n’a plus vraiment d’intérêt en terme de découverte dans l’utilisation de Prometheus et de Grafana, dont j’ai montré les fonctionnalités lors des précédents paragraphes. Cependant, je ne vais pas vous laisser sur un cliffhanger ;-)&lt;/p&gt;
&lt;p&gt;Je ne vais &lt;em&gt;tout&lt;/em&gt; détailler, mais dans l’idée, la solution que j’ai trouvée (il y en a peut être de plus élégantes) est :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;de lister tous les couples nom du déploiement + nom de l’hôte qui l’héberge&lt;/li&gt;
&lt;li&gt;de regrouper &lt;em&gt;par déploiement&lt;/em&gt; les items de la liste précédente et d’en faire une somme pour chaque déploiement&lt;/li&gt;
&lt;li&gt;de diviser chacun des items de cette dernière liste par le nombre total de container par déploiement&lt;/li&gt;
&lt;li&gt;d’afficher la liste des valeurs inférieures à 1&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1. count(container_last_seen{namespace=~&amp;#34;$k8snamespace&amp;#34;,container_name!~&amp;#34;^$|POD&amp;#34;}) by (container_name,instance))
2. count(count(container_last_seen{namespace=~&amp;#34;$k8snamespace&amp;#34;,container_name!~&amp;#34;^$|POD&amp;#34;}) by (container_name,instance)) by (container_name)
3. count(count(container_last_seen{namespace=~&amp;#34;$k8snamespace&amp;#34;,container_name!~&amp;#34;^$|POD&amp;#34;}) by (container_name,instance)) by (container_name) / count(container_last_seen{namespace=~&amp;#34;$k8snamespace&amp;#34;,container_name!~&amp;#34;^$|POD&amp;#34;}) by (container_name)
4. count(count(container_last_seen{namespace=~&amp;#34;$k8snamespace&amp;#34;,container_name!~&amp;#34;^$|POD&amp;#34;}) by (container_name,instance)) by (container_name) / count(container_last_seen{namespace=~&amp;#34;$k8snamespace&amp;#34;,container_name!~&amp;#34;^$|POD&amp;#34;}) by (container_name) &amp;lt; 1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ainsi, avec cette dernière formule, on peut lister l’ensemble des Deployments Kubernetes dont il existe un nombre de replica supérieur au nombre de Nodes qui les hébergent (et donc, de dénicher des soucis sur l’anti-affinités et par extension, de potentiels SPOF).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/09/grafana6.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;CQFD :-D&lt;/p&gt;</description></item><item><title>Proxmox VE + Prometheus = &lt;3</title><link>https://blog.zwindler.fr/2020/01/06/proxmox-ve-prometheus/</link><pubDate>Mon, 06 Jan 2020 07:15:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/01/06/proxmox-ve-prometheus/</guid><description>&lt;img src="https://blog.zwindler.fr/2019/11/grafana_prometheus_proxmox.webp" alt="Featured image of post Proxmox VE + Prometheus = &lt;3" /&gt;&lt;h2 id="proxmox-et-prometheus-sont-dans-un-bateau"&gt;Proxmox et Prometheus sont dans un bateau&amp;hellip;
&lt;/h2&gt;&lt;p&gt;Si vous avez suivi le précédent &lt;a class="link" href="https://blog.zwindler.fr/2019/11/12/tutoriel-installer-prometheus-grafana-sans-docker/" &gt;article sur Prometheus et Grafana&lt;/a&gt;, vous m’avez peut être vu teaser cet article.&lt;/p&gt;
&lt;p&gt;En effet, j’avais mis une capture d’écran d’un dashboard Grafana avec des métriques provenant de mon cluster Proxmox VE :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/11/grafana_prometheus_proxmox.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On fait du LXC à fond ici !caption&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="petit-récap"&gt;Petit récap’
&lt;/h2&gt;&lt;p&gt;Pour rappel, &lt;a class="link" href="https://blog.zwindler.fr/2019/11/12/tutoriel-installer-prometheus-grafana-sans-docker/" &gt;dans le tuto précédent&lt;/a&gt;, on avait installé le couple Grafana + Prometheus sur une machine virtuelle (ou physique peu importe), et pas dans un container (comme le préconise la plupart des billets de blogs que j’ai pu lire). Maintenant vous comprenez surement mieux pourquoi ;-).&lt;/p&gt;
&lt;p&gt;Pour alimenter notre Prometheus, on va donc vouloir le donner à manger. Et quoi de mieux dans une infrastructure &lt;em&gt;non containerisée&lt;/em&gt; que les métriques de l’hyperviseur ?&lt;/p&gt;
&lt;h2 id="prometheus-pve-exporter"&gt;prometheus-pve-exporter
&lt;/h2&gt;&lt;p&gt;On est plutôt gâté avec Proxmox VE, car les métriques pertinentes sont assez nombreuses et surtout exposées par API.&lt;/p&gt;
&lt;p&gt;S’il n’existe pas d’&lt;em&gt;exporter officiel&lt;/em&gt;, il existe néanmoins des implémentations Open Source réalisées par de gentils contributeurs.&lt;/p&gt;
&lt;p&gt;La plus utilisée semble être celle de &lt;strong&gt;znerol&lt;/strong&gt;, qui a en plus l’avantage d’être la base utilisée dans un dashboard sur le site de Grafana (on y reviendra). Dans la mesure du possible, j’essaye de rester sur les implémentations les plus couramment utilisées. Sauf exception, ça permet d’éviter d’être le seul à avoir un bug. Je vous ai mis une autre implémentation dans les sources en bas d’article, que je n’ai pas testée.&lt;/p&gt;
&lt;p&gt;Les sources et la documentation sont disponibles sur Github à l’adresse suivante : &lt;a class="link" href="https://github.com/znerol/prometheus-pve-exporter" target="_blank" rel="noopener"
&gt;github.com/znerol/prometheus-pve-exporter&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="prérequis"&gt;Prérequis
&lt;/h2&gt;&lt;p&gt;Dans tous les cas, on va devoir créer un utilisateur dans Proxmox VE, a qui on va autoriser l’accès aux métriques depuis l’API. C’est cet utilisateur qu’utilisera notre &lt;em&gt;exporter&lt;/em&gt; pour se connecter à PVE, récupérer les métriques et enfin les exposer au format &lt;a class="link" href="https://openmetrics.io/" target="_blank" rel="noopener"
&gt;OpenMetrics&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sur un des serveurs PVE du cluster :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;créer un groupe&lt;/li&gt;
&lt;li&gt;ajouter le rôle PVEAuditor au groupe&lt;/li&gt;
&lt;li&gt;créer un utilisateur&lt;/li&gt;
&lt;li&gt;lui ajouter le groupe, puis un mot de passe&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pveum groupadd monitoring -comment &amp;#39;Monitoring group&amp;#39;
pveum aclmod / -group monitoring -role PVEAuditor
pveum useradd pve_exporter@pve
pveum usermod pve_exporter@pve -group monitoring
pveum passwd pve_exporter@pve
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="installation-de-lexporter"&gt;Installation de l’&lt;em&gt;exporter&lt;/em&gt;
&lt;/h2&gt;&lt;p&gt;A partir de là, on peut installer l’&lt;em&gt;exporter&lt;/em&gt; sur nos serveurs PVE. L’avantage du cet &lt;em&gt;exporter&lt;/em&gt; c’est qu’il sait gérer le cluster. Je veux dire par là qu’avec un seul &lt;em&gt;exporter&lt;/em&gt; vous allez pouvoir collecter l’ensemble des métriques de l’ensemble de vos machines du cluster (containers, VMs, stockage, hyperviseurs, &amp;hellip;).&lt;/p&gt;
&lt;p&gt;En théorie, il n’est donc nécessaire de l’installer que sur une machine. Pour autant, je vous conseille quand même d’installer un &lt;em&gt;exporter&lt;/em&gt; par serveur. Dans les faits, cela vous évitera de perdre toute collecte de données de supervision en cas de panne du seul serveur portant l’&lt;em&gt;exporter&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Sur vos serveurs PVE, lancer les commandes suivantes :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;apt-get install python-pip
pip install prometheus-pve-exporter
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cette implémentation utilise le gestionnaire de paquet de Python, pip.&lt;/p&gt;
&lt;p&gt;On va ensuite créer un fichier de configuration qui va contenir les informations de connexion à notre PVE :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;mkdir -p /usr/share/pve_exporter/
cat &amp;gt; /usr/share/pve_exporter/pve_exporter.yml &amp;lt;&amp;lt; EOF
default:
user: pve_exporter@pve
password: myawesomepassword
verify_ssl: false
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Note : remplacer &lt;strong&gt;myawesomepassword&lt;/strong&gt; par un mot de passe vraiment cool.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Temporairement, vous pouvez lancer le binaire manuellement pour voir si ça fonctionne correctement :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/usr/local/bin/pve_exporter /usr/share/pve_exporter/pve_exporter.yml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si tout s’est bien passé, on va maintenant créer un script de démarrage &lt;em&gt;systemd&lt;/em&gt; pour que notre exporter se démarre tout seul avec l’hyperviseur :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;gt; /etc/systemd/system/pve_exporter.service &amp;lt;&amp;lt; EOF
[Unit]
Description=Proxmox VE Prometheus Exporter
After=network.target
Wants=network.target
[Service]
Restart=on-failure
WorkingDirectory=/usr/share/pve_exporter
ExecStart=/usr/local/bin/pve_exporter /usr/share/pve_exporter/pve_exporter.yml 9221 192.168.1.1
[Install]
WantedBy=multi-user.target
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Note : remplacer 192.168.1.1 par l’adresse IP de votre serveur Proxmox VE (aussi accessible par votre serveur Prometheus)&lt;/em&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;systemctl daemon-reload
systemctl enable pve_exporter
systemctl start pve_exporter
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="la-collecte"&gt;La collecte
&lt;/h2&gt;&lt;p&gt;On a maintenant un endpoint au format OpenMetrics qui peut être collecté par Prometheus. Cool !!&lt;/p&gt;
&lt;p&gt;Le but du jeu va être maintenant d’informer Prometheus qu’il doit scrapper notre &lt;em&gt;exporter&lt;/em&gt;. On va faire ça en ajoutant la configuration suivante à notre serveur Prometheus (puis le redémarrer) :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;vi /usr/share/prometheus/prometheus.yml
[...]
scrape_configs:
[...]
- job_name: &amp;#39;pve&amp;#39;
static_configs:
- targets:
- 192.168.1.1:9221 # Proxmox VE node with PVE exporter.
- 192.168.1.2:9221 # Proxmox VE node with PVE exporter.
metrics_path: /pve
params:
module: [default]
systemctl restart prometheus.service
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Note : remplacer les IPs par les adresses IP de vos exporters sur vos serveurs PVE.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="visualiser-tout-ça"&gt;Visualiser tout ça
&lt;/h2&gt;&lt;p&gt;Dernière étape avant d’aller prendre un café, afficher tout ça dans un dashboard. Là ça aurait pu être trivial mais j’ai du bidouiller (un tout petit peu).&lt;/p&gt;
&lt;p&gt;Je l’ai dis au début de l’article, un des avantages de cet &lt;em&gt;exporter&lt;/em&gt;, c’est que quelqu’un a pris la peine de faire un dashboard dans Grafana qui affiche déjà tout sans qu’on ait besoin de faire quoique ce soit.&lt;/p&gt;
&lt;p&gt;On peut donc l’installer juste en copiant l’URL ou l’ID dans notre Grafana &lt;a class="link" href="https://grafana.com/grafana/dashboards/10347" target="_blank" rel="noopener"
&gt;10347&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_add_dashboard.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_add_dashboard2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Trivial !&lt;/p&gt;
&lt;p&gt;La seule petite difficulté, c’est que ce Dashboard gère mal le clustering. Plus particulièrement, il n’aime pas qu’un meme exporter remonte les données de plusieurs nodes, ce qui est dommage pour un cluster.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_add_dashboard_ko.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;J’ai donc tweaké le Dashboard en y ajoutant une variable &amp;ldquo;node&amp;rdquo;, permettant de sélectionner les métriques du node qu’on veut (uniquement).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/04/proxmox_grafana_variable.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Enfin, j&amp;rsquo;ai modifié les graphiques concernés en ajoutant un filtre de type &lt;code&gt;id=&amp;quot;node/$node&amp;quot;&lt;/code&gt; utilisant cette variable dans la requête PromQL.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/12/grafana_add_node_in_promql.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Vous avez maintenant un Dashboard qui remonte les métriques de vos serveurs, stockages, vms et containers dans Proxmox VE ! A vous l’observabilité !&lt;/p&gt;
&lt;h2 id="sources"&gt;Sources
&lt;/h2&gt;&lt;p&gt;Une autre implémentation : &lt;a class="link" href="https://github.com/wakeful/pve_exporter" target="_blank" rel="noopener"
&gt;wakeful/pve_exporter&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[Tutoriel] Installer Prometheus/Grafana sans Docker</title><link>https://blog.zwindler.fr/2019/11/12/tutoriel-installer-prometheus-grafana-sans-docker/</link><pubDate>Tue, 12 Nov 2019 07:30:45 +0000</pubDate><guid>https://blog.zwindler.fr/2019/11/12/tutoriel-installer-prometheus-grafana-sans-docker/</guid><description>&lt;img src="https://blog.zwindler.fr/2019/11/grafana_prometheus_proxmox.webp" alt="Featured image of post [Tutoriel] Installer Prometheus/Grafana sans Docker" /&gt;&lt;h2 id="prometheus-et-grafana-dans-docker-quelle-horreur-"&gt;Prometheus et Grafana dans Docker, quelle horreur ?
&lt;/h2&gt;&lt;p&gt;Je sais que certains d’entre vous ne sont pas super fan (euphémisme) de la technologique containers Docker (et je ne parle même pas de Kubernetes, cf &lt;a class="link" href="https://blog.zwindler.fr/2019/09/03/concerning-kubernetes-combien-de-problemes-ces-stacks-ont-generes/" &gt;Concerning Kubernetes&lt;/a&gt;). Pour autant, pas besoin de Docker pour avoir besoin du couple Prometheus / Grafana.&lt;/p&gt;
&lt;p&gt;Prometheus a plein de features sympas (notamment l’auto discovery, le langage de requêtage PromQL, &amp;hellip;). De son côté, Grafana est vraiment top pour ce qui est visualisation rapide provenant de plusieurs sources de données.&lt;/p&gt;
&lt;p&gt;Peut être même que vous avez du Docker (ou même Kubernetes) mais que vous n’avez pas envie d’intégrer la supervision dans votre infra de compute.&lt;/p&gt;
&lt;p&gt;Il y a plein de bonnes raisons pour ça, comme ne pas vouloir héberger la supervision sur l’infra qu’elle est censé surveillée ou encore pour des problématiques de performances, &amp;hellip;&lt;/p&gt;
&lt;p&gt;Avec Docker, lancer Prometheus ou Grafana se fait en une ligne de commande, c’est pour ça qu’on voit cette manière de faire partout. Sans Docker, c’est nécessairement un poil plus compliqué (mais à peine) à faire. Et c’est pourquoi je fais ce petit tuto rapide.&lt;/p&gt;
&lt;h2 id="prometheus"&gt;Prometheus
&lt;/h2&gt;&lt;p&gt;Dans ce tuto, on va partir des sources. Pour &lt;a class="link" href="https://prometheus.io/download/" target="_blank" rel="noopener"
&gt;Prometheus&lt;/a&gt;, vous pourrez trouver un raccourci vers la dernière version &lt;a class="link" href="https://prometheus.io/download/" target="_blank" rel="noopener"
&gt;sur le site officiel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On télécharge cette version et on configure un utilisateur exécuter Prometheus&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;wget https://github.com/prometheus/prometheus/releases/download/v2.13.1/prometheus-2.13.1.linux-amd64.tar.gz
tar xzf prometheus-2.13.1.linux-amd64.tar.gz
sudo mv prometheus-2.13.1.linux-amd64/ /usr/share/prometheus
sudo useradd -u 3434 -d /usr/share/prometheus -s /bin/false prometheus
sudo mkdir -p /var/lib/prometheus/data
sudo chown prometheus:prometheus /var/lib/prometheus/data
sudo chown -R prometheus:prometheus /usr/share/prometheus
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Une fois que c’est fait, le mieux c’est de tester que Prometheus &amp;ldquo;fonctionne&amp;rdquo; correctement en le lançant à la main pour voir si le logiciel se lance bien, avec la configuration par défaut.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/usr/share/prometheus/prometheus --config.file=/usr/share/prometheus/prometheus.yml
[...]
level=info ts=2019-09-20T14:56:18.244Z caller=main.go:768 msg=&amp;#34;Completed loading of configuration file&amp;#34; filename=/usr/share/prometheus/prometheus.yml
level=info ts=2019-09-20T14:56:18.244Z caller=main.go:623 msg=&amp;#34;Server is ready to receive web requests.&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ici tout s’est bien passé, on peut donc le couper (Ctrl-C) et créer un script SystemD pour pouvoir le démarrer automatiquement avec le serveur.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo vi /etc/systemd/system/prometheus.service
[Unit]
Description=Prometheus Server
Documentation=https://prometheus.io/docs/introduction/overview/
After=network-online.target
[Service]
User=prometheus
Restart=on-failure
WorkingDirectory=/usr/share/prometheus
ExecStart=/usr/share/prometheus/prometheus --config.file=/usr/share/prometheus/prometheus.yml
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable prometheus
sudo systemctl start prometheus
sudo systemctl status prometheus
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="grafana"&gt;Grafana
&lt;/h2&gt;&lt;p&gt;Maintenant que c’est fait, on passe à Grafana. Vous allez voir, ça va aussi vite.&lt;/p&gt;
&lt;p&gt;Dans le cas de Grafana, &lt;a class="link" href="https://grafana.com/grafana/download" target="_blank" rel="noopener"
&gt;la méthode mise en avant sur le site officiel&lt;/a&gt; est l’utilisation des packages systèmes (&amp;quot;.deb&amp;quot; pour Debian ou Ubuntu, RPM pour CentOS). Par souci de cohérence dans l’article, je ne vais pas utiliser le .deb et installer le binaire précompilé pour l’installer de la même manière que Prometheus. Cependant, le .deb aurait très bien fait l’affaire (et ça ira plus vite si vous êtes pressés).&lt;/p&gt;
&lt;p&gt;On télécharge donc la version précompilée, on positionne les bons dossiers/binaires/fichiers de config aux bons endroits.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;wget https://dl.grafana.com/oss/release/grafana-6.4.4.linux-amd64.tar.gz
tar -xzf grafana-6.4.4.linux-amd64.tar.gz
sudo useradd -d /usr/share/grafana -s /bin/false grafana
sudo mkdir -p /var/lib/grafana/plugins /etc/grafana /var/log/grafana
sudo chown -R grafana:grafana /var/lib/grafana
sudo mv grafana-6.4.4/ /usr/share/grafana
sudo cp /usr/share/grafana/bin/grafana-server /usr/sbin/
sudo cp /usr/share/grafana/conf/sample.ini /etc/grafana/grafana.ini
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On configure systemD puis on démarre le service.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo vi /etc/default/grafana-server
GRAFANA_USER=grafana
GRAFANA_GROUP=grafana
GRAFANA_HOME=/usr/share/grafana
LOG_DIR=/var/log/grafana
DATA_DIR=/var/lib/grafana
MAX_OPEN_FILES=10000
CONF_DIR=/etc/grafana
CONF_FILE=/etc/grafana/grafana.ini
RESTART_ON_UPGRADE=true
PLUGINS_DIR=/var/lib/grafana/plugins
PROVISIONING_CFG_DIR=/etc/grafana/provisioning
PID_FILE_DIR=/var/run/grafana
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;sudo vi /etc/systemd/system/multi-user.target.wants/grafana-server.service
[Unit]
Description=Grafana instance
Documentation=http://docs.grafana.org
Wants=network-online.target
After=network-online.target
After=postgresql.service mariadb.service mysql.service
[Service]
EnvironmentFile=/etc/default/grafana-server
User=grafana
Group=grafana
Type=simple
Restart=on-failure
WorkingDirectory=/usr/share/grafana
RuntimeDirectory=grafana
RuntimeDirectoryMode=0750
ExecStart=/usr/sbin/grafana-server \
--config=${CONF_FILE} \
--pidfile=${PID_FILE_DIR}/grafana-server.pid \
cfg:default.paths.logs=${LOG_DIR} \
cfg:default.paths.data=${DATA_DIR} \
cfg:default.paths.plugins=${PLUGINS_DIR} \
cfg:default.paths.provisioning=${PROVISIONING_CFG_DIR}
LimitNOFILE=10000
TimeoutStopSec=20
UMask=0027
[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;systemctl start grafana-server
systemctl enable grafana-server
systemctl status grafana-server
[...]
Nov 10 15:40:17 nostromo grafana-server[14606]: t=2019-11-10T15:40:17+0000 lvl=info msg=&amp;#34;Initializing Stream Manager&amp;#34;
Nov 10 15:40:17 nostromo grafana-server[14606]: t=2019-11-10T15:40:17+0000 lvl=info msg=&amp;#34;HTTP Server Listen&amp;#34; logger=http.server address=0.0.0.0:3000 protocol
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="on-cable-le-tout-ensemble"&gt;On cable le tout ensemble
&lt;/h2&gt;&lt;p&gt;Vous avez vu, je vous avais pas menti, c’est assez simple en fait.&lt;/p&gt;
&lt;p&gt;Maintenant que Prometheus et Grafana tournent, on va les coufigurer pour qu’ils parlent ensemble.&lt;/p&gt;
&lt;p&gt;Tout se passe sur l’interface d’administration de Grafana, qui devrait maintenant être accessible à l’URL http://@IP_de_votre_serveur:3000&lt;/p&gt;
&lt;p&gt;Authentifiez vous en tant qu’administrateur. Par défaut à la première instanciation, seul un compte &amp;ldquo;admin&amp;rdquo; est créé, avec le mot de passe hautement sécurisé &amp;ldquo;admin&amp;rdquo;. Heureusement on change ça tout de suite&amp;hellip;&lt;/p&gt;
&lt;p&gt;La dernière étape consiste à simplement se rendre dans la partie administration de Grafana, puis de créer un source de données.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/11/grafana_data_source.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Il existe de nombreuses sources de données différentes. Nous dans notre cas, c’est bien une source de type Prometheus qu’on veut créer.&lt;/p&gt;
&lt;p&gt;Renseignez simplement l’URL d’accès à Prometheus (par défaut http://localhost:9090 dans ce tutoriel) et sauvez.&lt;/p&gt;
&lt;p&gt;A partir de maintenant, vous avez un couple Prometheus / Grafana fonctionnel. Vous allez pouvoir commencer à créer des Dashboard.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2019/11/grafana_prometheus_proxmox.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Enjoy !&lt;/p&gt;</description></item><item><title>CNCF Bdx #6 : les slides de mon talk Thanos</title><link>https://blog.zwindler.fr/2019/10/24/cncf-bdx-6-les-slides-de-mon-talk-thanos/</link><pubDate>Thu, 24 Oct 2019 17:00:10 +0000</pubDate><guid>https://blog.zwindler.fr/2019/10/24/cncf-bdx-6-les-slides-de-mon-talk-thanos/</guid><description>&lt;img src="https://blog.zwindler.fr/2019/10/cncfbdx_thanos.webp" alt="Featured image of post CNCF Bdx #6 : les slides de mon talk Thanos" /&gt;&lt;p&gt;Ce soir, je donne un talk sur Thanos au CNCF Meetup de Bordeaux. Comme d’habitude, je met à disposition les slides quelques minutes avant. &lt;a class="link" href="https://www.meetup.com/fr-FR/Cloud-Native-Computing-Bordeaux/events/265657289" target="_blank" rel="noopener"
&gt;[Le lien du Meetup pour les curieux]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Besoin de métriques Prometheus à long terme ? Thanos fera des Marvels !&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Prometheus, aussi puissant soit il, repose sur plusieurs postulats qui ne collent pas avec tous les cas d’usage. Les métriques doivent être stockées sur un medium local et rapide, il faut un serveur par zone (failure domain) et donc potentiellement un grand nombre de serveurs Prometheus indépendants, difficiles à corréler, …&lt;/p&gt;
&lt;p&gt;Arrive alors Thanos (rien à voir avec le bonhomme violet avec un gant doré) !&lt;/p&gt;
&lt;p&gt;Celui ci va nous permettre de stocker nos métriques infiniment, tout en les rassemblant au sein d’une même source de données et en améliorant la performance de nos requêtes les plus coûteuses.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="les-slides-les-slides-"&gt;Les slides, les slides !
&lt;/h2&gt;&lt;p&gt;Et voilà les slides :-D&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.zwindler.fr/2019/10/CNCF_meetup6_Thanos.pdf" &gt;CNCF_meetup6_Thanos.pdf&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="le-podcast-le-podcast-"&gt;Le podcast, le podcast !
&lt;/h2&gt;&lt;p&gt;Si je n’oublie pas de lancer l’enregistrement, je mettrais aussi un fichier audio de la conf, en mode podcast :-p.&lt;/p&gt;</description></item><item><title>CNCF Meetup Bordeaux #6 : Tour d’horizon du monitoring dans Kubernetes</title><link>https://blog.zwindler.fr/2019/10/14/cncf-meetup-bordeaux-6-tour-dhorizon-du-monitoring-dans-kubernetes/</link><pubDate>Mon, 14 Oct 2019 15:30:18 +0000</pubDate><guid>https://blog.zwindler.fr/2019/10/14/cncf-meetup-bordeaux-6-tour-dhorizon-du-monitoring-dans-kubernetes/</guid><description>&lt;img src="https://blog.zwindler.fr/2019/10/cncfbdx_thanos.webp" alt="Featured image of post CNCF Meetup Bordeaux #6 : Tour d’horizon du monitoring dans Kubernetes" /&gt;&lt;h2 id="cncf-meetup-bordeaux"&gt;CNCF Meetup Bordeaux
&lt;/h2&gt;&lt;p&gt;Et rebelotte !&lt;/p&gt;
&lt;p&gt;Je récidive et vais de nouveau venir vous raconter comment je travaille au CNCF Meetup de Bordeaux (pour rappel, vous pouvez retrouver &lt;a class="link" href="https://blog.zwindler.fr/2019/01/28/cncf-meetup-bordeaux-3-rex-kubernetes-et-chaos-engineering/" &gt;les slides de mon passage précédent, dans lequel j’avais fais un REX des incidents qu’on a eu sur Kubernetes&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Pour cette 6ème édition, ça se passera le 24 octobre à partir de 19h00 dans les locaux de « Le Wagon » à Bordeaux.&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.meetup.com/fr-FR/Cloud-Native-Computing-Bordeaux/events/258351142/?rv=ea1_v2&amp;amp;_xtd=gatlbWFpbF9jbGlja9oAJDI3YTAzNzNhLWY2YmEtNDdjMy1hN2QwLWEyYWVhZjllZjc0OQ" target="_blank" rel="noopener"
&gt;&lt;/a&gt;&lt;a class="link" href="https://www.meetup.com/fr-FR/Cloud-Native-Computing-Bordeaux/events/265657289" target="_blank" rel="noopener"
&gt;Le lien vers le meetup et l’inscription&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Si vous êtes du coin et que vous êtes de passage et que vous voulez échanger avec vos pairs sur les solutions open sources de containérisation et autres sujets ayant trait au cloud, c’est « the place to be ».&lt;/p&gt;
&lt;p&gt;Comme d’habitude, attention car les places partent très vite. Généralement, en 2 jours c’est plié&amp;hellip;&lt;/p&gt;
&lt;h2 id="cncf-"&gt;CNCF ?
&lt;/h2&gt;&lt;p&gt;Pour rappel, &lt;a class="link" href="https://www.cncf.io/" target="_blank" rel="noopener"
&gt;la Cloud Native Computing Foundation&lt;/a&gt;, c’est la fondation « spin-off » de la Linux Foundation qui a été créée pour fédérer, piloter, organiser l’ensemble des projets open source ayant trait aux containers, aux microservices et aux services clouds.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Cloud Native Computing Foundation builds sustainable ecosystems and fostersa community around a constellation of high-quality projects that orchestrate containers as part of a microservices architecture.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Elle a été créée lorsque Google a légué le code de Kubernetes en 2015.&lt;/p&gt;
&lt;h2 id="le-programme"&gt;Le programme
&lt;/h2&gt;&lt;p&gt;A 19H15, Etienne Coutaud, le co organisateur, nous fera son traditionnel « tour des news de l’écosystème CNCF ».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1 Monitorer mon cluster Kubernetes (quasiment) sans les mains.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A 19h30, Etienne embraye sur la supervision avec Prometheus dans Kubernetes&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Il est impensable de mettre une plateforme en production sans monitoring, ceci est aussi vrai pour du Kubernetes managé ou non. Kubernetes est conçu pour s’intégrer parfaitement avec un autre produit phare de la CNCF Prometheus. Nous verrons durant ce talk comment mettre en œuvre les deux, comment cela s’architecture et comment l’opérer. Nous verrons également comment cette architecture est faite pour nativement accueillir les métriques issus de votre propre code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;#2 Besoin de métriques Prometheus à long terme ? Thanos fera des Marvels !&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Et ensuite, c’est mon tour. J’irai un peu plus loin avec Prometheus en vous parlant de Thanos.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Prometheus, aussi puissant soit il, repose sur plusieurs postulats qui ne collent pas avec tous les cas d’usage. Les métriques doivent être stockées sur un medium local et rapide, il faut un serveur par zone (failure domain) et donc potentiellement un grand nombre de serveurs Prometheus indépendants, difficiles à corréler, … Arrive alors Thanos (rien à voir avec le bonhomme violet avec un gant doré) ! Celui ci va nous permettre de stocker nos métriques infiniment, tout en les rassemblant au sein d’une même source de données et en améliorant la performance de nos requêtes les plus coûteuses.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lier l’utile à l’agréable&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A 21h, nous nous retrouverons pour échanger autour d’une bière et d’une part de pizza offert par Gekko (Merci à eux :-D).&lt;/p&gt;</description></item></channel></rss>