Ga naar inhoud

Uitwerking

GKE Standard cluster opgezet met een moderne monitoring stack: Loki (SingleBinary), Grafana Alloy en Prometheus via kube-prometheus-stack.

Afwijkingen t.o.v. het aangeleverde schoolmateriaal

Het script vanuit school bevatte een aantal foutjes en verouderde onderdelen. Bij het uitvoeren kreeg ik deprecation warnings in mijn terminal, dus ik heb gekeken of ik dat zelf kon oplossen. Dat lukte.

SchoolscriptMijn versieReden
grafana/loki-distributedgrafana/loki (SingleBinary)loki-distributed chart is deprecated; functionaliteit zit nu in de hoofdchart
grafana/promtailgrafana/alloypromtail is deprecated
losse grafana/grafana releasegebundeld in kube-prometheus-stackstandalone chart is deprecated
storageClass: managed-csistandard-rwoAzure-specifiek, werkt niet op GKE

Het originele script staat in static/docs/week-5/bestanden/opdracht/, mijn versie in static/docs/week-5/bestanden/uitwerking/.

Gebruikte charts:

ComponentNamespaceChart
Lokilokigrafana/loki (SingleBinary)
Log collectoralloygrafana/alloy
Prometheus + Grafanaprometheusprometheus-community/kube-prometheus-stack
Ingressingress-nginxingress-nginx/ingress-nginx

Bronnen:

OnderwerpBron
Loki monolithic (SingleBinary)grafana.com/docs/…/install-monolithic/
Loki schema configuratiegrafana.com/docs/loki/latest/operations/storage/schema/
Alloy configureren op Kubernetesgrafana.com/docs/alloy/latest/configure/kubernetes/
Alloy voorbeeldscenario’sgithub.com/grafana/alloy-scenarios

Stap 1: Kubernetes cluster aanmaken

Waarom Standard en niet Autopilot?

Autopilot beperkt DaemonSets, blokkeert standaard privileged containers en vereist resource requests voor elke pod. Dat botst met de monitoring stack:

  • Alloy draait als DaemonSet met toegang tot /var/log/pods op de host
  • Prometheus node-exporter heeft privileged toegang nodig tot host-metrics
  • ingress-nginx vereist poortconfiguratie die Autopilot niet altijd toestaat

Met Standard heb je gewoon volledige controle over node-configuratie, DaemonSets en privileged workloads.

gcloud container clusters create week5-cluster \
  --region=europe-west4 \
  --node-locations=europe-west4-a,europe-west4-b \
  --project=project-5b8c5498-4fe2-42b9-bc3 \
  --machine-type=e2-medium \
  --num-nodes=2 \
  --disk-size=50 \
  --disk-type=pd-balanced \
  --release-channel=regular
VlagWaardeToelichting
--regioneurope-west4Regio dichtstbij Nederland
--node-locationseurope-west4-a,europe-west4-bAlleen zones a en b; zone-c had continu GCE_STOCKOUT fouten
--machine-typee2-medium2 vCPU, 4GB RAM, voldoende voor SingleBinary Loki + Prometheus + Grafana
--num-nodes22 nodes per zone × 2 zones = 4 nodes totaal
--disk-size504 × 50GB = 200GB SSD, ruim binnen het quota van 500GB
--disk-typepd-balancedSSD (balanced), betere I/O voor Prometheus TSDB writes
--release-channelregularStabiele GKE-versies met automatische upgrades

Studentquota (disk): De standaard GKE-instellingen (100GB per node) zouden 4 × 100GB = 400GB SSD vereisen. Met --disk-size=50 komt het uit op 4 × 50GB = 200GB SSD, ruim binnen het quota van 500GB.

Studentquota (RAM): e2-medium (4GB RAM per node) verdubbelt het RAM t.o.v. e2-small. GCP telt RAM niet als separate quota; de begrenzing zit in VM instances en CPUs, beide ruim binnen de studentlimieten.

