Observability in Kubernetes

Observability

Chapter 10 · Observability in Kubernetes

k8s2-7's own Observability chapter covered Metrics Server, Prometheus scraping, and Grafana at a deliberately light touch, closing with an honest note that a fuller course existed for anyone who needed to go deeper. This is that chapter — applying everything from Ch.2 through Ch.9 specifically to Kubernetes' own genuinely different operating conditions.

Why Kubernetes Needs Its Own Observability Chapter

obs1-3 already named the core problem: a hand-maintained, static target list breaks the moment instances scale up, scale down, or get rescheduled — exactly what happens continuously in Kubernetes, where pods are genuinely ephemeral and routinely get new IPs. And this is distinct from k8s1-11's own liveness/readiness probes — probes are Kubernetes' own built-in mechanism for restarting or routing around an unhealthy pod; this chapter is about actually observing metrics, logs, and traces from those same pods, a separate and complementary concern.

kube-state-metrics — Metrics About Kubernetes Objects Themselves

obs1-3's node_exporter reports host-level metrics — CPU, memory, disk of the underlying machine. kube-state-metrics reports something genuinely different: the state of Kubernetes API objects themselves — how many pods a Deployment currently has running versus desired, how many replicas are unavailable, pod restart counts, whether a PersistentVolumeClaim is bound. This is directly the same "desired vs. actual state" theme k8s1-2's own reconciliation loop and k8s1-5's ReplicaSet material already established, now exposed as real, queryable metrics.

kube_deployment_status_replicas_unavailable{deployment="checkout-api"} 3

A genuinely useful alert source on its own — a Deployment with unavailable replicas is a direct, concrete instance of obs1-6's own alert-rule material, applied here to Kubernetes' own object state rather than an application's business metrics.

The Prometheus Operator — Managing Prometheus the Kubernetes Way

Running Prometheus by hand inside Kubernetes — a raw Deployment plus a ConfigMap holding prometheus.yml — works, but every new scrape target means manually editing that config and reloading it. The Prometheus Operator introduces Kubernetes-native Custom Resources that let Prometheus's own configuration be managed declaratively, the same way any other Kubernetes object is defined per k8s1-4's own YAML-manifest material — rather than as one hand-edited file.

ServiceMonitors — Declarative Scrape Configuration

apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: checkout-api spec: selector: matchLabels: app: checkout-api endpoints: - port: metrics interval: 30s

A ServiceMonitor declares "scrape any Service matching these labels, on this port, at this interval." The Prometheus Operator watches for ServiceMonitor objects and automatically reconfigures the underlying Prometheus to match, live — no manual reload required. This is Kubernetes' own real fix for obs1-3's static-target problem: instead of a generic kubernetes_sd_config still requiring manual relabeling rules, each application team declares its own scrape intent right alongside its own Service definition, reviewed and version-controlled the exact same way obs1-5 already argued dashboards should be, and echoing k8s2-9's own GitOps pattern.

Logs and Traces in Kubernetes — A Brief Practical Note

Containers write logs to stdout/stderr by convention; a node-level agent — Promtail for Loki, or an OTel Collector deployed as a DaemonSet (k8s2-2's own one-pod-per-node pattern) — tails those logs and ships them centrally, automatically attaching pod, namespace, and container labels along the way. Traces work similarly: an OTel Collector, again commonly run as a DaemonSet or a sidecar, receives OTLP from instrumented pods and forwards it to Jaeger, with the same Kubernetes metadata attached automatically as span attributes. This is deliberately a light touch — the bulk of this chapter's genuinely new material is the metrics side (kube-state-metrics, the Operator, ServiceMonitors); logs and traces in Kubernetes are mostly Ch.7/8's own tools, deployed in a Kubernetes-shaped way.

Reports onExample question it answers
node_exporterThe underlying machineIs this node running out of memory?
kube-state-metricsKubernetes API object stateDoes this Deployment actually have as many ready replicas as it should?
kube-state-metrics + Alertmanager catches a real, common incident
A Deployment silently stuck at 2 of 5 replicas ready for an hour is invisible without an alert built specifically on kube_deployment_status_replicas_unavailable — the pods that are running might look perfectly healthy on their own, while the cluster quietly runs at a fraction of its intended capacity. This is exactly the kind of gap obs1-6's own alerting material, aimed at this specific metric, is built to close.
The Operator/ServiceMonitor pattern is genuinely more setup than one static config file
A single static prometheus.yml is simpler to reason about for a small cluster with few teams. The Prometheus Operator and ServiceMonitors earn their own added complexity specifically once there are enough services and teams that self-service, declarative scrape configuration actually starts paying for itself — not automatically, and not for every cluster, regardless of size.

Hands-On Exercises

Exercise 1

Explain, using a concrete example, the difference between what node_exporter would report and what kube-state-metrics would report for the same underlying incident — a pod repeatedly crashing and restarting.

📄 View solution
Exercise 2

Write a ServiceMonitor for a service named "inventory-api" with label app=inventory-api, scraping port "metrics" every 15 seconds, and explain what happens automatically once this object is applied to the cluster.

📄 View solution
Exercise 3

A small cluster with two services and one team is deciding between a single static prometheus.yml and the Prometheus Operator with ServiceMonitors. Recommend one, using this chapter's own warn-box as justification.

📄 View solution

Chapter 10 Quick Reference

  • Kubernetes' ephemeral pods break obs1-3's static target lists — this chapter is the real fix
  • node_exporter reports on the machine; kube-state-metrics reports on Kubernetes object state (desired vs. actual, the k8s1-2 reconciliation-loop theme made queryable)
  • The Prometheus Operator manages Prometheus declaratively via Kubernetes Custom Resources
  • A ServiceMonitor declares scrape intent per-service; the Operator reconfigures Prometheus live, automatically, with no manual reload
  • Logs/traces in Kubernetes: node-level DaemonSet agents (Promtail, OTel Collector) attach pod/namespace metadata automatically
  • kube-state-metrics + Alertmanager catches "stuck at N/M replicas ready" — invisible without a metric built specifically for it
  • The Operator/ServiceMonitor pattern is real added complexity — worth it at real scale, not automatically for every cluster