In mijn vorige post over Prometheus en Thanos behandelde ik de sidecar architectuur — Thanos Sidecar draait naast Prometheus, uploadt TSDB blocks naar object storage, en stelt data beschikbaar aan de Querier. Het werkt uitstekend voor clusters met stabiele connectiviteit naar je centrale infrastructuur.

Maar wat als je clusters aan de edge staan? Als ze uren of dagen connectiviteit kunnen verliezen? Als je tientallen of honderden kleine clusters draait en geen sidecar complexiteit op elk daarvan wilt?

Daar komt Thanos Receive om de hoek kijken. Push in plaats van pull.

Het Probleem met Sidecars op Schaal

Het sidecar model vereist:

  1. Thanos Sidecar draaiend op elke Prometheus instance
  2. Directe object storage toegang vanaf elk cluster
  3. Stabiele netwerkconnectiviteit voor block uploads
  4. gRPC connectiviteit naar de centrale Querier voor real-time queries

Voor een handvol clusters in hetzelfde datacenter is dit prima. Maar overweeg:

  • Edge locaties met intermitterende internetconnectiviteit
  • Air-gapped omgevingen die alleen outbound kunnen pushen
  • Honderden kleine clusters waar sidecar overhead optelt
  • Multi-tenant platforms waar je niet alle clusters beheert

Het sidecar model werkt niet meer. Je hebt iets simpelers nodig.

Maak Kennis met Thanos Receive

Thanos Receive draait het model om. In plaats van sidecars die data uit Prometheus halen, pusht Prometheus metrics direct naar een centrale Receive component.

flowchart TD
    subgraph edge["Edge Clusters"]
        subgraph E1["Site A (Fabriek)"]
            P1["Prometheus"]
        end
        subgraph E2["Site B (Magazijn)"]
            P2["Prometheus"]
        end
        subgraph E3["Site C (Retail)"]
            P3["Prometheus"]
        end
    end

    subgraph central["Centraal Cluster"]
        R["Thanos Receive<br/>(HA cluster)"]
        Q["Thanos Querier"]
        SG["Store Gateway"]
        C["Compactor"]
        OS["Object Storage"]
    end

    P1 -->|"remote_write"| R
    P2 -->|"remote_write"| R
    P3 -->|"remote_write"| R

    R --> OS
    OS --> SG
    SG --> Q
    R --> Q
    OS --> C

    Q --> G["Grafana"]

Het kernpunt: Prometheus heeft al remote_write. Het is een ingebouwde feature die samples pusht naar elk compatibel endpoint. Thanos Receive implementeert deze API.

Waarom Push Beter is voor Edge

1. Simpelere Edge Deployment

Geen sidecar. Geen object storage credentials aan de edge. Geen gRPC poorten om te exposen. Alleen Prometheus met een remote_write URL.

# De HELE edge configuratie
global:
  external_labels:
    cluster: factory-site-a
    region: europe-west

remote_write:
  - url: https://thanos-receive.central.example.com/api/v1/receive
    bearer_token_file: /etc/prometheus/token

Dat is alles. Het edge cluster hoeft niets te weten over object storage, Thanos componenten of iets anders. Het pusht gewoon metrics.

2. Tolereert Connectiviteitsverlies

Als connectiviteit wegvalt, buffert Prometheus samples lokaal. Als connectiviteit terugkeert, haalt het in. De Write-Ahead Log (WAL) regelt dit automatisch.

remote_write:
  - url: https://thanos-receive.central.example.com/api/v1/receive
    queue_config:
      capacity: 100000        # Buffer grootte
      max_shards: 50          # Parallelle send workers
      min_shards: 1
      max_samples_per_send: 5000
      batch_send_deadline: 30s
      min_backoff: 1s
      max_backoff: 5m         # Exponential backoff bij failure

Ik heb edge clusters gezien die 4+ uur connectiviteit verloren en succesvol inhaalden toen het netwerk terugkwam. De WAL hield alles veilig.

