Skip to content
Blog/Blog

Building a Resilient, Multi-Cluster Kubernetes Observability Stack with Thanos, Loki, and Grafana

A resilient Kubernetes monitoring architecture relying on decoupling short-term scrape buffers from long-term object storage.

Taufiq Permana SumarnaTaufiq Permana Sumarna

Building a Resilient Kubernetes Observability Stack Header

A resilient Kubernetes monitoring architecture relies on decoupling short-term local scrape buffers from long-term object storage. By combining kube-prometheus-stack, Thanos, Loki, Alloy, and Grafana, you establish a horizontally scalable observability plane across development, staging, and production clusters while maintaining strict resource boundaries and compliance controls.


Component Dependencies and Deployment Order

Installing an integrated monitoring stack requires strict deployment ordering because downstream services rely on existing Kubernetes Services and DNS endpoints to auto-wire data paths. Deploying components out of order leads to initialization failures and broken discovery.

The strict deployment sequence is:

  1. kube-prometheus-stack: Provisions Prometheus, the Prometheus Operator, node-exporter, kube-state-metrics, and the Thanos sidecar.
  2. thanos: Deploys Thanos Query, Store Gateway, and Compactor. Query auto-wires to the Prometheus sidecar deployed in step 1.
  3. loki: Establishes the log storage backend using Google Cloud Storage (GCS).
  4. alloy: Installs the log collection DaemonSet that tails node logs and ships them to Loki's gateway.
  5. grafana: Deploys the visualization engine, pre-configured with datasources for Thanos Query and Loki Gateway.

Metrics Layer: Short-Term Buffering and Long-Term Offloading

Prometheus instances in individual clusters act purely as transient scrapers. Long-term data retention, compaction, and cross-cluster query federation belong in object storage managed by Thanos.