Dit cluster heeft me bijna twee weken gekost.

Ik bleef een GCE_STOCKOUT fout krijgen in zone europe-west4-c - de zone had simpelweg geen capaciteit beschikbaar. Mijn quota’s zagen er prima uit, dus ik had geen idee waar het aan lag. Ik heb er samen met een paar klasgenoten naar gekeken, maar niemand kon het direct verklaren.

De oplossing was om zone-c uit te sluiten met --node-locations=europe-west4-a,europe-west4-b. Zones a en b hadden geen problemen, zone-c bleef hangen. Voor een monitoring stack zijn twee zones meer dan genoeg.

Quota overzicht - ruim binnen de limieten

GCE_STOCKOUT fout zichtbaar in de GKE console

GCE_STOCKOUT fout in de terminal tijdens cluster aanmaken

Instance groups: zone-c blijft hangen op Updating terwijl a en b gewoon draaien

Stap 1 t/m 3 voer je uit vanuit Google Cloud Shell. helm, kubectl en gcloud zijn daar standaard beschikbaar, je hoeft niets lokaal te installeren.

Na het installeren van de auth plugin in Cloud Shell:

gcloud components install gke-gcloud-auth-plugin

Cluster aanmaken via gcloud CLI

Clusterdetails tijdens aanmaken in de GCP Console

GKE cluster wordt aangemaakt in de GCP Console

Cluster succesvol aangemaakt met status RUNNING

GKE console: Standard modus, 6 nodes, versie 1.35.1-gke.1396001, Regular release channel


Stap 2: Verbinding maken met het cluster

Verbinden in Google Cloud Shell:

gcloud container clusters get-credentials week5-cluster \
  --region=europe-west4 \
  --project=project-5b8c5498-4fe2-42b9-bc3

get-credentials en kubectl get nodes tonen 6 Ready nodes


Stap 3: Stack deployen

De repository klonen in Cloud Shell (of updaten als die al bestaat):

# Eerste keer
git clone https://github.com/Stensel8/public-cloud-concepts.git
cd public-cloud-concepts

# Al eerder gecloned
cd public-cloud-concepts && git pull

Daarna het script uitvoeren:

cd static/docs/week-5/bestanden/uitwerking
bash setup-loki-prometheus-grafana.sh

Uitvoer van setup-loki-prometheus-grafana.sh in Cloud Shell

Het script installeert de stack in vijf stappen: Helm repos toevoegen, ingress-nginx (met kubectl wait), Loki, Alloy, Prometheus + Grafana.

Waarom ingress-nginx als eerste? De kube-prometheus-stack maakt bij installatie direct een Grafana Ingress-object aan. De ingress-nginx controller valideert dat object via een webhook; als ingress-nginx nog niet draait, mislukt de Helm-installatie met een webhook-fout. Door ingress-nginx eerst te installeren en te wachten tot de controller Ready is, voorkom ik dat.

loki-values.yaml

De grafana/loki chart vereist een expliciete schemaConfig, anders geeft Helm een harde fout:

Error: You must provide a schema_config for Loki.

Deployment mode kiezen

De grafana/loki chart ondersteunt drie deployment modes. De keuze hangt af van de clustergrootte:

ModePodsWanneer gebruikenMemcached caches
SingleBinary1Dev, labs, één gebruikerZinloos (alles intern)
SimpleScalable3 (read / write / backend)Middelgrote teams, stagingZinvol
Distributed7+ (elk component apart)Grote productie, hoge loadEssentieel

Distributed is niet altijd beter. Het principe is dat read- en write-paden onafhankelijk schalen, maar als je toch op 1 replica per component zit voeg je alleen maar netwerkhops en geheugenoverhead toe. Op een cluster van 4× e2-medium nodes is Distributed ronduit verspilling.

