Lesson  in  Kubernetes per Ingegneri — Dal Container al Cluster

Stack di Osservabilità Avanzato: Prometheus, Loki, Grafana, Thanos, Mimir e OpenTelemetry

Approfondimento sullo stack di osservabilità production-ready: Prometheus per le metriche, Loki per i log, Grafana per la visualizzazione, Thanos e Mimir per lo storage a lungo termine, e OpenTelemetry come layer di raccolta vendor-neutral.

Obiettivi

Al termine di questa lezione i partecipanti saranno in grado di:

  • Descrivere l'architettura completa dello stack LGTM (Loki, Grafana, Tempo, Mimir)
  • Configurare Loki per la raccolta log con Promtail o Grafana Alloy
  • Spiegare le differenze tra Thanos e Mimir per lo storage a lungo termine di Prometheus
  • Scegliere tra Thanos e Mimir in base ai requisiti del progetto
  • Installare e configurare l'OpenTelemetry Collector in Kubernetes
  • Usare l'auto-strumentazione OTel per raccogliere trace senza modificare il codice

Teoria

Prometheus: Riassunto Architetturale

Prometheus è il cuore delle metriche in Kubernetes. Riassunto rapido:

ComponenteRuolo
Prometheus ServerScraping pull-based, TSDB locale, valutazione regole
AlertmanagerRouting alert → Slack, PagerDuty, email, webhook
Exportersnode-exporter (host), kube-state-metrics (oggetti K8s)
ServiceMonitor/PodMonitorCRD per configurare target di scraping (Prometheus Operator)

Limiti di Prometheus standalone:

  • Storage locale → no HA (se il Pod muore, perdi la storia)
  • Retention limitata (tipicamente 15d–30d per ragioni di spazio)
  • Nessuna vista globale su più cluster
  • Nessun multi-tenancy nativo

Questi limiti portano a Thanos e Mimir.


Thanos: Scalare Prometheus con il Pattern Sidecar

Thanos estende Prometheus senza sostituirlo. Aggiunge componenti laterali che abilitano:

  • Storage a lungo termine su object storage (S3, GCS, Azure Blob)
  • Query globali su più cluster Prometheus
  • Compattazione e downsampling

Architettura

┌──────────────────────────────────────────────────┐
│                  Cluster A                        │
│  ┌────────────┐   ┌─────────────┐                │
│  │ Prometheus  │◄──│   Thanos    │──► Object      │
│  │  (TSDB)    │   │  Sidecar    │    Storage     │
│  └────────────┘   └─────────────┘    (S3/GCS)    │
└──────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────┐
│                  Cluster B                        │
│  ┌────────────┐   ┌─────────────┐                │
│  │ Prometheus  │◄──│   Thanos    │──► Object      │
│  │  (TSDB)    │   │  Sidecar    │    Storage     │
│  └────────────┘   └─────────────┘    (S3/GCS)    │
└──────────────────────────────────────────────────┘
         │                    │
         ▼                    ▼
   ┌──────────────────────────────┐
   │        Thanos Querier        │ ← vista globale
   │  (fan-out su Sidecar +      │
   │   Store Gateway)             │
   └──────────────┬───────────────┘
                  │
   ┌──────────────▼───────────────┐
   │      Thanos Store Gateway    │ ← serve dati storici
   │  (legge da object storage)   │    da object storage
   └──────────────────────────────┘
   ┌──────────────────────────────┐
   │       Thanos Compactor       │ ← compatta + downsample
   └──────────────────────────────┘

Componenti chiave:

ComponenteFunzione
SidecarGira accanto a Prometheus, carica blocchi su object storage, serve query real-time
Store GatewayServe dati storici dall'object storage
QuerierInterfaccia PromQL unificata, fan-out su sidecar + store gateway
CompactorCompatta blocchi, applica downsampling (5m, 1h), gestisce retention
Ruler (opzionale)Valuta regole e alert su dati storici

Quando scegliere Thanos:

  • Hai già Prometheus e vuoi aggiungere long-term storage gradualmente
  • Pattern sidecar = impatto minimo sull'infrastruttura esistente
  • Vuoi una vista globale su cluster multipli

Mimir: Storage Metriche Scalabile Nativamente

Grafana Mimir è un backend metriche microservizio-nativo. A differenza di Thanos (sidecar), Mimir riceve le metriche via remote write — Prometheus le invia attivamente.

Architettura

