Observability on NKPPart 1: the concepts

Published
Reading
11 min

Tested onNKP 2.19Kubernetes 1.36.2Rook Ceph 1.19.6Grafana Loki 3.6.7Lab date

Ler em português

Cover of the Observability on NKP series, with part 1, the concepts, highlighted

Summary: monitoring tells you whether something is broken; observability tells you why. This part brings together the concepts I use with customers (pillars, methods, SLOs and cost) and shows what NKP 2.19 already ships. In the lab, the workload cluster had metrics only. Turning on logs from the catalog took four apps and about 30 minutes, including a complete Ceph storage cluster. And the Alertmanager, on since day one, was firing alerts to no one. This is part 1 of 3.

Why this series

After the NKP upgrade to 2.19, the next question from customers was almost always the same: “so how do I see what is happening inside the cluster?”. The short answer is that NKP already brings a lot. The long answer involves concepts, choices and a few caveats, and it became this series.

PartTopic
1The concepts and what NKP already ships (this post)
2NKP Insights: the cluster pointing out its own problems
3OpenTelemetry Operator: traces, metrics and logs from an application, without touching its code

Everything was tested in the Clear IT AI lab: one management cluster and one workload cluster on NKP 2.19, running on Nutanix AHV.


Monitoring × observability

The two terms are often used as synonyms, but they answer different questions.

MonitoringObservability
QuestionIs it working?Why is it not working?
Starts fromProblems you already knowProblems nobody predicted
Typical formDashboard and fixed-threshold alertExploring data freely, crossing signals
Example“Node CPU above 90%”“Why do 10% of purchases fail only when the item is a mouse?”

Monitoring is a subset of observability. You still need the alerts; the difference is having enough data to investigate what the alert does not explain.

Observability is a property of the system

A system is observable when you can understand its internal state just by looking at what it emits. It is not a tool you buy: it is something you build, by instrumenting the applications and keeping the right signals.

The pillars

SignalWhat it isGood forExample tools
MetricsNumbers over timeTrends, alerting, capacityPrometheus, Thanos, Mimir, VictoriaMetrics
LogsEvent records, as textDetail of a specific errorLoki, Elasticsearch, Fluent Bit, Fluentd
TracesThe path of a request across servicesLatency and failures in distributed systemsJaeger, Tempo, Zipkin
Kubernetes eventsState changes of objects“What changed?”kubectl get events, Headlamp
ProfilingWhere the code spends CPU and memoryFine-grained optimizationPyroscope, Parca

In Kubernetes, events work in practice as a fourth pillar: an OOMKilled or a FailedScheduling explains a lot before any dashboard does. The real value shows up when the signals are linked. In Part 3, one click on a failed trace opens the logs of that very request.

What to measure: three methods

Measuring everything is expensive and confusing. These methods help you pick the useful minimum.

MethodFor whatSignals
Four golden signals (Google SRE book)Any user-facing serviceLatency, traffic, errors and saturation
REDMicroservices and APIsRate, Errors, Duration
USEInfrastructure: CPU, disk, networkUtilization, Saturation, Errors

A rule of thumb: RED for applications, USE for nodes and storage. The dashboards NKP ships cover USE well; RED depends on instrumenting the applications, which is the subject of Part 3.

SLI, SLO and error budget

This is where observability becomes a business conversation.

TermWhat it isExample
SLIThe measured indicator% of purchases completed successfully
SLOThe target for the indicator99.5% success over 30 days
Error budgetHow much you can fail within the target0.5% of purchases, about 3.6 hours a month of equivalent downtime

With an SLO in place, the alert stops being “CPU went up” and becomes “we are burning the error budget too fast”. That cuts useless alerts and gives a clear criterion for choosing between shipping new features and investing in stability.

OpenTelemetry: the open standard

OpenTelemetry is a CNCF project that standardizes how applications produce metrics, logs and traces and how that data is transported. The core idea: instrument once and send to any tool, open source or commercial.

In practice, it removes lock-in from the instrumentation layer. Changing backends becomes a configuration change in the Collector, not a code rewrite. NKP 2.19 ships the OpenTelemetry Operator in the catalog, and it is the topic of Part 3.

The tools on the market

A neutral view of what is out there. There is no best one; there is the one that fits each company’s team, budget and retention rules.

TypeExamplesStrengthsWatch out for
Open sourcePrometheus, Grafana, Loki, Tempo, Mimir, Thanos, VictoriaMetrics, Jaeger, OpenTelemetry, Fluent Bit, SigNoz, OpenCostNo license cost, no lock-in, large communityRunning, scaling and storing the data is on you
Enterprise and SaaSDatadog, Dynatrace, New Relic, Splunk Observability, Elastic, Grafana Cloud, Honeycomb, ChronosphereReady to use, built-in correlation and AI, supportCost grows with volume; data leaves the environment; vendor dependency
From the platform (Nutanix)NKP stack (Prometheus, Grafana, Loki, Logging Operator), NKP Insights, Prism operationsAlready integrated, supported by the platform vendorScope limited to what the platform packages

