<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Prometheus on Guillaume Delré</title><link>https://guillaumedelre.github.io/fr/tags/prometheus/</link><description>Recent content in Prometheus on Guillaume Delré</description><generator>Hugo</generator><language>fr-FR</language><lastBuildDate>Sat, 07 Jun 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://guillaumedelre.github.io/fr/tags/prometheus/index.xml" rel="self" type="application/rss+xml"/><item><title>Observabilité sur des conteneurs FrankenPHP avant que la migration cloud soit finie</title><link>https://guillaumedelre.github.io/fr/2025/06/07/observabilit%C3%A9-sur-des-conteneurs-frankenphp-avant-que-la-migration-cloud-soit-finie/</link><pubDate>Sat, 07 Jun 2025 00:00:00 +0000</pubDate><guid>https://guillaumedelre.github.io/fr/2025/06/07/observabilit%C3%A9-sur-des-conteneurs-frankenphp-avant-que-la-migration-cloud-soit-finie/</guid><description>Déplacer 14 microservices PHP vers le cloud impliquait d&amp;#39;avoir de l&amp;#39;observabilité avant que la migration soit finie, pas après. La couche Caddy de FrankenPHP l&amp;#39;a rendu possible avec deux lignes de config.</description><content:encoded><![CDATA[<p>Quand on fait tourner des workloads on-premise, on peut s&rsquo;en sortir avec presque aucune observabilité. On a SSH. On a <code>top</code>. On a quelqu&rsquo;un qui sait que le service d&rsquo;authentification monte toujours le lundi matin. La connaissance institutionnelle se substitue à l&rsquo;instrumentation, et personne ne budgète le temps pour la remplacer.</p>
<p>Puis on migre vers le cloud. La connaissance institutionnelle ne suit pas. L&rsquo;accès SSH est parti ou peu pratique. Et pour la première fois, on se retrouve à fixer quatorze conteneurs FrankenPHP sans la moindre idée de ce qu&rsquo;ils font réellement.</p>
<p>C&rsquo;est le moment où on a besoin de métriques. Pas éventuellement. Avant que la migration soit terminée.</p>
<h2 id="le-problème-à-le-faire-correctement">Le problème à le faire correctement</h2>
<p>La bonne façon d&rsquo;instrumenter un service PHP pour Prometheus : ajouter une bibliothèque client, écrire des compteurs et histogrammes autour de ce qui importe, exposer une route <code>/metrics</code>, mettre à jour la config de scrape. Pour un seul service, c&rsquo;est un après-midi raisonnable. Pour quatorze services en pleine migration, c&rsquo;est un projet de plusieurs sprints qui entre en compétition avec tout le reste qui doit bouger.</p>
<p>Le calcul est gênant. On a besoin de métriques pour avoir confiance que la migration se passe bien. Mais ajouter des métriques à tout avant la migration signifie que la migration prend plus longtemps. Et plus elle prend longtemps, plus on a besoin de métriques pour savoir où on en est.</p>
<p>Il fallait bien que quelque chose cède.</p>
<h2 id="ce-que-frankenphp-embarque-sans-lannoncer">Ce que FrankenPHP embarque sans l&rsquo;annoncer</h2>
<p>FrankenPHP n&rsquo;est pas un runtime PHP qui utilise <a href="https://caddyserver.com" target="_blank" rel="noopener noreferrer">Caddy</a> comme serveur web. La relation est inversée : Caddy est le serveur, et PHP est un module Caddy. Chaque requête HTTP passe par Caddy avant d&rsquo;atteindre le code applicatif.</p>
<p>Caddy embarque un endpoint compatible Prometheus intégré. Pas de plugin, pas de binaire supplémentaire. Activer l&rsquo;admin API et il est là.</p>
<p><code>CADDY_GLOBAL_OPTIONS</code> est une variable d&rsquo;environnement FrankenPHP qui injecte des directives directement dans le bloc de configuration global de Caddy. Deux lignes suffisent :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">CADDY_GLOBAL_OPTIONS</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        admin 0.0.0.0:2019
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        metrics</span>
</span></span></code></pre></div><p><code>admin 0.0.0.0:2019</code> lie l&rsquo;admin API à toutes les interfaces réseau — le défaut est localhost uniquement, inaccessible depuis un conteneur Prometheus sur le même réseau. <code>metrics</code> active l&rsquo;endpoint.</p>
<p>Après ça, chaque conteneur répond à <code>GET :2019/metrics</code> avec un payload Prometheus complet. Comptes de requêtes labellisés par code de statut, histogrammes de latence, connexions actives. Aucune route ajoutée à l&rsquo;application. Aucun <code>composer require</code>. Aucun changement au Dockerfile.</p>
<p>Une variable d&rsquo;environnement, ajoutée à chaque définition de service dans un seul commit. Quatorze cibles de scrape, toutes produisant des données.</p>
<h2 id="une-image-utilisable-dans-grafana">Une image utilisable dans Grafana</h2>
<p>La config de scrape Prometheus liste chaque service par son nom de conteneur :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">scrape_configs</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">job_name</span>: <span style="color:#ae81ff">caddy</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">metrics_path</span>: <span style="color:#ae81ff">/metrics</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">static_configs</span>:
</span></span><span style="display:flex;"><span>          - <span style="color:#f92672">targets</span>:
</span></span><span style="display:flex;"><span>              - <span style="color:#ae81ff">authentication:2019</span>
</span></span><span style="display:flex;"><span>              - <span style="color:#ae81ff">content:2019</span>
</span></span><span style="display:flex;"><span>              - <span style="color:#ae81ff">media:2019</span>
</span></span><span style="display:flex;"><span>              <span style="color:#75715e"># les 14 services</span>
</span></span></code></pre></div><p>Grafana se pose au-dessus de Prometheus. Le dashboard communautaire Caddy donne les taux de requêtes, les taux d&rsquo;erreur et les percentiles de latence par service, par endpoint, par code de statut. En moins d&rsquo;une journée après que la migration a atterri dans le nouvel environnement, il y avait quelque chose de significatif à regarder.</p>
<p>La couche données suit la même logique : des exporters pour PostgreSQL, Redis et RabbitMQ scrappent au niveau infrastructure sans toucher le code applicatif. Des dashboards communautaires existent pour tous.</p>
<h2 id="ce-que-cette-baseline-couvre-réellement">Ce que cette baseline couvre réellement</h2>
<p>Les métriques HTTP de Caddy sont des métriques de serveur web, pas des métriques applicatives. Elles répondent à : est-ce que ce service reçoit du trafic, est-ce qu&rsquo;il retourne des erreurs, à quelle vitesse répond-il. Le genre de questions qu&rsquo;on pose quand quelque chose est cassé et qu&rsquo;on doit trier dans le noir.</p>
<p>Elles ne répondent pas à : combien d&rsquo;éléments ont été traités aujourd&rsquo;hui, quel job en arrière-plan est bloqué, quel est l&rsquo;impact business de ce pic de latence. Pour ça, il faut de l&rsquo;instrumentation applicative, et ce travail existe encore quand on a des choses spécifiques à mesurer.</p>
<p>Mais dans un contexte de migration, cette distinction compte moins qu&rsquo;elle n&rsquo;en a l&rsquo;air. Les choses qui cassent pendant une migration cloud sont principalement des problèmes d&rsquo;infrastructure : un service qui ne peut pas atteindre sa base de données, une limite mémoire définie trop bas, un consumer de queue qui a arrêté de traiter les messages. Ce sont exactement les choses que la baseline couvre.</p>
<p>Avoir l&rsquo;instrumentation parfaite pour les événements au niveau business peut attendre que la plateforme soit stable. Avoir assez de visibilité pour savoir si la migration a réussi ne peut pas.</p>
]]></content:encoded></item></channel></rss>