Prometheus ──remote_write──► ┌─────────────┐
                             │ Distributor  │ ← valida, partiziona
                             └──────┬───────┘
                                    │
                             ┌──────▼───────┐
                             │   Ingester   │ ← scrive in memoria + WAL
                             └──────┬───────┘
                                    │ flush
                             ┌──────▼───────┐
                             │Object Storage│ ← TSDB blocks
                             └──────┬───────┘
                                    │
                             ┌──────▼───────┐
                             │Store Gateway │ ← serve query storiche
                             └──────┬───────┘
                                    │
                             ┌──────▼───────┐
                             │   Querier    │ ← unifica ingester + store
                             └──────┬───────┘
                                    │
                             ┌──────▼───────┐
                             │  Compactor   │ ← compatta + retention
                             └──────────────┘

Differenze chiave rispetto a Thanos:

ThanosMimir
PatternSidecar accanto a PrometheusRemote write (Prometheus → Mimir)
Multi-tenancyNo nativoSì, nativo (header X-Scope-OrgID)
MigrazioneGraduale (aggiungi sidecar)Richiede configurare remote_write
HA ingestionPrometheus in HA + dedupReplicazione nell'Ingester (factor 3)
Query performanceBuona (fan-out)Ottima (query splitting, caching)
OperationallyPiù semplice inizialmentePiù componenti, ma più scalabile
CostoMeno computePiù compute, meno storage (compressione migliore)

Quando scegliere Mimir:

  • Multi-tenancy è un requisito (SaaS, team multipli)
  • Scala molto grande (milioni di serie attive)
  • Vuoi query caching e splitting nativi
  • Stai già nell'ecosistema Grafana (Loki + Tempo + Mimir = LGTM)

Configurare remote_write in Prometheus:

# values.yaml per kube-prometheus-stack
prometheus:
  prometheusSpec:
    remoteWrite:
    - url: http://mimir-distributor.monitoring:8080/api/v1/push
      headers:
        X-Scope-OrgID: team-platform

Loki: Log Aggregation per Kubernetes

Loki è il "Prometheus dei log": indicizza solo le label, non il contenuto dei log. Questo lo rende ordini di grandezza più economico di Elasticsearch per i log Kubernetes.

Architettura

Pod logs ──► Promtail/Alloy ──► ┌─────────────┐
                                │ Distributor  │
                                └──────┬───────┘
                                       │
                                ┌──────▼───────┐
                                │   Ingester   │ ← chunk in memoria
                                └──────┬───────┘
                                       │ flush
                                ┌──────▼───────┐
                                │Object Storage│ ← chunk + indice
                                └──────────────┘
                                       │
                                ┌──────▼───────┐
                                │   Querier    │ ← LogQL
                                └──────────────┘

Raccolta log — opzioni:

AgenteCaratteristiche
PromtailAgent originale di Loki, DaemonSet, semplice
Grafana AlloySostituto di Promtail (2024+), pipeline configurabili, supporta OTel
Fluent BitLeggero, plugin Loki output, adatto se già in uso

LogQL — Esempi:

# Tutti i log di un namespace
{namespace="production"}

# Filtro per contenuto
{namespace="production", app="api"} |= "error"

# Regex
{app="nginx"} |~ "status=[45]\\d\\d"

# Aggregazioni (come PromQL)
sum(rate({namespace="production"} |= "error" [5m])) by (app)

# Top 10 pod per volume di log
topk(10, sum(rate({namespace="production"}[1h])) by (pod))

Installazione con Helm:

helm repo add grafana https://grafana.github.io/helm-charts
helm repo update

# Loki in modalità simple-scalable (produzione leggera)
helm install loki grafana/loki \
  --namespace monitoring \
  --set loki.commonConfig.replication_factor=1 \
  --set loki.storage.type=filesystem

# Promtail come DaemonSet
helm install promtail grafana/promtail \
  --namespace monitoring \
  --set config.clients[0].url=http://loki-gateway.monitoring/loki/api/v1/push

Strategia label per K8s:

  • Label automatiche: namespace, pod, container, node
  • Non aggiungere label ad alta cardinalità (es. request_id, user_id)
  • Usare il filtro |= o |~ per cercare nel contenuto dei log

Grafana: Il Pannello di Controllo Unificato

Grafana è la piattaforma di visualizzazione che unifica tutte le fonti dati:

Data SourceTipo di datiQuery Language
Prometheus/MimirMetrichePromQL
LokiLogLogQL
TempoTraceTraceQL
AlertmanagerAlert attivi

Dashboard essenziali per K8s:

  • Cluster overview: CPU/RAM per nodo, Pod count, scheduling pressure
  • Namespace resources: requests vs limits vs actual per namespace
  • Pod detail: CPU/RAM/network/restart per singolo Pod
  • Node exporter: disco, rete, load average per nodo

Grafana Unified Alerting (dalla v9):

Alert Rule (PromQL/LogQL)
    │
    ▼
Contact Point (Slack, PagerDuty, Email, Webhook)
    │
    ▼