SimpleScalable klinkt als de logische middenweg, maar vereist een object storage backend (GCS, S3 of MinIO). Filesystem storage is de eenvoudigste optie in een leeromgeving, maar wordt niet ondersteund in SimpleScalable mode. Dat levert de volgende fout bij helm install:

Error: Cannot run scalable targets (backend, read, write) or distributed targets without an object storage backend.

SimpleScalable is een goede keuze als object storage al beschikbaar is (zoals een GCS bucket), maar dat opzetten voegt behoorlijk wat overhead toe voor een labopdracht.

SingleBinary is daarmee de juiste keuze: één pod, filesystem storage, geen object storage nodig. De memcached caches (chunks-cache, results-cache) zijn in deze mode zinloos en worden uitgeschakeld. Alles draait in-process, dus caching via een externe service voegt alleen overhead toe.

Verband met de opdracht: De docent gebruikte de grafana/loki-distributed chart, die inmiddels deprecated is. Dat betekent niet dat distributed Loki deprecated is; de functionaliteit zit nu in de hoofdchart (grafana/loki). Voor een leeromgeving met filesystem storage is SingleBinary de correcte keuze.

Het volledige bestand staat op GitHub. Overige keuzes:

  • storageClass: standard-rwo: GKE-compatibel; het schoolscript gebruikte managed-csi, wat Azure-specifiek is
  • minio.enabled: false: filesystem storage is voldoende voor deze setup
  • retention_period: 336h (14 dagen) + compactor met retention_enabled: true: logs worden daadwerkelijk verwijderd na 14 dagen

alloy-values.yaml

Alloy vervangt Promtail en gebruikt de Alloy flow language. De config doet hetzelfde als Promtail, maar declaratief:

  1. Kubernetes pods ontdekken (discovery.kubernetes)
  2. Labels toevoegen op basis van pod-metadata (discovery.relabel)
  3. Logs lezen van de pods (loki.source.kubernetes)
  4. Logs doorsturen naar Loki (loki.write)

De grafana/loki chart zet standaard een nginx gateway voor de Loki pod. Alle Loki-URLs gaan via die gateway:

# Alloy naar Loki (push)
http://loki-gateway.loki.svc.cluster.local/loki/api/v1/push

# Grafana datasource
http://loki-gateway.loki.svc.cluster.local

Twee geldige aanpakken: De officiële Grafana tutorial gebruikt de grafana/k8s-monitoring chart (kant-en-klare bundel). Voor meer inzicht in wat er onder de motorkap gebeurt heb ik gekozen voor de standalone grafana/alloy chart.

prometheus-values.yaml

Grafana is ingebouwd in kube-prometheus-stack (grafana.enabled: true), dus is er geen aparte grafana/grafana chart nodig. Prometheus staat op 1 replica, de monitoring stack is RAM-intensief en meerdere replica’s zijn voor deze setup niet nodig.


Stap 4: IP-adres ophalen

kubectl get ingress -n prometheus

kubectl get ingress toont het externe IP-adres voor grafana.stijhuis.nl

Ingress status met adres en hostnaam


Stap 5: DNS instellen

Het externe IP is als A-record ingesteld bij Bunny DNS voor grafana.stijhuis.nl, in plaats van het hosts-bestand handmatig aan te passen. Een DNS-record werkt direct op alle apparaten wereldwijd, zonder lokale configuratie.

Grafana values aangepast met de hostnaam

DNS record aanmaken in Bunny DNS

Overzicht DNS records in Bunny DNS


Stap 6: Grafana openen

Via https://grafana.stijhuis.nl in de browser:

Grafana 404 bij eerste bezoek, DNS nog niet gepropageerd

Grafana login pagina bereikbaar

Na het inloggen zijn de twee databronnen actief: Loki en Prometheus. Via Connections > Data sources heb ik beide bronnen getest.


Stap 7: Dashboards instellen

Als basis voor Kubernetes monitoring is het community dashboard k8s-custom-metrics (ID 20960) gebruikt (versie 3).