The criteria I use to choose:

CriterionQuestion
CostHow much per GB of logs, per metric series, per host? And two years from now?
Operating effortWho maintains, upgrades and scales the tool?
RetentionHow long must data be kept, by policy or for audits?
Data sovereigntyCan the data leave the environment?
Lock-inIs the instrumentation open (OpenTelemetry) or proprietary?

Many companies end up with a mixed model: the platform’s open stack for day-to-day work and a commercial tool for the most critical applications.

The cost of observability

Observability is not free, even with open source tools. The cost comes from three places:

  • Metric cardinality: every combination of labels becomes a series. A label holding the user ID can multiply the series by millions.
  • Log volume and retention: debug logging left on in production fills storage fast.
  • Cluster resources: every component of the stack uses CPU, memory and disk.

In the lab, the management cluster’s Prometheus alone used about 5.9 GiB of memory, with 10-day retention on a 100 GiB volume. And by the end of this series, after turning on logs, Insights and OpenTelemetry in the workload cluster, the cluster’s reserved CPU (requests) went from 27.1% to 72.5%. Observability has to be part of sizing from the start.


What NKP already ships turned on

Before enabling anything, I ran a read-only inventory on both clusters. The difference between them was the first finding.

ComponentManagementWorkload
Prometheus (kube-prometheus-stack)✓✓
Alertmanager✓✓
Grafana✓ (per cluster plus a central one)✓
Thanos (cross-cluster queries)✓route only
Karma (alert dashboard)✓route only
OpenCost✓ (per cluster plus a central one)✓
Grafana Loki + Logging Operator✓—
Grafana Logging✓—
NKP Insights (central part)✓—
Prometheus retention10 days, 100 GiB10 days, 100 GiB

The workload cluster comes with metrics but no logs. For whoever runs applications there, the most-used signal in daily work was missing.

The workload Grafana already showed the resource dashboards working, with a detail worth flagging to any customer: the CPU limits of the kube-system namespace added up to 161% of what the cluster has.

Workload cluster Grafana, Kubernetes Compute Resources Cluster dashboard: CPU 8.7% used, 27.1% in requests and 60.4% in limits

In the catalog, the Observability category has two apps, both off by default. They are the topics of parts 2 and 3.

NKP catalog, Observability category: NKP Insights 1.9.7 and OpenTelemetry Operator 0.114.1, both disabled

In the lab: turning on logs in the workload cluster

Goal: get the logs of every pod in the workload cluster into Grafana, using only the NKP catalog.

This is the log path in NKP:

There are four apps in the catalog, each depending on another:

AppRoleDepends on
Grafana LoggingLog dashboards and searchGrafana Loki
Grafana LokiStores and indexes the logsRook Ceph Cluster and Logging Operator
Logging OperatorFluent Bit on each node collects; Fluentd filters and ships—
Rook Ceph ClusterCreates the Ceph storage and Loki’s S3 bucketRook Ceph (the operator)

The shortcut that did not work

I started with Grafana Logging and accepted the dependencies the interface showed. When I enabled Loki, NKP warned that two were missing: Rook Ceph Cluster and Logging Operator. The warning lets you continue anyway, and I did, to see what would happen.

Dependency warning when enabling Grafana Loki: Rook Ceph Cluster and Logging Operator are missing in the cluster

The app showed as Enabled in the interface. The pods did not come up:

grafana-loki-v3-ingester-zone-a-0 0/1 CreateContainerConfigError
...
Warning Failed kubelet Error: secret "dkp-loki" not found

The dkp-loki Secret holds the credentials for the bucket Loki writes to. That bucket is created by Rook Ceph Cluster, which did not exist yet. Note a confusing detail: Rook Ceph and Rook Ceph Cluster are different apps. The first is only the operator; the second creates the storage cluster.

“Enabled” does not mean working

NKP lets you enable an app with a missing dependency. The interface shows the app as enabled, but it may never start. After an Enable, check the pods, not just the card.

In the right order

I enabled the missing dependencies. The Logging Operator came up in about a minute: one operator, 6 Fluent Bit pods (one per node) and one Fluentd. Rook Ceph Cluster took longer, because it builds an entire storage cluster in sequence: monitors, managers, disks and the S3 gateway.

TimeWhat happened
00:02Grafana Logging, Loki and Rook Ceph enabled, ignoring the warnings
00:11Loki stuck: secret "dkp-loki" not found
00:13Logging Operator up; Fluentd starts collecting
00:16Rook Ceph Cluster enabled
~00:223 monitors, 2 managers and 4 disks being prepared
~00:32Bucket and Secret created; Loki recovers on its own, with no action
~00:48Ceph HEALTH_OK, less than 32 minutes after the Enable