Notification Policy (routing, muting, grouping)
    │
    ▼
Silences (soppressione temporanea)

Unified alerting sostituisce sia Alertmanager di Prometheus sia il vecchio sistema alert di Grafana con un'interfaccia unica.


OpenTelemetry: Il Layer di Raccolta Vendor-Neutral

OpenTelemetry (OTel) è lo standard CNCF per la raccolta di telemetria. Non è un backend — è il collettore e il formato che alimenta i backend.

I tre segnali:

SegnaleCosa raccoglieBackend tipico
TracesPercorso della richiesta attraverso i serviziTempo, Jaeger
MetricsCounter, gauge, histogramPrometheus, Mimir
LogsMessaggi strutturatiLoki

OTel Collector: Architettura Pipeline

┌─────────────────────────────────────────────┐
│            OTel Collector                    │
│                                             │
│  Receivers ──► Processors ──► Exporters     │
│                                             │
│  otlp          batch          prometheus    │
│  prometheus     memory_limiter loki         │
│  filelog        k8sattributes  otlp/tempo   │
│  kubeletstats   filter         debug        │
└─────────────────────────────────────────────┘

Modalità di deployment in K8s:

ModalitàQuando usarla
DaemonSetRaccolta log/metriche da ogni nodo (kubelet, node-exporter)
DeploymentRaccolta centralizzata, gateway per OTLP da app
SidecarIsolamento per-Pod, più risorse ma più flessibile

OTel Operator — Auto-strumentazione:

L'operatore OpenTelemetry per Kubernetes abilita la zero-code instrumentation: inietta automaticamente le librerie OTel nei Pod tramite un webhook di ammissione.

# 1. Installa l'operatore
helm install otel-operator open-telemetry/opentelemetry-operator \
  --namespace monitoring

# 2. Configura il Collector
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
  name: otel
  namespace: monitoring
spec:
  mode: deployment
  config:
    receivers:
      otlp:
        protocols:
          grpc: {}
          http: {}
    processors:
      batch:
        send_batch_size: 1000
        timeout: 10s
      k8sattributes:
        extract:
          metadata:
          - k8s.namespace.name
          - k8s.pod.name
          - k8s.deployment.name
    exporters:
      otlp/tempo:
        endpoint: tempo.monitoring:4317
        tls:
          insecure: true
      prometheusremotewrite:
        endpoint: http://mimir-distributor.monitoring:8080/api/v1/push
      loki:
        endpoint: http://loki-gateway.monitoring/loki/api/v1/push
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: [batch, k8sattributes]
          exporters: [otlp/tempo]
        metrics:
          receivers: [otlp]
          processors: [batch]
          exporters: [prometheusremotewrite]
        logs:
          receivers: [otlp]
          processors: [batch]
          exporters: [loki]

# 3. Auto-strumentazione per Java/Python/Node.js/Go
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: auto-instrumentation
  namespace: production
spec:
  exporter:
    endpoint: http://otel-collector.monitoring:4317
  propagators:
  - tracecontext
  - baggage
  java:
    image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:latest
  python:
    image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-python:latest
  nodejs:
    image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-nodejs:latest

Per abilitare l'auto-strumentazione su un Deployment, aggiungi un'annotazione:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    metadata:
      annotations:
        instrumentation.opentelemetry.io/inject-java: "true"
        # oppure: inject-python, inject-nodejs, inject-dotnet, inject-go

Lo Stack Completo: Come Si Collega Tutto

┌─────────────────────────────────────────────────────────────────┐
│                     Applicazioni K8s                            │
│  (auto-strumentate con OTel SDK / operator annotation)          │
└────────────────────────┬────────────────────────────────────────┘
                         │ OTLP (gRPC/HTTP)
                ┌────────▼────────┐
                │  OTel Collector  │
                │  (Deployment)    │
                └──┬─────┬─────┬──┘
                   │     │     │
         ┌─────────▼┐ ┌─▼────┐ ┌▼──────────┐
         │ Prometheus│ │ Loki │ │   Tempo    │
         │ / Mimir   │ │      │ │            │
         │ (metriche)│ │(log) │ │  (trace)   │
         └─────┬─────┘ └──┬───┘ └─────┬─────┘
               │          │           │
         ┌─────▼──────────▼───────────▼─────┐
         │              Grafana              │
         │  Dashboard + Alerting unificato   │
         └──────────────────────────────────┘

Raccomandazione 2026:

Anche se usi Prometheus per le metriche e Loki per i log, metti un OTel Collector davanti. Ottieni: vendor choice futura, auto-strumentazione zero-code, un unico punto per filtrare e arricchire i dati prima che raggiungano i backend.


Risorse