Dashboard geïmporteerd via Dashboards > Import met ID 20960, Prometheus als datasource:

Dashboard template selecteren bij importeren

Dashboard importeren in Grafana met Prometheus als datasource

Kubernetes application insights dashboard actief, cluster CPU 70%, RAM 63%


Stap 8: Week 1 en 2 applicatie deployen

De week 1 applicatie (stensel8/public-cloud-concepts:latest) is een statische website geserveerd via nginx. Week 2 gebruikt hetzelfde Docker image, een aparte deployment is daarvoor niet nodig. Het installatiescript deployt de app automatisch als stap 6. Omdat ingress-nginx al actief is, gebruikt de app een ClusterIP service met een Ingress.

kubectl get pods -n mywebsite
kubectl get ingress -n mywebsite

Stel een DNS A-record in voor mywebsite.stijhuis.nl naar hetzelfde Ingress IP-adres als Grafana.

Wat valt er te monitoren aan een static site?

Op het eerste gezicht weinig, maar de monitoring stack pikt automatisch het volgende op:

  • Loki + Alloy leest de nginx access logs uit → HTTP statuscodes, request rate, 404’s
  • kube-state-metrics (onderdeel van kube-prometheus-stack) → pod availability, restarts, CPU/memory

In Grafana zijn deze logs en metrics direct zichtbaar via de Loki- en Prometheus-databronnen. Dat is precies wat de opdracht aantoont: niet de complexiteit van de app, maar het functioneren van de monitoring stack.


Stap 9: Architectuurdiagram

De monitoring stack bestaat uit vier lagen: log-verzameling (Alloy), log-opslag (Loki), metrics (Prometheus + exporters) en visualisatie (Grafana). Ingress-nginx verzorgt de externe toegang.

    flowchart LR
    browser(["Browser\ngrafana.stijhuis.nl"])

    subgraph ingress_ns["ingress-nginx"]
        nginx["ingress-nginx\nLoadBalancer"]
    end

    subgraph app_ns["mywebsite"]
        app["nginx static site\nstensel8/public-cloud-concepts"]
    end

    subgraph alloy_ns["alloy"]
        alloy["Grafana Alloy\nDaemonSet"]
    end

    subgraph loki_ns["loki"]
        loki_gw["Loki Gateway"]
        loki_pod[("Loki SingleBinary\nfilesystem storage")]
        loki_gw --> loki_pod
    end

    subgraph prom_ns["prometheus — kube-prometheus-stack"]
        node_exp["node-exporter\nDaemonSet"]
        ksm["kube-state-metrics"]
        prom[("Prometheus TSDB")]
        grafana["Grafana"]
        node_exp -->|"scrape /metrics"| prom
        ksm -->|"scrape /metrics"| prom
    end

    browser -->|"HTTPS — Bunny DNS"| nginx
    nginx --> grafana
    app -->|"stdout/stderr"| alloy
    alloy -->|"HTTP push"| loki_gw
    prom -->|"PromQL"| grafana
    loki_pod -->|"LogQL"| grafana
  
ComponentNamespaceRol
ingress-nginxingress-nginxExterne toegang; exposeert Grafana via HTTP Ingress
Grafana AlloyalloyDaemonSet; leest pod-logs via loki.source.kubernetes en stuurt ze naar Loki
Loki Gatewaylokinginx reverse proxy voor de Loki API
Loki SingleBinarylokiLog-aggregatie; slaat logs op als chunks op filesystem
node-exporterprometheusDaemonSet; exporteert host-level metrics (CPU, RAM, disk, netwerk)
kube-state-metricsprometheusExporteert Kubernetes object-status (pods, deployments, replicas)
PrometheusprometheusScrapet metrics van node-exporter en kube-state-metrics; slaat op als TSDB
GrafanaprometheusVisualiseert metrics (PromQL) en logs (LogQL) via datasources

Stap 10: Andere monitoring-tools voor Kubernetes

