<?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>Monitoring on Valérian Pyckaert</title>
    <link>https://valerian-pyckaert.dev/tags/monitoring/</link>
    <description>Recent content in Monitoring on Valérian Pyckaert</description>
    <image>
      <title>Valérian Pyckaert</title>
      <url>https://valerian-pyckaert.dev/images/default-cover.svg</url>
      <link>https://valerian-pyckaert.dev/images/default-cover.svg</link>
    </image>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Sun, 31 May 2026 09:35:18 +0200</lastBuildDate>
    <atom:link href="https://valerian-pyckaert.dev/tags/monitoring/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>TheForge #3 — Monitoring Kubernetes avec Prometheus, Grafana et Loki</title>
      <link>https://valerian-pyckaert.dev/posts/the-forge-monitoring/</link>
      <pubDate>Sun, 31 May 2026 09:35:18 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/the-forge-monitoring/</guid>
      <description>Installation d&amp;#39;une stack de monitoring complète sur Kubernetes avec Prometheus, Grafana et Loki.</description>
      <content:encoded><![CDATA[<hr>
<h2 id="pré-requis">Pré-requis</h2>
<ul>
<li>Un cluster GKE up and running</li>
<li>Connaissance de base de Kubernetes et GitOps</li>
<li>ArgoCD installé et configuré</li>
</ul>
<hr>
<h2 id="étapes">Étapes</h2>
<h3 id="1-quest-ce-quon-va-installer-">1. Qu&rsquo;est ce qu&rsquo;on va installer ?</h3>
<table>
  <thead>
      <tr>
          <th>Outil</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Prometheus</td>
          <td>Système de surveillance open-source qui collecte et stocke des métriques sous forme de séries temporelles en interrogeant périodiquement des endpoints HTTP.</td>
      </tr>
      <tr>
          <td>Kube State Metrics</td>
          <td>Service Kubernetes qui expose l&rsquo;état des objets du cluster (pods, deployments, nodes…) sous forme de métriques consommables par Prometheus.</td>
      </tr>
      <tr>
          <td>Grafana</td>
          <td>Plateforme de visualisation qui permet de créer des dashboards interactifs à partir de sources de données comme Prometheus.</td>
      </tr>
      <tr>
          <td>Alertmanager</td>
          <td>Composant de l&rsquo;écosystème Prometheus qui gère le routage, le regroupement et l&rsquo;envoi des alertes vers des canaux de notification (Slack, e-mail, PagerDuty…).</td>
      </tr>
      <tr>
          <td>Loki</td>
          <td>Système d&rsquo;agrégation de logs inspiré de Prometheus, conçu pour indexer uniquement les métadonnées des logs afin de réduire les coûts de stockage.</td>
      </tr>
      <tr>
          <td>Alloy</td>
          <td>Agent de collecte de données de Grafana Labs, successeur de Grafana Agent, capable de collecter métriques, logs et traces pour les acheminer vers différents backends.</td>
      </tr>
  </tbody>
</table>
<h3 id="1-installation-de-la-kube-prometheus-stack-prometheus--grafana--alertmanager">1. Installation de la kube-prometheus-stack (Prometheus + Grafana + Alertmanager)</h3>
<p>Si vous avez suivi l&rsquo;article précédent, rien de plus simple : il suffit d&rsquo;ajouter une nouvelle application dans <code>apps/</code> dans notre repo de CD.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">argoproj.io/v1alpha1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Application</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">kube-prometheus-stack</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">argocd</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">finalizers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">resources-finalizer.argocd.argoproj.io</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">project</span><span class="p">:</span><span class="w"> </span><span class="l">default</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">source</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">repoURL</span><span class="p">:</span><span class="w"> </span><span class="l">https://prometheus-community.github.io/helm-charts</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">chart</span><span class="p">:</span><span class="w"> </span><span class="l">kube-prometheus-stack</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">targetRevision</span><span class="p">:</span><span class="w"> </span><span class="m">86.0.1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">helm</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">releaseName</span><span class="p">:</span><span class="w"> </span><span class="l">kube-prometheus-stack</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">valueFiles</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">values</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">        grafana:
</span></span></span><span class="line"><span class="cl"><span class="sd">          enabled: true
</span></span></span><span class="line"><span class="cl"><span class="sd">          adminPassword: admin
</span></span></span><span class="line"><span class="cl"><span class="sd">          service:
</span></span></span><span class="line"><span class="cl"><span class="sd">            type: ClusterIP
</span></span></span><span class="line"><span class="cl"><span class="sd">        prometheus:
</span></span></span><span class="line"><span class="cl"><span class="sd">          prometheusSpec:
</span></span></span><span class="line"><span class="cl"><span class="sd">            retention: 7d
</span></span></span><span class="line"><span class="cl"><span class="sd">            resources:
</span></span></span><span class="line"><span class="cl"><span class="sd">              requests:
</span></span></span><span class="line"><span class="cl"><span class="sd">                cpu: 200m
</span></span></span><span class="line"><span class="cl"><span class="sd">                memory: 512Mi
</span></span></span><span class="line"><span class="cl"><span class="sd">              limits:
</span></span></span><span class="line"><span class="cl"><span class="sd">                memory: 2Gi
</span></span></span><span class="line"><span class="cl"><span class="sd">            storageSpec: {}
</span></span></span><span class="line"><span class="cl"><span class="sd">        alertmanager:
</span></span></span><span class="line"><span class="cl"><span class="sd">          enabled: true
</span></span></span><span class="line"><span class="cl"><span class="sd">        kubeStateMetrics:
</span></span></span><span class="line"><span class="cl"><span class="sd">          enabled: true
</span></span></span><span class="line"><span class="cl"><span class="sd">        nodeExporter:
</span></span></span><span class="line"><span class="cl"><span class="sd">          enabled: true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">destination</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">server</span><span class="p">:</span><span class="w"> </span><span class="l">https://kubernetes.default.svc</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">monitoring</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">syncPolicy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">automated</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">prune</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">selfHeal</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">syncOptions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">CreateNamespace=true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">ServerSideApply=true</span><span class="w">
</span></span></span></code></pre></div><p>On push ce fichier <code>kube-prometheus-stack.yaml</code> et Argo se charge de déployer la stack de monitoring dans notre cluster.</p>
<p>Après quelques minutes d&rsquo;attente, vous devriez voir les pods de Prometheus, Grafana et Alertmanager en cours d&rsquo;exécution dans le namespace <code>monitoring</code> :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl get pods -n monitoring
</span></span><span class="line"><span class="cl">NAME                                                        READY   STATUS    RESTARTS   AGE
</span></span><span class="line"><span class="cl">alertmanager-kube-prometheus-stack-alertmanager-0           2/2     Running   <span class="m">0</span>          2m30s
</span></span><span class="line"><span class="cl">kube-prometheus-stack-admission-create-ljf79                0/1     Pending   <span class="m">0</span>          41s
</span></span><span class="line"><span class="cl">kube-prometheus-stack-grafana-6ddb85bf55-j5shg              3/3     Running   <span class="m">0</span>          2m35s
</span></span><span class="line"><span class="cl">kube-prometheus-stack-kube-state-metrics-5fc57bf8f9-vhfhq   1/1     Running   <span class="m">0</span>          2m35s
</span></span><span class="line"><span class="cl">kube-prometheus-stack-operator-585c4957f7-2r772             1/1     Running   <span class="m">0</span>          2m35s
</span></span><span class="line"><span class="cl">prometheus-kube-prometheus-stack-prometheus-0               2/2     Running   <span class="m">0</span>          2m30s
</span></span><span class="line"><span class="cl">---
</span></span></code></pre></div><p>Grafana est désormais accessible via un port-forwarding :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:80
</span></span></code></pre></div><p>Rendez-vous sur <code>http://localhost:3000</code> et connectez-vous avec les identifiants <code>admin/admin</code>.</p>
<p>Cliquez ensuite sur &ldquo;Dashboards&rdquo; pour voir la liste des dashboards disponibles par défaut avec la chart :
<img alt="Dashboards Grafana" loading="lazy" src="/dashboard-grafana.png"></p>
<h3 id="3-collecte-des-logs-avec-loki">3. Collecte des Logs avec Loki</h3>
<p>Là encore il suffit de créer une nouvelle application ArgoCD qui pointe vers le chart Helm de Loki pour déployer un stack de collecte de logs dans notre cluster.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">argoproj.io/v1alpha1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Application</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">loki</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">argocd</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">finalizers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">resources-finalizer.argocd.argoproj.io</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">project</span><span class="p">:</span><span class="w"> </span><span class="l">default</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">source</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">repoURL</span><span class="p">:</span><span class="w"> </span><span class="l">https://grafana.github.io/helm-charts</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">chart</span><span class="p">:</span><span class="w"> </span><span class="l">loki</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">targetRevision</span><span class="p">:</span><span class="w"> </span><span class="m">7.0.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">helm</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">releaseName</span><span class="p">:</span><span class="w"> </span><span class="l">loki</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">values</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">        deploymentMode: SingleBinary
</span></span></span><span class="line"><span class="cl"><span class="sd">        loki:
</span></span></span><span class="line"><span class="cl"><span class="sd">          auth_enabled: false
</span></span></span><span class="line"><span class="cl"><span class="sd">          commonConfig:
</span></span></span><span class="line"><span class="cl"><span class="sd">            replication_factor: 1
</span></span></span><span class="line"><span class="cl"><span class="sd">          storage:
</span></span></span><span class="line"><span class="cl"><span class="sd">            type: filesystem
</span></span></span><span class="line"><span class="cl"><span class="sd">          schemaConfig:
</span></span></span><span class="line"><span class="cl"><span class="sd">            configs:
</span></span></span><span class="line"><span class="cl"><span class="sd">              - from: &#34;2024-01-01&#34;
</span></span></span><span class="line"><span class="cl"><span class="sd">                store: tsdb
</span></span></span><span class="line"><span class="cl"><span class="sd">                object_store: filesystem
</span></span></span><span class="line"><span class="cl"><span class="sd">                schema: v13
</span></span></span><span class="line"><span class="cl"><span class="sd">                index:
</span></span></span><span class="line"><span class="cl"><span class="sd">                  prefix: index_
</span></span></span><span class="line"><span class="cl"><span class="sd">                  period: 24h
</span></span></span><span class="line"><span class="cl"><span class="sd">        singleBinary:
</span></span></span><span class="line"><span class="cl"><span class="sd">          replicas: 1
</span></span></span><span class="line"><span class="cl"><span class="sd">          persistence:
</span></span></span><span class="line"><span class="cl"><span class="sd">            size: 10Gi
</span></span></span><span class="line"><span class="cl"><span class="sd">        read:
</span></span></span><span class="line"><span class="cl"><span class="sd">          replicas: 0
</span></span></span><span class="line"><span class="cl"><span class="sd">        write:
</span></span></span><span class="line"><span class="cl"><span class="sd">          replicas: 0
</span></span></span><span class="line"><span class="cl"><span class="sd">        backend:
</span></span></span><span class="line"><span class="cl"><span class="sd">          replicas: 0
</span></span></span><span class="line"><span class="cl"><span class="sd">        gateway:
</span></span></span><span class="line"><span class="cl"><span class="sd">          enabled: true
</span></span></span><span class="line"><span class="cl"><span class="sd">        chunksCache:
</span></span></span><span class="line"><span class="cl"><span class="sd">          enabled: false
</span></span></span><span class="line"><span class="cl"><span class="sd">        resultsCache:
</span></span></span><span class="line"><span class="cl"><span class="sd">          enabled: false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">destination</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">server</span><span class="p">:</span><span class="w"> </span><span class="l">https://kubernetes.default.svc</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">monitoring</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">syncPolicy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">automated</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">prune</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">selfHeal</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">syncOptions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">CreateNamespace=true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">ServerSideApply=true</span><span class="w">
</span></span></span></code></pre></div><p>Enfin il faut indiquer à Grafana où trouver Loki pour pouvoir visualiser les logs dans notre dashboard.</p>
<p>Pour cela, on ajoute une datasource Loki dans Grafana en utilisant un ConfigMap Kubernetes :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">source</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">helm</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">values</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">        grafana:
</span></span></span><span class="line"><span class="cl"><span class="sd">          additionalDataSources:
</span></span></span><span class="line"><span class="cl"><span class="sd">            - name: Loki
</span></span></span><span class="line"><span class="cl"><span class="sd">              type: loki
</span></span></span><span class="line"><span class="cl"><span class="sd">              access: proxy
</span></span></span><span class="line"><span class="cl"><span class="sd">              url: http://loki-gateway.monitoring.svc.cluster.local
</span></span></span><span class="line"><span class="cl"><span class="sd">              jsonData:
</span></span></span><span class="line"><span class="cl"><span class="sd">                maxLines: 1000</span><span class="w">
</span></span></span></code></pre></div><p>Et voilà le résultat :</p>
<p><img alt="Logs loki" loading="lazy" src="/loki.png"></p>
<h3 id="4-collecte-des-logs-de-notre-application">4. Collecte des logs de notre application</h3>
<p>Pour l&rsquo;heure, les logs de notre application nginx ne sont pas collectés par Loki.
Nous allons déployer Alloy en tant que DaemonSet dans notre cluster pour collecter les logs de tous les pods et les envoyer à Loki, il s&rsquo;agit ici encore d&rsquo;ajouter une nouvelle application ArgoCD dans notre repo de CD :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">argoproj.io/v1alpha1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Application</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">alloy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">argocd</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">finalizers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">resources-finalizer.argocd.argoproj.io</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">project</span><span class="p">:</span><span class="w"> </span><span class="l">default</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">source</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">repoURL</span><span class="p">:</span><span class="w"> </span><span class="l">https://grafana.github.io/helm-charts</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">chart</span><span class="p">:</span><span class="w"> </span><span class="l">alloy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">targetRevision</span><span class="p">:</span><span class="w"> </span><span class="m">1.16.1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">helm</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">releaseName</span><span class="p">:</span><span class="w"> </span><span class="l">alloy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">values</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">        alloy:
</span></span></span><span class="line"><span class="cl"><span class="sd">          configMap:
</span></span></span><span class="line"><span class="cl"><span class="sd">            content: |
</span></span></span><span class="line"><span class="cl"><span class="sd">              discovery.kubernetes &#34;pods&#34; {
</span></span></span><span class="line"><span class="cl"><span class="sd">                role = &#34;pod&#34;
</span></span></span><span class="line"><span class="cl"><span class="sd">              }
</span></span></span><span class="line"><span class="cl"><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">              discovery.relabel &#34;pods&#34; {
</span></span></span><span class="line"><span class="cl"><span class="sd">                targets = discovery.kubernetes.pods.targets
</span></span></span><span class="line"><span class="cl"><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">                rule {
</span></span></span><span class="line"><span class="cl"><span class="sd">                  source_labels = [&#34;__meta_kubernetes_namespace&#34;]
</span></span></span><span class="line"><span class="cl"><span class="sd">                  target_label  = &#34;namespace&#34;
</span></span></span><span class="line"><span class="cl"><span class="sd">                }
</span></span></span><span class="line"><span class="cl"><span class="sd">                rule {
</span></span></span><span class="line"><span class="cl"><span class="sd">                  source_labels = [&#34;__meta_kubernetes_pod_name&#34;]
</span></span></span><span class="line"><span class="cl"><span class="sd">                  target_label  = &#34;pod&#34;
</span></span></span><span class="line"><span class="cl"><span class="sd">                }
</span></span></span><span class="line"><span class="cl"><span class="sd">                rule {
</span></span></span><span class="line"><span class="cl"><span class="sd">                  source_labels = [&#34;__meta_kubernetes_pod_container_name&#34;]
</span></span></span><span class="line"><span class="cl"><span class="sd">                  target_label  = &#34;container&#34;
</span></span></span><span class="line"><span class="cl"><span class="sd">                }
</span></span></span><span class="line"><span class="cl"><span class="sd">                rule {
</span></span></span><span class="line"><span class="cl"><span class="sd">                  source_labels = [&#34;__meta_kubernetes_pod_label_app&#34;]
</span></span></span><span class="line"><span class="cl"><span class="sd">                  target_label  = &#34;app&#34;
</span></span></span><span class="line"><span class="cl"><span class="sd">                }
</span></span></span><span class="line"><span class="cl"><span class="sd">              }
</span></span></span><span class="line"><span class="cl"><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">              loki.source.kubernetes &#34;pods&#34; {
</span></span></span><span class="line"><span class="cl"><span class="sd">                targets    = discovery.relabel.pods.output
</span></span></span><span class="line"><span class="cl"><span class="sd">                forward_to = [loki.write.default.receiver]
</span></span></span><span class="line"><span class="cl"><span class="sd">              }
</span></span></span><span class="line"><span class="cl"><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">              loki.write &#34;default&#34; {
</span></span></span><span class="line"><span class="cl"><span class="sd">                endpoint {
</span></span></span><span class="line"><span class="cl"><span class="sd">                  url = &#34;http://loki-gateway.monitoring.svc.cluster.local/loki/api/v1/push&#34;
</span></span></span><span class="line"><span class="cl"><span class="sd">                }
</span></span></span><span class="line"><span class="cl"><span class="sd">              }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">destination</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">server</span><span class="p">:</span><span class="w"> </span><span class="l">https://kubernetes.default.svc</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">monitoring</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">syncPolicy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">automated</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">prune</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">selfHeal</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">syncOptions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">CreateNamespace=true</span><span class="w">
</span></span></span></code></pre></div><p>La configuration utilise la syntaxe River d&rsquo;Alloy pour :</p>
<ul>
<li>Découvrir tous les pods Kubernetes</li>
<li>Extraire les labels namespace, pod, container et app</li>
<li>Envoyer les logs vers votre Loki gateway</li>
<li>Alloy sera déployé comme DaemonSet et collectera les logs de votre nginx. Dans Grafana, vous pourrez les consulter avec :</li>
</ul>
<blockquote>
<p>{namespace=&ldquo;demo&rdquo;, app=&ldquo;nginx&rdquo;}</p>
</blockquote>
<p>De retour sur Grafana, la liste des filtres disponibles est désormais bien plus fournie :
<img alt="Filtres Loki" loading="lazy" src="/filtres-loki.png"></p>
<p><img alt="Logs Loki" loading="lazy" src="/logs-loki.png"></p>
<hr>
<h2 id="résultat">Résultat</h2>
<p>Dans cet article nous avons vu comment installer une stack de monitoring complète sur Kubernetes avec Prometheus, Grafana et Loki, le tout déployé en GitOps via ArgoCD.
Nous avons également vu comment collecter les logs de nos pods sur notre cluster avec Alloy et les visualiser dans Grafana.</p>
<p>Si vous avez suivi toutes les étapes de cet article vous devriez avoir les workloads suivantes :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl get pods -n monitoring
</span></span><span class="line"><span class="cl">NAME                                                        READY   STATUS    RESTARTS   AGE
</span></span><span class="line"><span class="cl">alertmanager-kube-prometheus-stack-alertmanager-0           2/2     Running   <span class="m">0</span>          21m
</span></span><span class="line"><span class="cl">alloy-jb2nf                                                 2/2     Running   <span class="m">0</span>          5m22s
</span></span><span class="line"><span class="cl">kube-prometheus-stack-grafana-bf74d765f-4hzlt               3/3     Running   <span class="m">0</span>          23m
</span></span><span class="line"><span class="cl">kube-prometheus-stack-kube-state-metrics-6b747b7c5f-hjjwd   1/1     Running   <span class="m">0</span>          23m
</span></span><span class="line"><span class="cl">kube-prometheus-stack-operator-59c5d9f8c-q6phj              1/1     Running   <span class="m">0</span>          23m
</span></span><span class="line"><span class="cl">kube-prometheus-stack-prometheus-node-exporter-zhmfp        1/1     Running   <span class="m">0</span>          23m
</span></span><span class="line"><span class="cl">loki-0                                                      2/2     Running   <span class="m">0</span>          32m
</span></span><span class="line"><span class="cl">loki-canary-55ccd5d799-wkc7t                                1/1     Running   <span class="m">0</span>          32m
</span></span><span class="line"><span class="cl">loki-gateway-6df7c96bc9-l92d2                               1/1     Running   <span class="m">0</span>          32m
</span></span><span class="line"><span class="cl">prometheus-kube-prometheus-stack-prometheus-0               2/2     Running   <span class="m">0</span>          21m
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl get pods -n demo
</span></span><span class="line"><span class="cl">NAME                     READY   STATUS    RESTARTS   AGE
</span></span><span class="line"><span class="cl">nginx-7489fb554f-hffjv   1/1     Running   <span class="m">0</span>          33m
</span></span></code></pre></div><hr>
<p>L&rsquo;essentiel des travaux est disponible sur <a href="https://github.com/Bernedotcom2312/theforge-cd">mon repo GitHub</a></p>
<h2 id="ce-qui-vient-ensuite">Ce qui vient ensuite</h2>
<p>Nous verrons comment exposer notre application à travers la Gateway API dans le prochain article de la série, stay tuned !</p>
<hr>
<p><strong>Sources :</strong></p>
<ul>
<li><a href="https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack">kube-prometheus-stack Helm Chart</a></li>
<li><a href="https://github.com/grafana/helm-charts/tree/main/charts/loki">Loki Helm Chart</a></li>
<li><a href="https://github.com/grafana/alloy/blob/main/operations/helm/charts/alloy/README.md">Alloy Helm Chart</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>The Forge Project</title>
      <link>https://valerian-pyckaert.dev/posts/the-forge-project/</link>
      <pubDate>Fri, 22 May 2026 08:00:00 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/the-forge-project/</guid>
      <description>Projet fil rouge : construire une plateforme Kubernetes complète sur GCP, from scratch, avec les outils indispensables en 2026. Chaque article documente une étape, les obstacles rencontrés et comment je les ai résolus.</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>Stack</strong> : GCP · GKE · Terraform · Helm · ArgoCD · SOPS · Kube-Prom-Stack · Nginx Gateway Fabric · cert-manager</p>
</blockquote>
<hr>
<h2 id="pourquoi-ce-projet-">Pourquoi ce projet ?</h2>
<p>Je me lance en freelance DevOps / Platform Engineer / Cloud Engineer. Pour montrer ce que je sais faire (et documenter ce que j&rsquo;apprends en chemin), je démarre un projet fil rouge public : construire une plateforme Kubernetes complète sur GCP, from scratch, avec les outils que j&rsquo;estime indispensables en 2026.</p>
<p>Chaque article de la série documente <strong>une étape</strong>, les <strong>obstacles rencontrés</strong> et comment je les ai résolus. Format court, orienté pratique.</p>
<p>Je vais tenter de garder une approche pragmatique orientée &ldquo;best practices&rdquo; (mais pas dogmatique) pour que ce soit utile à d&rsquo;autres personnes qui veulent se lancer dans la même aventure.</p>
<hr>
<h2 id="ce-quon-va-construire">Ce qu&rsquo;on va construire</h2>
<p>Un cluster GKE avec la stack suivante, déployée en GitOps :</p>
<table>
  <thead>
      <tr>
          <th>Composant</th>
          <th>Rôle</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Terraform</strong></td>
          <td>Provisionning du cluster et bootstrap</td>
      </tr>
      <tr>
          <td><strong>Helm + ArgoCD</strong></td>
          <td>GitOps, tout passe par là après le bootstrap</td>
      </tr>
      <tr>
          <td><strong>SOPS</strong></td>
          <td>Gestion des secrets chiffrés dans Git</td>
      </tr>
      <tr>
          <td><strong>kube-prometheus-stack</strong></td>
          <td>Monitoring &amp; alerting (Prometheus, Grafana, Alertmanager)</td>
      </tr>
      <tr>
          <td><strong>Nginx Gateway Fabric</strong></td>
          <td>Ingress via la Gateway API</td>
      </tr>
      <tr>
          <td><strong>cert-manager + Let&rsquo;s Encrypt</strong></td>
          <td>TLS automatique</td>
      </tr>
  </tbody>
</table>
<p>Je me focalise sur ce qui me semble essentiel pour adresser la majorité des besoins.
A termes j&rsquo;envisage d&rsquo;ajouter d&rsquo;autres composants destinés à des usages plus complexes : KEDA, Karpenter, Dapr, &hellip;</p>
<hr>
<h2 id="les-étapes-prévues">Les étapes prévues</h2>
<ol>
<li><strong>Création du cluster GKE via Terraform</strong></li>
<li><strong>Bootstrap Helm &amp; ArgoCD via Terraform</strong></li>
<li><strong>Déploiement de kube-prometheus-stack</strong> via ArgoCD</li>
<li><strong>Déploiement de Nginx Gateway Fabric / Gateway API</strong> via ArgoCD</li>
<li><strong>Déploiement de cert-manager + Let&rsquo;s Encrypt</strong> via ArgoCD</li>
<li><strong>Mise en place de SOPS</strong> pour la gestion des secrets</li>
</ol>
<p><em>J&rsquo;ajouterai probablement d&rsquo;autres étapes au fur et à mesure</em>* (ex: gestion des node pools, autoscaling, etc.) selon les besoins et les obstacles rencontrés*</p>
<hr>
<h2 id="principes-de-base">Principes de base</h2>
<ul>
<li><strong>Tout dans Git</strong> — aucune modification manuelle sur le cluster après le bootstrap</li>
<li><strong>Least privilege</strong> — les SA GCP auront le minimum requis</li>
<li><strong>Les secrets ne sont jamais en clair</strong> dans le repo</li>
<li><strong>KISS</strong> — Keep It Simple Stupid. Pas de sur-optimisation, pas de microservices inutiles, pas de complexité superflue</li>
</ul>
<hr>
<h2 id="prochaine-étape">Prochaine étape</h2>
<p>→ <a href="#">Création du cluster GKE avec Terraform</a> <em>(à venir)</em></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