In kube-prometheus-stack, local TSDB retention is set to a 2-day buffer. A Thanos sidecar runs inside the Prometheus pod, continuously shipping 2-hour TSDB blocks to a designated GCS bucket (gs://k8s-monitoring-<env>). Thanos Query runs in its own namespace (thanos) and dynamically discovers local sidecars across namespaces via the kube-prometheus-stack-thanos-discovery DNS-SRV service. Store Gateway handles cold historical data queries from GCS, while Compactor handles downsampling (5-minute resolution retained for 30 days, hourly resolution retained for up to 10 years).

To prevent version mismatch issues between Bitnami repackaged image tags and upstream sidecars, Thanos components are pinned explicitly to upstream image version v0.42.4 (quay.io/thanos/thanos), setting global.security.allowInsecureImages: true in Bitnami's chart. Authentication avoids long-lived secret keys by utilizing GCP Workload Identity, mapping individual Kubernetes ServiceAccounts (thanos-storegateway, thanos-compactor, and prometheus) directly to Google Service Accounts.

Thanos Cost & Resource Economics

The only extra cost Thanos adds to an existing Prometheus setup is essentially the price of storing and querying data from object storage and running the store node.

  • Compute Parity: Queriers, compactors, and store nodes require approximately as many compute resources as they save by not doing the same work directly on Prometheus servers.
  • Network Overhead: Data that is accessed locally in conventional Prometheus setups is transferred over the network in Thanos, typically happening in unmetered internal networks.
  • Object Storage Pricing: Typical object storage prices per GB are ~$0.02. Adding 20% to total storage cost accounts for retrievals ($0.004 per 10,000) and running store nodes.

Capacity Calculations (100TB Metric Data at ~1.07 bytes/sample):

100 TB/1.07 bytes/sample=1.02758×1014 samples

Assuming 1 million active time series:

  • 15s Scrape Interval (4 samples/min):102,758,096.1 samples4 samples/min=25,689,524 min48.88 years of data
  • 1s Scrape Interval (60 samples/min):102,758,096.1 samples60 samples/min=1,712,634 min3.25 years of data

Storing 100TB costs ~$2,400/month on top of baseline Prometheus. In return, reducing Prometheus retention from weeks to hours provides substantial savings on local SSD / network block storage ($0.17/GB) while lowering memory consumption.


Logging Layer: Lightweight Footprint and Compliance Retention

Running full microservices-based logging setups on small-to-medium clusters introduces unnecessary compute overhead. Using Grafana Loki in SingleBinary mode provides a compact footprint while offloading chunk and index storage to cloud object stores.

Loki uses TSDB schema v13 backed directly by GCS, keeping local persistent storage requirements minimal by storing only the write-ahead log (WAL) and index caches on local Persistent Volume Claims (PVCs). Resource consumption is optimized further by disabling default Memcached instances (chunks-cache and results-cache), saving 16Gi of allocated memory per cluster.

Log retention is aligned with ISO 27001:2022 A.8.15 requirements: 90 days (2160h) for development and staging, and 1 year (8760h) for production. To guarantee compliance even if application-level compaction fails, retention is backstopped out-of-band via GCS bucket lifecycle rules. Container logs are gathered by the Grafana Alloy DaemonSet deployed across all nodes and pushed into loki-gateway.


Visualization and Platform Integration

Visualizing telemetry requires robust ingress routing, zero-downtime upgrades, and strict access controls.

Grafana Application Health & Logs Dashboard

Grafana is installed using the maintained grafana-community/grafana Helm chart (12.10.4, app 13.1.3) rather than deprecated repositories. Traffic ingress is managed through Envoy Gateway via native HTTPRoute resources, offloading TLS termination to cluster-level wildcard certificates.

Because Grafana runs as a single replica backed by a ReadWriteOnce (RWO) PVC, using standard RollingUpdate deployment strategies results in Kubernetes volume attachment deadlocks during upgrades. The deployment strategy is explicitly set to Recreate to ensure the old pod releases the RWO volume before the new pod attempts to attach it.

Authentication is secured with GitLab OAuth, restricting access via allowed_domains (acme.com, acme.cloud) and mapping user roles dynamically from GitLab group memberships. Local administrative credentials remain accessible via break-glass settings (disable_login_form = false).


System Architecture & Data Flow

mermaid
graph TD
    subgraph Visualization & Ingress
        G[Grafana]
    end

    subgraph Query & Aggregation Gateways
        TQ[Thanos Query]
        LG[Loki Gateway]
    end

    subgraph Metrics & Scrapes
        P[Prometheus TSDB<br/>Hot Buffer 2d]
        TS[Thanos Sidecar]
        SG[Thanos Store Gateway / Compactor]
    end

    subgraph Logging Engine
        A[Grafana Alloy DaemonSet]
        LSB[Loki SingleBinary<br/>WAL / Local PVC]
    end

    subgraph Cloud Object Storage
        GCS[(Google Cloud Storage<br/>gs://k8s-monitoring-env)]
    end

    G -->|Query Metrics| TQ
    G -->|Query Logs| LG

    TQ -->|Live / Local Scrape| TS
    TQ -->|Historical Data| SG

    P -->|2h Blocks| TS
    TS -->|Ship Blocks| GCS
    SG <-->|Read / Downsample| GCS

    A -->|Push Logs| LG
    LG -->|Write Chunks| LSB
    LSB -->|Chunk & Index Storage| GCS

Observability Standards, SLIs, and Symptom-Based Alerting

Dashboards follow a structured drill-down hierarchy aligned with Grafana Dashboard Best Practices: HTTP Overview (RED metrics), Envoy Gateway Ingress, and Namespace Workloads (USE metrics).

Grafana Service Health RED Dashboard

Grafana DevOps Infrastructure & Cluster Health Dashboard

Ingress traffic is monitored by scraping Envoy proxies via dedicated PodMonitor CRDs and aggregating traffic metrics into standardized service:http_* series using Prometheus recording rules. Service Level Indicators (SLIs) and Objectives (SLOs) are tracked over rolling 30-day windows:

  • Availability SLO: 99.5% non-5xx HTTP response ratio.
  • Latency SLO: p95 upstream response time <2s, and 99% of requests completed within 2.5s.

Alerts fire on user-impacting symptoms rather than arbitrary resource thresholds. For example, HighHttp5xxRate triggers when error rates exceed 5% for 10 minutes (indicating an ~10x error budget burn rate), while HighHttpLatency triggers when p95 latency exceeds 2 seconds for 15 minutes. Alerts evaluate in Alertmanager, which comes pre-enabled in the cluster stack.


Key Takeaways

  • Storage Decoupling: Offloads long-term TSDB metrics to GCS, eliminating node disk overhead and large local volume risks.
  • SingleBinary Logging: Reduces operational complexity and memory footprint compared to microservice modes while remaining ISO 27001 compliant.
  • Deployment Safety: Uses Recreate deployment strategies on single-replica RWO workloads to avoid PVC attachment deadlocks during Helm upgrades.
  • Upstream Image Pinning: Pins Thanos images to upstream quay.io releases to avoid version drift from third-party chart repackaging.
  • Stateless Query Aggregation: Delegates historical and cross-cluster query deduplication to Thanos Query for a clean single-datasource setup.

Concrete Improvement Advice

  1. Configure Alertmanager Receivers: Alertmanager is running and evaluating rules, but lacks configured outbound notification channels. Add explicit Slack or Webhook receivers to values.yaml under alertmanager.config.receivers to route critical alerts.
  2. Eliminate Public Egress Dependencies at Startup: Grafana's init container downloads dashboards 315 and 6417 from grafana.com on startup. Bundle dashboard JSON files locally in the repository and deploy them via Kubernetes ConfigMaps tagged with grafana_dashboard: "1" using apply.sh.
  3. Harden OAuth Access Controls: Transition from domain-based access gating (allowed_domains) to explicit group gating (allowed_groups) in Grafana's OAuth settings once team structures stabilize in GitLab.

External References

Source / ResourceLinkDescription
kube-prometheus-stack Helm Chartprometheus-community/kube-prometheus-stackHelm chart for Prometheus Operator, Prometheus, node-exporter, and Alertmanager.
Thanos Helm Chartbitnami/thanosHelm chart for Thanos Query, Store Gateway, and Compactor.
Loki Helm Chartgrafana/lokiHelm chart for Grafana Loki log aggregation system.
Alloy Helm Chartgrafana/alloyHelm chart for Grafana Alloy telemetry collector.
Grafana Helm Chartgrafana/grafanaMaintained Helm chart for Grafana visualization platform.
Thanos Projectthanos.ioHighly available Prometheus setup with long-term storage capabilities.
Grafana OSSgrafana.com/ossOpen-source visualization and logging platform overview.
Grafana Best PracticesDashboard Best PracticesOfficial design patterns for structuring production dashboards.

Personal Portfolio, Blog and Documentation