De stack die ik gebruik (Loki, Alloy, Prometheus, Grafana) is open-source en zelf te hosten. Er zijn ook commerciële alternatieven die meer out-of-the-box bieden.

Datadog

Datadog is een cloud-native observability platform. Je installeert een DaemonSet (de Datadog Agent) in je cluster, en daarna verzamelt het automatisch metrics, logs en traces. Geen losse Helm charts voor Prometheus, Loki en Grafana; alles zit in één platform.

Voordeel: snelle setup, sterke integraties, goede APM (Application Performance Monitoring) voor distributed tracing. Nadeel: kostbaar op schaal en je bent volledig afhankelijk van Datadog als vendor.

New Relic

Vergelijkbaar met Datadog. New Relic heeft ook een Kubernetes-integratie die automatisch cluster-health bijhoudt. Het heeft een genereuze gratis laag (100 GB/maand), wat het aantrekkelijk maakt voor kleinere omgevingen.

Dynatrace

Dynatrace gaat een stap verder met AI-gedreven root cause analysis. In plaats van alleen dashboards te tonen, probeert het automatisch te bepalen wat de oorzaak is van een probleem. Nuttig in grote, complexe omgevingen waar handmatig door dashboards scrollen niet schaalbaar is.

Vergelijking met mijn stack

Mijn stackDatadog / New Relic / Dynatrace
KostenGratis (open-source)Betaald (op basis van hosts of data)
SetupMeer configuratie nodigSnelle installatie
Vendor lock-inGeenHoog
FlexibiliteitVolledig aanpasbaarBeperkt tot platform-mogelijkheden
APM / tracingZelf opzetten (Tempo)Ingebouwd

Voor een leeromgeving is de open-source stack de betere keuze: je begrijpt wat er onder de motorkap gebeurt. In een professionele omgeving met een groot cluster zou ik Datadog of Dynatrace overwegen vanwege de lage beheerslast.


Stap 11: SIEM en SOAR

Wat is SIEM?

SIEM staat voor Security Information and Event Management. Een SIEM verzamelt logs en events uit allerlei bronnen (servers, netwerkapparaten, applicaties) en correleert die om verdacht gedrag te detecteren. Bekende voorbeelden zijn Microsoft Sentinel, Splunk en IBM QRadar.

Het gaat niet alleen om opslaan van logs, maar om het vinden van patronen: meerdere mislukte inlogpogingen van hetzelfde IP, een account dat midden in de nacht data downloadt, of een nieuwe admin die opeens toegang heeft tot productie.

Wat is SOAR?

SOAR staat voor Security Orchestration, Automation and Response. Waar een SIEM detecteert, regelt een SOAR de reactie. Als een SIEM een alert genereert, kan een SOAR automatisch een playbook uitvoeren: het account blokkeren, een ticket aanmaken, de beheerder notificeren.

In combinatie werkt het zo: SIEM detecteert een incident, SOAR reageert er geautomatiseerd op.

Koppeling aan ITIL

ITIL beschrijft processen voor IT-dienstverlening. Twee processen zijn hier direct relevant:

Incident Management gaat over het zo snel mogelijk herstellen van een dienst. Een SIEM signaleert het incident, een SOAR-playbook schakelt de aanval automatisch in en maakt een ticket aan. Dat verkort de Mean Time to Detect (MTTD) en Mean Time to Respond (MTTR) direct.

Problem Management gaat een stap verder: wat is de onderliggende oorzaak? Uit SIEM-data kun je patronen halen die wijzen op een structureel probleem, zoals een applicatie die structureel te veel rechten vraagt of een endpoint dat regelmatig het doelwit is van brute-force.

Koppeling aan DevOps