3. Alleen Outbound Connectiviteit

Edge locaties hebben vaak restrictieve firewalls. Inbound connecties? Geblokkeerd. VPNs? Nachtmerrie om te onderhouden. Maar outbound HTTPS naar een bekend endpoint? Meestal toegestaan.

Push architectuur sluit aan bij hoe edge netwerken daadwerkelijk werken.

4. Lager Resource Gebruik aan Edge

Geen sidecar betekent:

  • Minder geheugen op edge nodes
  • Geen extra container om te beheren
  • Geen gRPC connecties om te onderhouden
  • Simpelere failure modes

Voor resource-beperkte edge devices maakt dit uit.

Thanos Receive Opzetten

Centraal Cluster: Receive Deployment

Thanos Receive is stateful — het schrijft naar disk voordat het upload naar object storage. Draai het als StatefulSet:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: thanos-receive
  namespace: monitoring
spec:
  serviceName: thanos-receive
  replicas: 3
  selector:
    matchLabels:
      app: thanos-receive
  template:
    metadata:
      labels:
        app: thanos-receive
    spec:
      containers:
        - name: thanos-receive
          image: quay.io/thanos/thanos:v0.34.0
          args:
            - receive
            - --http-address=0.0.0.0:10902
            - --grpc-address=0.0.0.0:10901
            - --remote-write.address=0.0.0.0:19291
            - --tsdb.path=/var/thanos/receive
            - --objstore.config-file=/etc/thanos/objstore.yaml
            - --label=receive_replica="$(POD_NAME)"
            - --tsdb.retention=6h
            # Hashring voor HA distributie
            - --receive.hashrings-file=/etc/thanos/hashring.json
            - --receive.local-endpoint=$(POD_NAME).thanos-receive.monitoring.svc:10901
          ports:
            - name: http
              containerPort: 10902
            - name: grpc
              containerPort: 10901
            - name: remote-write
              containerPort: 19291
          volumeMounts:
            - name: data
              mountPath: /var/thanos/receive
            - name: objstore-config
              mountPath: /etc/thanos
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
      volumes:
        - name: objstore-config
          secret:
            secretName: thanos-objstore-secret
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        storageClassName: longhorn
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 50Gi

Hashring voor High Availability

Bij meerdere Receive replicas heb je een hashring nodig om inkomende data te distribueren:

[
  {
    "endpoints": [
      "thanos-receive-0.thanos-receive.monitoring.svc:10901",
      "thanos-receive-1.thanos-receive.monitoring.svc:10901",
      "thanos-receive-2.thanos-receive.monitoring.svc:10901"
    ]
  }
]

Sla dit op in een ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: thanos-receive-hashring
  namespace: monitoring
data:
  hashring.json: |
    [
      {
        "endpoints": [
          "thanos-receive-0.thanos-receive.monitoring.svc:10901",
          "thanos-receive-1.thanos-receive.monitoring.svc:10901",
          "thanos-receive-2.thanos-receive.monitoring.svc:10901"
        ]
      }
    ]

De hashring zorgt dat samples van dezelfde time series altijd naar dezelfde Receive instance gaan, wat duplicaten voorkomt.

Load Balancer Service

Expose Receive voor externe clusters:

apiVersion: v1
kind: Service
metadata:
  name: thanos-receive-lb
  namespace: monitoring
spec:
  type: LoadBalancer
  ports:
    - name: remote-write
      port: 443
      targetPort: 19291
  selector:
    app: thanos-receive
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: thanos-receive
  namespace: monitoring
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
  tls:
    - hosts:
        - thanos-receive.example.com
      secretName: thanos-receive-tls
  rules:
    - host: thanos-receive.example.com
      http:
        paths:
          - path: /api/v1/receive
            pathType: Prefix
            backend:
              service:
                name: thanos-receive
                port:
                  number: 19291

Edge Cluster: Prometheus Configuratie