The Ceph cluster created by the app uses volumes from the cluster’s default storage and delivered 160 GiB raw, with 4 data disks across the 3 workers, 2 S3 gateways and 3+1 erasure coding for bucket data. It created two buckets: Loki’s and one for Velero.

Ceph Dashboard: HEALTH_OK, version 19.2.3, 3 hosts, 3 monitors, 4 OSDs, 9 pools and 160 GiB raw

The Ceph dashboard has its own login

The card’s Dashboard button opens the Ceph Dashboard, but it does not use Kommander’s single sign-on. The user is admin, and the password is in the rook-ceph-dashboard-password Secret.

The logs that arrived before Loki

In Grafana Logging, kube-system logs showed up from 00:20, about 12 minutes before Loki was ready. The explanation was in the Fluentd log:

[warn]: ... failed to flush the buffer. retry_times=0 ... error="502 Bad Gateway"
[warn]: ... failed to flush the buffer. retry_times=1 ...

Fluentd tried to deliver, got a 502 from the Loki gateway, kept the logs in an on-disk buffer and kept retrying. When Loki came up, it delivered what it had stored. Nothing was lost.

Grafana Logging, kube-system log volume: records start at 00:20, before Loki was ready

Result

Logs from every pod in the workload cluster in Grafana, collected by Fluent Bit and Fluentd and stored in Loki on a Ceph cluster created by NKP itself. About 30 minutes, most of it waiting for Ceph.

The alerts that warned no one

Alertmanager comes turned on in both clusters. In the workload cluster, 5 alerts were firing:

Workload cluster Alertmanager: 4 alerts in the workspace namespace and 1 in kube-system, all on the null receiver

AlertSeverityWhat it was
WatchdognoneAlways firing on purpose: proves the alerting pipeline is alive
InfoInhibitornoneHelper that silences info-level alerts
CPUThrottlingHighinfoFluentd sidecar with 30% CPU throttling, right after starting
KubeProxyDowncriticalFiring for two days. False alarm

KubeProxyDown is a false alarm because the cluster has no kube-proxy: Cilium does that job.

Terminal window
$ kubectl -n kube-system get ds kube-proxy
Error from server (NotFound): daemonsets.apps "kube-proxy" not found
$ kubectl -n kube-system get cm cilium-config -o jsonpath='{.data.kube-proxy-replacement}'
true

And the most important part was in the default configuration:

route:
receiver: "null"
receivers:
- name: "null"

The only configured destination is "null". Alerts fire and go to no one: no email, no Slack, no Teams. Together with a false critical alert firing for two days, that is the scenario that teaches a team to ignore alerts.

Before production

Configure at least one real destination in Alertmanager, send the Watchdog to a “dead man’s switch” service, and tune or silence the rules that do not apply to your environment, such as KubeProxyDown in a cluster running Cilium.

What about AI?

The same logic applies to AI workloads, with their own signals:

LayerWhat to observe
GPUUtilization, memory, temperature and errors (NVIDIA DCGM Exporter)
Inference serverQueue, requests per second, latency
LLMInput and output tokens, time to first token (TTFT), cost per request

OpenTelemetry already has semantic conventions specific to generative AI, to record model, tokens and latency in a standard way.

A maturity model

To place where each customer stands:

LevelWhat it looks likeIn the lab, before this series
1. ReactiveSomeone looks at the dashboard when users complain—
2. MonitoredFixed-threshold alerts reach someonePartial: alerts exist but reach no one
3. ObservableMetrics, logs and traces linked together; you can investigate the unknownMetrics yes; logs only on management; no traces
4. SLO-drivenError-budget alerts; product decisions use the data—

Parts 2 and 3 take the lab from level 2 to level 3.


What I learned

  1. The workload cluster comes with metrics only. Logs and traces have to be enabled, and that has a cost.
  2. The dependency warning lets you continue, and the result is an “Enabled” app that does not work. Check the pods after every Enable.
  3. Rook Ceph and Rook Ceph Cluster are different apps. The first is the operator; the second is the storage.
  4. The Fluentd buffer holds the logs when the destination goes down. That resilience comes out of the box.
  5. An alert with no destination protects nothing, and a false critical alert teaches people to ignore alerts.
  6. Observability uses resources. It goes into sizing, not after it.

Basic observability checklist on NKP

  • Inventory of what is already on in each cluster
  • Logs enabled on workload clusters, with dependencies in order
  • Pods checked after every Enable, not just the app card
  • At least one real destination configured in Alertmanager
  • Watchdog wired to an external “dead man’s switch” service
  • Rules that do not apply to the environment tuned or silenced
  • Metric and log retention defined by business rules
  • Observability stack consumption included in cluster sizing

Next part

In Part 2, NKP Insights: enabling it on both clusters, seeing what it finds on its own and comparing it with the Prometheus alerts we just saw.

References

Comments

Comments use GitHub Discussions; you need a GitHub account.