In DevOps wil je security integreren in de hele pipeline (DevSecOps). Een SIEM/SOAR past daar goed in:

  • Alerts uit de SIEM kunnen automatisch een pipeline blokkeren als er verdachte activiteit is gedetecteerd.
  • SOAR-playbooks kunnen geautomatiseerd reageren zonder dat een beheerder handmatig hoeft in te grijpen, wat past bij de DevOps-filosofie van automatisering.

Stap 12: TerramEarth casestudy

TerramEarth maakt zware machines voor de mijnbouw en landbouw. Ze hebben 2 miljoen voertuigen in gebruik die sensortdata verzamelen: kritieke data gaat real-time, de rest wordt dagelijks geupload. Dat is per voertuig 200-500 MB per dag. Ze draaien op Google Cloud, maar hebben ook legacy-systemen on-premise.

Een expliciete uitdaging uit hun executive statement: “improve and standardize tools necessary for application and network monitoring and troubleshooting.” Dat is precies het speelveld van de twee producten hieronder.

Product 1: Google Cloud Monitoring (Operations Suite)

Google Cloud Monitoring verzamelt metrics, logs en traces van alle Google Cloud-resources. Omdat TerramEarth al op Google Cloud draait, is integratie minimaal: Cloud Monitoring is out-of-the-box beschikbaar.

Problem Management:

Tactisch niveau: Cloud Monitoring kan trends analyseren over langere periodes. Als voertuigsensoren van een bepaald model structureel hogere CPU-load rapporteren op de verwerkingspipeline, is dat een signaal voor een structureel probleem in de dataverwerkingscode. Een dashboard met historische trends maakt dit zichtbaar voor het management.

Operationeel niveau: Een beheerder ziet in real-time dat de ingest-pipeline vertraging oploopt. Via Cloud Monitoring Alerts krijgt hij een notificatie als de latency boven een drempelwaarde komt. Hij kan direct de oorzaak opsporen via de bijbehorende logs in Cloud Logging.

Monitoring and Event Management:

Tactisch niveau: SLO (Service Level Objectives) instellen voor de datapipeline. TerramEarth kan afspreken dat 99,9% van de real-time vehicledata binnen 5 seconden verwerkt moet zijn. Cloud Monitoring bewaakt deze SLO continu en rapporteert de error budget naar het management.

Operationeel niveau: Automatische alerts bij afwijkingen. Als een zone opeens geen data meer ontvangt van voertuigen in een bepaalde regio, triggert een alert direct. Dat kan wijzen op een netwerkaanleg of een softwarefout in de on-board firmware.


Product 2: Grafana + Prometheus (zelf te hosten of via Grafana Cloud)

Dit is dezelfde stack als ik in Week 5 gebruik. Voor TerramEarth is dit interessant omdat ze naast hun Google Cloud omgeving ook on-premise legacy-systemen hebben. Grafana kan datasources van beide omgevingen combineren in één dashboard.

Problem Management:

Tactisch niveau: Grafana heeft annotaties: je kunt events (zoals software-releases of firmware-updates) markeren op grafieken. Als een nieuwe firmware-versie samenvalt met een stijging in foutmeldingen, is de correlatie direct zichtbaar. Dat helpt bij het identificeren van de root cause.

Operationeel niveau: Via Prometheus-alerting kunnen beheerders automatisch gewaarschuwd worden als een specifiek voertuigtype buiten normale bandbreedtegrenzen valt. Dat kan wijzen op een defect sensor of een netwerkprobleem in het veld.

Monitoring and Event Management:

Tactisch niveau: Omdat TerramEarth zowel Google Cloud als on-premise heeft, is een gecentraliseerd Grafana-dashboard waardevol. Prometheus scrapt metrics van beide omgevingen, Grafana visualiseert alles in één plek. Het management heeft zo een compleet beeld van de infrastructuurstatus.

Operationeel niveau: Grafana Alerting kan bij een alert automatisch een webhook sturen naar een ticketsysteem (zoals PagerDuty of Jira). Dat is vergelijkbaar met SOAR: detectie en de eerste stap van response zijn geautomatiseerd.