Op elk edge cluster, configureer Prometheus om metrics te pushen:

apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  name: prometheus
  namespace: monitoring
spec:
  replicas: 1
  retention: 24h  # Lokale retentie voor edge queries

  externalLabels:
    cluster: factory-site-a
    region: europe-west
    environment: production

  remoteWrite:
    - url: https://thanos-receive.example.com/api/v1/receive
      bearerTokenSecret:
        name: thanos-remote-write-token
        key: token
      queueConfig:
        capacity: 50000
        maxShards: 20
        minShards: 1
        maxSamplesPerSend: 2000
        batchSendDeadline: 30s
        minBackoff: 1s
        maxBackoff: 5m
      writeRelabelConfigs:
        # Drop high-cardinality metrics die je centraal niet nodig hebt
        - sourceLabels: [__name__]
          regex: 'go_.*'
          action: drop

Belangrijk: Zet zinvolle externalLabels. Deze identificeren van welk cluster de metrics komen. Zonder kan je data van verschillende sites niet onderscheiden.

Authenticatie en Beveiliging

Expose nooit Thanos Receive zonder authenticatie. Opties:

Bearer Token (Simpel)

Genereer een token en deel het met edge clusters:

# Genereer token
openssl rand -hex 32 > receive-token.txt

# Maak secret in centraal cluster
kubectl create secret generic thanos-receive-auth \
  --from-file=token=receive-token.txt \
  -n monitoring

# Maak secret in edge cluster
kubectl create secret generic thanos-remote-write-token \
  --from-file=token=receive-token.txt \
  -n monitoring

Configureer Receive om tokens te valideren:

# Voeg toe aan Receive container args
- --receive.tenant-header=THANOS-TENANT
- --receive.default-tenant-id=anonymous

mTLS (Veiliger)

Voor omgevingen die sterkere authenticatie vereisen:

# Receive args
- --grpc-server-tls-cert=/etc/tls/server.crt
- --grpc-server-tls-key=/etc/tls/server.key
- --grpc-server-tls-client-ca=/etc/tls/ca.crt

# Edge Prometheus remoteWrite
remoteWrite:
  - url: https://thanos-receive.example.com/api/v1/receive
    tlsConfig:
      certFile: /etc/prometheus/tls/client.crt
      keyFile: /etc/prometheus/tls/client.key
      caFile: /etc/prometheus/tls/ca.crt

Multi-Tenancy

Thanos Receive ondersteunt multi-tenancy via de tenant header:

# Edge cluster A
remoteWrite:
  - url: https://thanos-receive.example.com/api/v1/receive
    headers:
      THANOS-TENANT: tenant-a

# Edge cluster B
remoteWrite:
  - url: https://thanos-receive.example.com/api/v1/receive
    headers:
      THANOS-TENANT: tenant-b

Data wordt opgeslagen met het tenant label, wat isolatie in queries mogelijk maakt:

# Query alleen tenant-a data
http_requests_total{tenant_id="tenant-a"}

Dit is handig wanneer verschillende teams of klanten dezelfde Receive infrastructuur delen.

Omgaan met Intermitterende Connectiviteit

De killer feature voor edge: graceful degradation wanneer connectiviteit faalt.

Prometheus WAL Buffering

Prometheus buffert niet-verzonden samples in zijn Write-Ahead Log. Configureer voor je connectiviteitspatronen:

remoteWrite:
  - url: https://thanos-receive.example.com/api/v1/receive
    queueConfig:
      capacity: 100000       # Samples om te bufferen
      maxShards: 30          # Parallelle senders bij inhalen
      maxSamplesPerSend: 5000
      batchSendDeadline: 60s
      minBackoff: 1s
      maxBackoff: 10m        # Niet hameren als het down is

Voor een typisch edge cluster dat elke 30s scraped:

  • 100k sample buffer ≈ 3-4 uur metrics
  • Pas aan op basis van je scrape interval en aantal targets

