Alerting operativo — Query interattive
Alerting operativo — Query interattive
Query PromQL da usare interattivamente nella Console OpenShift (Observe → Metrics) o via oc exec sul pod Prometheus. Sono query “moderne” (allineate a cluster OCP 4.14+ con OVN-Kubernetes) per capire lo stato reale del cluster prima che qualcuno apra un ticket.
Non sono
PrometheusRule(alert autoconsistenti); sono query da tenere in una collezione personale — copia-incolla, aggiusta la finestra, valuta.
1. CPU throttling — il killer silenzioso
Il CPU throttling è la vera causa dietro molti “l’app è lenta” quando la CPU sembra “libera” sul monitoring. Un container con limits.cpu = 500m che serve un carico spike a 700m viene throttled dal cgroup e la latenza salta alle stelle, ma le metriche di usage dicono “50%“.
1.1 Top 20 container più throttled nell’ultima ora
topk(20, sum by (namespace, pod, container, node) ( rate(container_cpu_cfs_throttled_periods_total{container!="", container!="POD"}[1h]) / rate(container_cpu_cfs_periods_total{container!="", container!="POD"}[1h]) ) * on(pod, namespace) group_left(node) kube_pod_info) > 0.05Cosa mostra: percentuale di periodi CPU throttled. Se > 0.05 (5%) sei già in zona “il container sta soffrendo”. > 0.20 = grave.
Fix tipico: alzare limits.cpu. Regola pratica: limits.cpu = requests.cpu * 2 (QoS Burstable), oppure limits.cpu = requests.cpu (QoS Guaranteed, più costoso ma no throttling).
1.2 Namespace con più CPU throttling totale
topk(10, sum by (namespace) ( rate(container_cpu_cfs_throttled_seconds_total{container!="", container!="POD"}[1h]) ))Restituisce secondi/s di throttling per namespace. Utile per capire “quali applicazioni stanno effettivamente strette”.
2. Pending / Unschedulable pods
Pod che non partono mai perché lo scheduler non trova un node valido. Cause tipiche: overcommit, taint mancanti, nodeSelector troppo stretti.
2.1 Pod attualmente Pending
sum by (namespace, pod, reason) ( kube_pod_status_unschedulable) > 0Oppure via oc:
oc get pods -A --field-selector=status.phase=Pending \ -o custom-columns=NS:.metadata.namespace,POD:.metadata.name,\NODE:.spec.nodeName,\REASON:.status.conditions[0].message2.2 Pod Pending per motivo
sum by (namespace, reason) ( kube_pod_status_scheduled{condition="false"})reason tipici:
Unschedulable→ nessun node valido (vedi §2.3)SchedulerError→ scheduler in errore- Vuoto → pod appena creato, dagli tempo
2.3 Perché lo scheduler non trova posto
Manca in PromQL, va con oc:
oc describe pod -n <ns> <pod> | grep -A5 "Events:"
# Cerchi messaggi tipo:# - "0/6 nodes are available: 3 Insufficient cpu, 3 Insufficient memory"# - "node(s) had untolerated taint {node-role.kubernetes.io/master: true}"# - "node(s) didn't match node selector"3. Memory pressure a livello node
3.1 Node in MemoryPressure attualmente
kube_node_status_condition{condition="MemoryPressure", status="true"}3.2 Memory available per node
node_memory_MemAvailable_bytes / 1024 / 1024 / 1024Restituisce GiB disponibili per node. Se < 2 su node medi (32-64 GB) sei vicino al margine kubelet reserved (500 Mi hard-reserved by default).
3.3 Node con memory usage > 85%
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) > 0.853.4 Overcommit ratio (requests vs allocatable)
sum by (node) ( kube_pod_container_resource_requests{resource="memory"} * on(pod, namespace) group_left(node) kube_pod_info)/sum by (node) ( kube_node_status_allocatable{resource="memory"})> 0.95 = zona critica. > 1.0 = impossibile (scheduler dovrebbe averlo bloccato, se lo vedi c’è un bug o pod DaemonSet che non rispetta requests).
4. Disk pressure & filesystem
4.1 Node con disk usage > 80%
100 * ( 1 - ( node_filesystem_avail_bytes{fstype!~"tmpfs|devtmpfs|overlay",mountpoint="/"} / node_filesystem_size_bytes{fstype!~"tmpfs|devtmpfs|overlay",mountpoint="/"} )) > 804.2 Node con inode pressure
100 * ( 1 - ( node_filesystem_files_free{fstype!~"tmpfs|devtmpfs|overlay",mountpoint="/"} / node_filesystem_files{fstype!~"tmpfs|devtmpfs|overlay",mountpoint="/"} )) > 80Overlooked — cluster con molti container che scrivono lock/pid file possono esaurire gli inode prima del disco.
4.3 Node con /var/lib/containers pieno (image cache)
100 * ( 1 - ( node_filesystem_avail_bytes{mountpoint="/var/lib/containers"} / node_filesystem_size_bytes{mountpoint="/var/lib/containers"} )) > 85Se questa cresce, i pull di nuove immagini falliranno.
5. API server health
L’API server (kube-apiserver) è il collo di bottiglia più importante del control plane.
5.1 API server latency p99 nelle ultime 5 min
histogram_quantile(0.99, sum by (le, verb) ( rate(apiserver_request_duration_seconds_bucket{ verb!~"CONNECT|WATCH", subresource!~"log|exec|portforward" }[5m]) ))Restituisce p99 latency per verb (GET, POST, PUT, DELETE). Se > 1s per verb LIST significa cluster grande / etcd lento.
5.2 Error rate API server
sum by (verb, code) ( rate(apiserver_request_total{code=~"5.."}[5m]))5xx sull’API server. Deve essere ~0. Se non lo è, c’è un problema serio (etcd, cert, memory di kube-apiserver).
5.3 Request rate per resource
topk(10, sum by (resource, verb) ( rate(apiserver_request_total[5m]) ))Utile a capire “chi sta bombardando l’API”. A volte è un operator che pollera troppo aggressivo.
6. etcd health
etcd è il DB del control plane. Un etcd lento = cluster lento.
6.1 etcd fsync latency (write to disk)
histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[5m]))Se > 0.010 (10 ms) sei in zona rossa. Red Hat suggerisce < 10 ms per etcd sano. Cause tipiche di lentezza: disco lento, contention IO.
6.2 etcd backend commit latency
histogram_quantile(0.99, rate(etcd_disk_backend_commit_duration_seconds_bucket[5m]))Se > 0.025 (25 ms) c’è pressione IO su etcd.
6.3 etcd leader changes (dovrebbe essere ~0)
increase(etcd_server_leader_changes_seen_total[1h])Se > 0 nell’ultima ora, il quorum etcd è instabile. Cause: rete tra master lenta, un master sotto stress, o proprio problemi HW.
6.4 etcd DB size vs quota
etcd_mvcc_db_total_size_in_bytes / (1024 * 1024 * 1024)Se si avvicina alla quota (default 2 GB, spesso portata a 8 GB su OCP), etcd andrà in NOSPACE e il cluster diventa read-only.
7. OVN-Kubernetes network health
OpenShift 4.18 usa OVN-K di default. Query per sanità della SDN:
7.1 OVN pod restart nel control plane
sum by (pod, container) ( increase(kube_pod_container_status_restarts_total{ namespace="openshift-ovn-kubernetes" }[1h])) > 0I pod ovnkube-master, ovnkube-node, ovs-node non dovrebbero restartare in produzione. Se lo fanno, hai problemi di rete o memoria sul control plane.
7.2 OVN control plane latency
histogram_quantile(0.99, rate(ovnkube_master_pod_creation_latency_seconds_bucket[5m]))Latenza percepita quando OVN crea la network config per un nuovo pod. > 5s è sintomo di control plane satura.
7.3 Node OVN in errore
kube_pod_container_status_ready{ namespace="openshift-ovn-kubernetes", container="ovnkube-controller"} == 0Se qualche ovnkube-controller non è ready, i pod su quel node hanno rete parziale o assente.
8. Ingress / Router health
Il router OpenShift (basato su HAProxy) espone le app all’esterno. Se soffre lui, soffre tutto.
8.1 Router pod restart
sum by (pod, container, node) ( increase(kube_pod_container_status_restarts_total{ namespace="openshift-ingress", container="router" }[1h]) * on(pod, namespace) group_left(node) kube_pod_info) > 08.2 HTTP 5xx nel router negli ultimi 5 min
sum by (namespace, route, code) ( rate(haproxy_backend_http_responses_total{code="5xx"}[5m]))Filtra i backend che stanno restituendo errori 5xx (backend applicativo giù, non l’infrastruttura).
8.3 Router queue depth
haproxy_backend_current_queue{state="current"}Se il backend applicativo è lento, HAProxy accoda le connessioni. Coda > 0 sostenuta = throughput backend insufficiente.
9. Persistent Volumes
9.1 PV in stato Failed
kube_persistentvolume_status_phase{phase="Failed"} == 19.2 PVC in Pending
kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1Se un PVC resta Pending, il pod che lo usa non parte. Cause: StorageClass non esiste, CSI operator degraded, quota namespace superata.
9.3 PV con uso > 90% (predittivo prima che l’app si blocchi)
100 * ( 1 - ( kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes )) > 90Con nome PVC e namespace:
topk(20, 100 * ( 1 - ( kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes ) ))10. Cluster operator health
I cluster operator sono i “componenti auto-manutentivi” del cluster. Se anche uno solo va Degraded per troppo tempo, il cluster è a rischio upgrade.
10.1 Cluster operator non Available
cluster_operator_conditions{condition="Available", name!=""} == 010.2 Cluster operator Degraded
cluster_operator_conditions{condition="Degraded", name!=""} == 110.3 Cluster operator che stanno Progressing da troppo tempo
cluster_operator_conditions{condition="Progressing"} == 1Se un CO è Progressing da > 15 min in condizioni normali (fuori da upgrade), è bloccato. Vedi con oc describe co <name> cosa dice negli Events.
11. Query “state of the cluster” — 1 minute health check
Quando qualcuno chiede “come sta il cluster?”, queste 5 query in ordine ti danno una salute rapida:
# 1. Node non Readycount(kube_node_status_condition{condition="Ready", status="false"} == 1)
# 2. Pod non Running/Succeededcount(kube_pod_status_phase{phase!~"Running|Succeeded"} == 1)
# 3. Cluster operator Degradedcount(cluster_operator_conditions{condition="Degraded"} == 1)
# 4. Pod OOMKilled ultima oracount( kube_pod_container_status_last_terminated_reason{reason="OOMKilled"} == 1)
# 5. API server error ratesum(rate(apiserver_request_total{code=~"5.."}[5m]))Se tutte e 5 tornano 0 (o valori molto bassi), il cluster è in salute. Se una è alta, hai il punto d’attacco per l’investigazione.
Note operative
- Windows di tempo: query con
[5m]sono economiche, con[24h]costose. Non abusare di finestre lunghe su cluster grandi (rallenta Prometheus). by (label1, label2, ...)— sempre presente nelle aggregazioni: senza, PromQL somma tutto in un solo numero e perdi contesto.* on(pod, namespace) group_left(node) kube_pod_info— il pattern-oro per arricchire QUALUNQUE metrica pod-level con il node.- Salvare le query preferite — nella Console OpenShift, in Observe → Metrics, puoi salvare come “Named query” nei bookmark del browser. Utile.