Pré-requis

  • Un cluster GKE up and running
  • Connaissance de base de Kubernetes et GitOps
  • ArgoCD installé et configuré

Étapes

1. Qu’est ce qu’on va installer ?

OutilDescription
PrometheusSystè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.
Kube State MetricsService Kubernetes qui expose l’état des objets du cluster (pods, deployments, nodes…) sous forme de métriques consommables par Prometheus.
GrafanaPlateforme de visualisation qui permet de créer des dashboards interactifs à partir de sources de données comme Prometheus.
AlertmanagerComposant de l’écosystème Prometheus qui gère le routage, le regroupement et l’envoi des alertes vers des canaux de notification (Slack, e-mail, PagerDuty…).
LokiSystème d’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.
AlloyAgent 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.

1. Installation de la kube-prometheus-stack (Prometheus + Grafana + Alertmanager)

Si vous avez suivi l’article précédent, rien de plus simple : il suffit d’ajouter une nouvelle application dans apps/ dans notre repo de CD.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: kube-prometheus-stack
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://prometheus-community.github.io/helm-charts
    chart: kube-prometheus-stack
    targetRevision: 86.0.1
    helm:
      releaseName: kube-prometheus-stack
      valueFiles: []
      values: |
        grafana:
          enabled: true
          adminPassword: admin
          service:
            type: ClusterIP
        prometheus:
          prometheusSpec:
            retention: 7d
            resources:
              requests:
                cpu: 200m
                memory: 512Mi
              limits:
                memory: 2Gi
            storageSpec: {}
        alertmanager:
          enabled: true
        kubeStateMetrics:
          enabled: true
        nodeExporter:
          enabled: true
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true

On push ce fichier kube-prometheus-stack.yaml et Argo se charge de déployer la stack de monitoring dans notre cluster.

Après quelques minutes d’attente, vous devriez voir les pods de Prometheus, Grafana et Alertmanager en cours d’exécution dans le namespace monitoring :

kubectl get pods -n monitoring
NAME                                                        READY   STATUS    RESTARTS   AGE
alertmanager-kube-prometheus-stack-alertmanager-0           2/2     Running   0          2m30s
kube-prometheus-stack-admission-create-ljf79                0/1     Pending   0          41s
kube-prometheus-stack-grafana-6ddb85bf55-j5shg              3/3     Running   0          2m35s
kube-prometheus-stack-kube-state-metrics-5fc57bf8f9-vhfhq   1/1     Running   0          2m35s
kube-prometheus-stack-operator-585c4957f7-2r772             1/1     Running   0          2m35s
prometheus-kube-prometheus-stack-prometheus-0               2/2     Running   0          2m30s
---

Grafana est désormais accessible via un port-forwarding :

kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:80

Rendez-vous sur http://localhost:3000 et connectez-vous avec les identifiants admin/admin.

Cliquez ensuite sur “Dashboards” pour voir la liste des dashboards disponibles par défaut avec la chart : Dashboards Grafana

3. Collecte des Logs avec Loki

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.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: loki
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://grafana.github.io/helm-charts
    chart: loki
    targetRevision: 7.0.0
    helm:
      releaseName: loki
      values: |
        deploymentMode: SingleBinary
        loki:
          auth_enabled: false
          commonConfig:
            replication_factor: 1
          storage:
            type: filesystem
          schemaConfig:
            configs:
              - from: "2024-01-01"
                store: tsdb
                object_store: filesystem
                schema: v13
                index:
                  prefix: index_
                  period: 24h
        singleBinary:
          replicas: 1
          persistence:
            size: 10Gi
        read:
          replicas: 0
        write:
          replicas: 0
        backend:
          replicas: 0
        gateway:
          enabled: true
        chunksCache:
          enabled: false
        resultsCache:
          enabled: false
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true

Enfin il faut indiquer à Grafana où trouver Loki pour pouvoir visualiser les logs dans notre dashboard.

Pour cela, on ajoute une datasource Loki dans Grafana en utilisant un ConfigMap Kubernetes :

spec:
  source:
    helm:
      values: |
        grafana:
          additionalDataSources:
            - name: Loki
              type: loki
              access: proxy
              url: http://loki-gateway.monitoring.svc.cluster.local
              jsonData:
                maxLines: 1000

Et voilà le résultat :

Logs loki

4. Collecte des logs de notre application

Pour l’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’agit ici encore d’ajouter une nouvelle application ArgoCD dans notre repo de CD :

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: alloy
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://grafana.github.io/helm-charts
    chart: alloy
    targetRevision: 1.16.1
    helm:
      releaseName: alloy
      values: |
        alloy:
          configMap:
            content: |
              discovery.kubernetes "pods" {
                role = "pod"
              }

              discovery.relabel "pods" {
                targets = discovery.kubernetes.pods.targets

                rule {
                  source_labels = ["__meta_kubernetes_namespace"]
                  target_label  = "namespace"
                }
                rule {
                  source_labels = ["__meta_kubernetes_pod_name"]
                  target_label  = "pod"
                }
                rule {
                  source_labels = ["__meta_kubernetes_pod_container_name"]
                  target_label  = "container"
                }
                rule {
                  source_labels = ["__meta_kubernetes_pod_label_app"]
                  target_label  = "app"
                }
              }

              loki.source.kubernetes "pods" {
                targets    = discovery.relabel.pods.output
                forward_to = [loki.write.default.receiver]
              }

              loki.write "default" {
                endpoint {
                  url = "http://loki-gateway.monitoring.svc.cluster.local/loki/api/v1/push"
                }
              }
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

La configuration utilise la syntaxe River d’Alloy pour :

  • Découvrir tous les pods Kubernetes
  • Extraire les labels namespace, pod, container et app
  • Envoyer les logs vers votre Loki gateway
  • Alloy sera déployé comme DaemonSet et collectera les logs de votre nginx. Dans Grafana, vous pourrez les consulter avec :

{namespace=“demo”, app=“nginx”}

De retour sur Grafana, la liste des filtres disponibles est désormais bien plus fournie : Filtres Loki

Logs Loki


Résultat

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.

Si vous avez suivi toutes les étapes de cet article vous devriez avoir les workloads suivantes :

kubectl get pods -n monitoring
NAME                                                        READY   STATUS    RESTARTS   AGE
alertmanager-kube-prometheus-stack-alertmanager-0           2/2     Running   0          21m
alloy-jb2nf                                                 2/2     Running   0          5m22s
kube-prometheus-stack-grafana-bf74d765f-4hzlt               3/3     Running   0          23m
kube-prometheus-stack-kube-state-metrics-6b747b7c5f-hjjwd   1/1     Running   0          23m
kube-prometheus-stack-operator-59c5d9f8c-q6phj              1/1     Running   0          23m
kube-prometheus-stack-prometheus-node-exporter-zhmfp        1/1     Running   0          23m
loki-0                                                      2/2     Running   0          32m
loki-canary-55ccd5d799-wkc7t                                1/1     Running   0          32m
loki-gateway-6df7c96bc9-l92d2                               1/1     Running   0          32m
prometheus-kube-prometheus-stack-prometheus-0               2/2     Running   0          21m
kubectl get pods -n demo
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7489fb554f-hffjv   1/1     Running   0          33m

L’essentiel des travaux est disponible sur mon repo GitHub

Ce qui vient ensuite

Nous verrons comment exposer notre application à travers la Gateway API dans le prochain article de la série, stay tuned !


Sources :