Monitor Remote Write Health

Op het edge cluster, alert op remote write failures:

- alert: PrometheusRemoteWriteFailing
  expr: |
    rate(prometheus_remote_storage_failed_samples_total[5m]) > 0
  for: 15m
  labels:
    severity: warning
  annotations:
    summary: "Prometheus remote write faalt"
    description: "Edge cluster {{ $labels.cluster }} faalt met verzenden metrics"

Centrale Monitoring van Edge Health

Op het centrale cluster, detecteer stille edges:

- alert: EdgeClusterMissing
  expr: |
    absent_over_time(up{job="prometheus", cluster=~"edge-.*"}[1h])
  for: 30m
  labels:
    severity: critical
  annotations:
    summary: "Edge cluster rapporteert niet"
    description: "Geen metrics van {{ $labels.cluster }} voor 1 uur"

Sidecar vs Receive: Wanneer Welke Gebruiken

AspectSidecarReceive
Edge/offline ondersteuningSlechtUitstekend
Real-time queriesJa (via gRPC)Ja (via Receive gRPC)
Resources aan edgeHogerLager
Object storage toegangVereist aan edgeAlleen centraal
Netwerk richtingOutbound + inboundAlleen outbound
Complexiteit aan edgeHogerLager
Block upload latency2h (block grootte)Real-time

Gebruik Sidecar wanneer:

  • Alle clusters stabiele connectiviteit hebben
  • Je minimale centrale infrastructuur wilt
  • Real-time queries over alle clusters belangrijk zijn

Gebruik Receive wanneer:

  • Edge clusters intermitterende connectiviteit hebben
  • Je schaalt naar veel (50+) clusters
  • Edge resources beperkt zijn
  • Alleen outbound firewall regels gelden

Hybride aanpak:

  • Sidecar voor core/stabiele clusters
  • Receive voor edge/remote clusters
  • Beide voeden dezelfde Querier en object storage

Mijn Productie Setup

Ik draai een hybride model:

# Centraal infrastructuur cluster: Sidecar
# (stabiele connectiviteit, heeft real-time queries nodig)
prometheus:
  thanos:
    enabled: true
    objectStorageConfig:
      name: thanos-objstore

# Edge manufacturing sites: Remote Write
# (intermitterende connectiviteit, resource beperkt)
prometheus:
  remoteWrite:
    - url: https://thanos-receive.central:443/api/v1/receive
      bearerTokenSecret:
        name: edge-token
      queueConfig:
        capacity: 150000  # 6+ uur buffer
        maxBackoff: 15m

# Alles voedt dezelfde Thanos Query
thanos:
  query:
    stores:
      - dnssrv+_grpc._tcp.prometheus-operated.monitoring.svc  # Sidecars
      - dnssrv+_grpc._tcp.thanos-receive.monitoring.svc        # Receive
      - dnssrv+_grpc._tcp.thanos-store.monitoring.svc          # Historisch

Edge sites kunnen uren connectiviteit verliezen. Als ze reconnecten, worden metrics automatisch ingehaald. De centrale Grafana dashboards tonen het volledige beeld, ongeacht welke architectuur de data leverde.

Waarom Dit Ertoe Doet

Monitoring is niet optioneel. Je moet zien wat er gebeurt over al je clusters — niet alleen degene met perfecte connectiviteit.

Het push model met Thanos Receive geeft je:

  • Resilience: Edge clusters overleven connectiviteitsverlies
  • Simpelheid: Geen sidecars, geen object storage creds aan edge
  • Schaalbaarheid: Centraliseer complexiteit, houd edges simpel
  • Flexibiliteit: Mix sidecar en receive naar behoefte

Dit is hoe je observability bouwt die werkt in de echte wereld, waar netwerken falen en edge locaties bestaan.


Pull werkt als alles connected is. Push werkt als de realiteit tussenbeide komt. Goede architecturen kunnen beide aan.