Rete
Le metriche container_network_* sono raccolte da cAdvisor sulla network namespace del pod, quindi esistono solo sulla serie con container="". È l’unico caso in cui il filtro container!="" va omesso: usarlo restituisce una serie vuota.
| Triage | drop, OVN, ingress |
| Traffico pod · Traffico nodo | |
| Drop ed errori · Conntrack | |
| OVN-Kubernetes | |
| Ingress e router | |
| EgressIP | |
| Service Mesh | quando c’è OSSM |
| Verifica connettività · Alert |
Triage
T1. Pacchetti scartati
# pacchetti al secondotopk(20, sum by (namespace, pod) ( rate(container_network_receive_packets_dropped_total[5m]) + rate(container_network_transmit_packets_dropped_total[5m]) )) > 0T2. Componenti OVN non pronti
# elenco: ogni serie restituita soddisfa la condizionekube_pod_container_status_ready{namespace="openshift-ovn-kubernetes"} == 0T3. Route senza backend attivi
# elenco: ogni serie restituita soddisfa la condizionehaproxy_backend_up == 0Route esposta ma nessun pod pronto dietro: gli utenti vedono 503 e la causa è la readiness dei pod, non il router.
T4. 5xx dal router
# eventi al secondotopk(20, sum by (namespace, route) (rate(haproxy_backend_http_responses_total{code="5xx"}[5m]))) > 0T5. Conntrack vicino al limite
# conteggionode_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.80Sopra 0.80 le nuove connessioni iniziano a essere rifiutate in modo apparentemente casuale, e l’applicazione lo vede come timeout.
Traffico dei pod
Top per traffico in ingresso
# MiBtopk(20, sum by (namespace, pod) ( rate(container_network_receive_bytes_total{ namespace!~"kube-.*|openshift-.*|default" }[5m]) ) * on(namespace, pod) group_left(node) max by (namespace,pod,node) (kube_pod_info)) / 1024^2Top per traffico in uscita
# MiBtopk(20, sum by (namespace, pod) ( rate(container_network_transmit_bytes_total{ namespace!~"kube-.*|openshift-.*|default" }[5m]) ) * on(namespace, pod) group_left(node) max by (namespace,pod,node) (kube_pod_info)) / 1024^2Un pod specifico
# MiB · sostituisci $ns, $podsum by (pod) (rate(container_network_receive_bytes_total{namespace="$ns", pod=~"$pod.*"}[5m])) / 1024^2# MiB · sostituisci $ns, $podsum by (pod) (rate(container_network_transmit_bytes_total{namespace="$ns", pod=~"$pod.*"}[5m])) / 1024^2Per interfaccia
# MiB · sostituisci $ns, $podsum by (pod, interface) ( rate(container_network_receive_bytes_total{namespace="$ns", pod=~"$pod.*"}[5m])) / 1024^2Su pod con più interfacce (Multus), il label interface le separa. eth0 è la rete di default, net1 e successive sono le NetworkAttachmentDefinition.
Spike brevi
# MiBtopk(20, max_over_time( sum by (namespace, pod) ( rate(container_network_transmit_bytes_total{ namespace!~"kube-.*|openshift-.*|default" }[1m]) )[6h:1m] )) / 1024^2Finestra [1m] dentro una subquery a 6 ore: cattura i picchi che una rate([5m]) media via. È la query per identificare job notturni, sincronizzazioni verso sistemi esterni, dump.
Pacchetti al secondo
# pacchetti al secondotopk(20, sum by (namespace, pod) ( rate(container_network_receive_packets_total{ namespace!~"kube-.*|openshift-.*|default" }[5m]) ))Dimensione media del pacchetto
# byte al secondo · sostituisci $ns, $podrate(container_network_receive_bytes_total{namespace="$ns", pod=~"$pod.*"}[5m])/rate(container_network_receive_packets_total{namespace="$ns", pod=~"$pod.*"}[5m])Pacchetti sotto i 200 byte ad alta frequenza indicano protocolli chatty o mancanza di batching: costano CPU al kernel e al sidecar molto più del volume di dati. Il sintomo collaterale è un softirq alto sul nodo.
Sbilanciamento tra repliche
# MiB · sostituisci $ns, $workloadsum by (pod) ( rate(container_network_receive_bytes_total{namespace="$ns", pod=~"$workload-.*"}[5m])) / 1024^2Repliche dietro lo stesso Service devono ricevere traffico comparabile. Una a zero è fuori dagli endpoint (readiness fallita); una a 5× le altre indica sessioni sticky o un client che non rifà la risoluzione DNS.
Traffico per namespace
# MiBtopk(20, sum by (namespace) ( rate(container_network_transmit_bytes_total{ namespace!~"kube-.*|openshift-.*|default" }[5m]) )) / 1024^2Traffico dei nodi
Per nodo, aggregato dai pod
# MiBsum by (node) ( rate(container_network_receive_bytes_total[5m]) * on(namespace, pod) group_left(node) max by (namespace,pod,node) (kube_pod_info)) / 1024^2Sbilanciamenti forti tra nodi indicano che un workload ad alto traffico non è distribuito, oppure che quel nodo ospita l’ingress.
Interfacce fisiche
# MiBtopk(10, sum by (instance) ( rate(node_network_receive_bytes_total{device!~"lo|veth.*|ovn.*|br-.*|genev.*|tun.*"}[5m]) )) / 1024^2# MiBtopk(10, sum by (instance) ( rate(node_network_transmit_bytes_total{device!~"lo|veth.*|ovn.*|br-.*|genev.*|tun.*"}[5m]) )) / 1024^2Comprende tutto: traffico applicativo, storage, replica etcd, tunnel Geneve. Su nodi con una sola NIC condivisa tra dati e storage, la saturazione qui spiega latenze applicative altrimenti inspiegabili.
Saturazione della NIC
# byte al secondosum by (instance, device) ( rate(node_network_receive_bytes_total{device!~"lo|veth.*"}[5m])) * 8/(node_network_speed_bytes{device!~"lo|veth.*"} * 8)Frazione della banda nominale in uso. Sopra 0.70 sostenuto la NIC inizia a essere il collo di bottiglia.
MTU
# bytenode_network_mtu_bytes{device!~"lo|veth.*"}Un MTU disallineato tra nodi (o tra nodo e rete fisica) produce il sintomo peggiore da diagnosticare: le connessioni si stabiliscono, i pacchetti piccoli passano, e i trasferimenti grandi si bloccano. Su OVN-K con incapsulamento Geneve l’MTU dell’overlay è tipicamente 100 byte sotto quello fisico.
# numero di seriecount by (mtu) (node_network_mtu_bytes{device="ens192"})Più di un valore = disallineamento.
Drop ed errori
Drop a livello pod
# pacchetti al secondotopk(20, sum by (namespace, pod) ( rate(container_network_receive_packets_dropped_total{ namespace!~"kube-.*|openshift-.*|default" }[5m]) )) > 0# pacchetti al secondotopk(20, sum by (namespace, pod) ( rate(container_network_transmit_packets_dropped_total{ namespace!~"kube-.*|openshift-.*|default" }[5m]) )) > 0Deve essere zero. Drop in ricezione = buffer del socket pieno, l’applicazione non consuma abbastanza in fretta. Drop in trasmissione = coda dell’interfaccia satura.
Drop come frazione del traffico
# pacchetti al secondo · sostituisci $nssum by (namespace, pod) (rate(container_network_receive_packets_dropped_total{namespace=~"$ns"}[5m]))/sum by (namespace, pod) (rate(container_network_receive_packets_total{namespace=~"$ns"}[5m]))Sopra 0.001 (un pacchetto su mille) è già anomalo su rete interna.
Errori sui pod
# eventi al secondosum by (namespace, pod) ( rate(container_network_receive_errors_total[5m]) + rate(container_network_transmit_errors_total[5m])) > 0Errori sulle interfacce fisiche
# eventi al secondosum by (instance, device) (rate(node_network_receive_errs_total{device!~"lo|veth.*"}[5m])) > 0# eventi al secondosum by (instance, device) (rate(node_network_transmit_errs_total{device!~"lo|veth.*"}[5m])) > 0Errori sulle interfacce fisiche sono hardware o driver: cavo, SFP, MTU mismatch, offload buggato. Escalation infrastruttura, non applicativa.
Drop sulle interfacce fisiche
# pacchetti scartati al secondosum by (instance, device) (rate(node_network_receive_drop_total{device!~"lo|veth.*"}[5m])) > 0Coda di trasmissione
# numero di pacchetti in coda sull'interfaccianode_network_transmit_queue_length{device!~"lo|veth.*"}Conntrack
# conteggionode_nf_conntrack_entries / node_nf_conntrack_entries_limit# conteggiotopk(10, node_nf_conntrack_entries)# numero massimo di connessioni tracciabilinode_nf_conntrack_entries_limitIl conntrack tiene traccia di ogni connessione che attraversa il nodo. Quando si riempie, le nuove connessioni vengono scartate silenziosamente e l’applicazione le vede come timeout, in modo intermittente e apparentemente casuale.
Sintomo classico su nodi che ospitano molti pod con connessioni brevi: client HTTP senza keep-alive, scraper, health check frequenti.
oc debug node/$node -- chroot /host sysctl net.netfilter.nf_conntrack_maxoc debug node/$node -- chroot /host sysctl net.netfilter.nf_conntrack_countoc debug node/$node -- chroot /host dmesg | grep -i "conntrack table full"nf_conntrack: table full, dropping packet nel dmesg è la conferma definitiva.
OVN-Kubernetes
Su OCP 4.18 è la SDN di default.
Metriche disponibili sul tuo cluster
# numero di seriecount by (__name__) ({__name__=~"ovnkube.*|ovs_.*|ovn_.*"})Lancia questa per prima. I nomi delle metriche OVN cambiano tra minor di OCP, e copiare una query per una metrica che non esiste fa perdere tempo.
Restart dei componenti
# conteggio nell'ultima orasum by (pod, container) ( increase(kube_pod_container_status_restarts_total{ namespace="openshift-ovn-kubernetes" }[1h])) > 0ovnkube-node, ovnkube-control-plane, ovs-node non devono restartare in produzione. Se lo fanno, i pod sui nodi interessati hanno rete parziale o assente, e i sintomi applicativi che stai indagando sono conseguenza.
Componenti non ready
# elenco: ogni serie restituita soddisfa la condizionekube_pod_container_status_ready{namespace="openshift-ovn-kubernetes"} == 0Copertura del DaemonSet
# numero di pod del DaemonSetkube_daemonset_status_number_ready{namespace="openshift-ovn-kubernetes"}!=kube_daemonset_status_desired_number_scheduled{namespace="openshift-ovn-kubernetes"}Un nodo senza ovnkube-node ha rete rotta pur risultando Ready.
Latenza di configurazione della rete di un pod
# secondihistogram_quantile(0.99, sum by (le) (rate(ovnkube_controller_ready_duration_seconds_bucket[5m])))Tempo che OVN impiega a rendere operativa la rete di un pod appena schedulato. Oltre i 5 secondi il control plane è in affanno e i deploy diventano lenti in modo inspiegabile.
Elezione del leader
# conteggio nell'ultima oraincrease(ovnkube_controller_leader_changes_total[1h]) > 0Risorse consumate da OVN
# core CPUsum by (pod) ( rate(container_cpu_usage_seconds_total{ namespace="openshift-ovn-kubernetes", container!="", container!="POD" }[5m]))# MiBsum by (pod) ( container_memory_working_set_bytes{ namespace="openshift-ovn-kubernetes", container!="", container!="POD" }) / 1024^2Su cluster grandi ovnkube-node può consumare parecchia memoria: cresce con il numero di pod, servizi e NetworkPolicy. Un OOM di ovnkube-node porta giù la rete del nodo.
Errori OVS
# eventi al secondosum by (instance) (rate(ovs_vswitchd_netlink_overflow_total[5m])) > 0Flow installati
# numero di flow installati nel datapathovs_vswitchd_dp_flows_totalUn numero di flow che cresce senza sosta indica NetworkPolicy troppo granulari o un leak nel datapath.
Comandi
oc get pods -n openshift-ovn-kubernetes -o wideoc get ds -n openshift-ovn-kubernetes
# Log del controller su un nodoPOD=$(oc get pods -n openshift-ovn-kubernetes -l app=ovnkube-node --field-selector spec.nodeName=$node -o name | head -1)oc logs -n openshift-ovn-kubernetes $POD -c ovnkube-controller --tail=100
# Database OVN (sui nodi del control plane)oc rsh -n openshift-ovn-kubernetes -c northd $(oc get pods -n openshift-ovn-kubernetes -l app=ovnkube-control-plane -o name | head -1) \ ovn-nbctl show 2>/dev/null | head -40
# NetworkPolicy di un namespaceoc get networkpolicy -n $nsoc describe networkpolicy -n $nsIngress e router
Il router OpenShift è basato su HAProxy. Se soffre lui, soffre tutto ciò che è esposto.
Restart del router
# conteggio nell'ultima orasum by (pod, container) ( increase(kube_pod_container_status_restarts_total{ namespace="openshift-ingress", container="router" }[1h])) > 0Backend senza server attivi
# elenco: ogni serie restituita soddisfa la condizionehaproxy_backend_up == 0Route esposta, nessun pod pronto dietro. Gli utenti ricevono 503 e la causa è la readiness dei pod applicativi, non il router. È la distinzione che chiude più in fretta le segnalazioni di irraggiungibilità.
5xx per route
# eventi al secondotopk(20, sum by (namespace, route) ( rate(haproxy_backend_http_responses_total{code="5xx"}[5m]) )) > 0I 5xx contati qui sono generati dal backend applicativo, non da HAProxy. Un 503 di HAProxy stesso (nessun endpoint) si vede con la query precedente.
Distribuzione dei codici di risposta
# eventi al secondosum by (code) (rate(haproxy_backend_http_responses_total[5m]))# eventi al secondo · sostituisci $nssum by (namespace, route, code) ( rate(haproxy_backend_http_responses_total{namespace="$ns"}[5m]))Tasso di errore per route
# eventi al secondosum by (namespace, route) (rate(haproxy_backend_http_responses_total{code=~"5xx"}[5m]))/sum by (namespace, route) (rate(haproxy_backend_http_responses_total[5m]))Coda del backend
# numero di richieste in codatopk(20, haproxy_backend_current_queue) > 0HAProxy accoda quando i backend non tengono il ritmo. Coda sostenuta = throughput applicativo insufficiente o maxconn troppo basso.
Sessioni attive
# numero di sessioni attivesum by (pod) (haproxy_frontend_current_sessions)# percentuale 0-100 delle sessioni disponibili in uso100 * ( sum by (pod) (haproxy_frontend_current_sessions) / sum by (pod) (haproxy_frontend_limit_sessions))Tempo di risposta del backend
# secondihaproxy_backend_response_latency_average_seconds# seconditopk(20, haproxy_backend_connect_latency_average_seconds) > 0.1Latenza di connessione alta significa che il router fatica a raggiungere i pod: rete, o pod sovraccarichi che non accettano connessioni.
Connessioni rifiutate
# connessioni rifiutate al secondosum by (pod) (rate(haproxy_frontend_connections_denied_total[5m])) > 0Numero di route
# numero di seriecount(kube_service_info{namespace="openshift-ingress"})# numero di route per IngressControllersum by (name) (route_metrics_route_type)Oltre alcune migliaia di route per IngressController, il reload di HAProxy diventa costoso e ogni modifica a una route provoca un blip su tutte le altre. La soluzione è lo sharding per label.
oc get ingresscontroller -n openshift-ingress-operatoroc get routes -A --no-headers | wc -loc get routes -A -o json | jq -r '.items[] | .spec.host' | awk -F. '{print $NF}' | sort | uniq -cReload di HAProxy
# eventi al secondorate(haproxy_process_reloads_total[5m])Un tasso di reload alto significa che le route cambiano continuamente: qualcosa sta ricreando oggetti in loop.
EgressIP
oc get egressipoc get cloudprivateipconfigoc describe egressip <nome> | sed -n '/Status:/,$p'oc get nodes -l k8s.ovn.org/egress-assignableNamespace e pod coinvolti
# numero di seriecount by (namespace) (kube_pod_labels{label_egress_group!=""})Il selettore effettivo dipende da come è configurata la EgressIP: può essere per namespace (namespaceSelector) o per pod (podSelector).
oc get egressip <nome> -o jsonpath='{.spec}' | jqoc get ns -l <label-del-namespaceSelector>Verifica dell’IP sorgente effettivo
oc rsh -n $ns $pod curl -s --max-time 5 https://ifconfig.meSu cluster air-gapped serve un endpoint interno che rifletta l’IP sorgente. In alternativa, dal lato del sistema di destinazione: guardare i log di connessione e verificare che l’IP visto sia quello dell’EgressIP e non quello del nodo.
Un failover di EgressIP produce interruzioni brevi verso i sistemi esterni, che l’applicazione vede come connection reset senza nessuna traccia lato Kubernetes. Se il sintomo è intermittente e coincide con manutenzioni sui nodi egress-assignable, è quello.
# Su quale nodo è assegnato l'IP adessooc get egressip <nome> -o jsonpath='{.status.items}' | jq
# Storico degli spostamentioc get events -A --field-selector reason=EgressIPAssigned --sort-by=.lastTimestamp | tailService Mesh
Se il namespace ha injection, le metriche di Envoy danno molto più di container_network_*: codici di risposta, servizio di destinazione, latenza per percentile.
Metriche disponibili
# numero di seriecount by (__name__) ({__name__=~"istio_.*"})Richieste per servizio
# eventi al secondo · sostituisci $nssum by (destination_service_name, response_code) ( rate(istio_requests_total{destination_workload_namespace="$ns"}[5m]))Tasso di errore
# eventi al secondo · sostituisci $nssum by (destination_service_name) ( rate(istio_requests_total{destination_workload_namespace="$ns", response_code=~"5.."}[5m]))/sum by (destination_service_name) ( rate(istio_requests_total{destination_workload_namespace="$ns"}[5m]))Latenza per percentile
# millisecondi · sostituisci $nshistogram_quantile(0.99, sum by (le, destination_service_name) ( rate(istio_request_duration_milliseconds_bucket{destination_workload_namespace="$ns"}[5m]) ))Chi chiama chi
# eventi al secondo · sostituisci $nssum by (source_workload, destination_service_name) ( rate(istio_requests_total{destination_workload_namespace="$ns"}[5m]))È l’informazione che container_network_* non può dare: la topologia reale delle chiamate. Serve per capire quale dipendenza sta causando il degrado.
Flag di risposta di Envoy
# eventi al secondo · sostituisci $nssum by (response_flags, destination_service_name) ( rate(istio_requests_total{destination_workload_namespace="$ns", response_flags!="-"}[5m]))response_flags | Significato |
|---|---|
UF | upstream connection failure: il backend non risponde |
UO | upstream overflow: circuit breaker scattato |
URX | superato il limite di retry |
UT | upstream timeout |
NR | nessuna route configurata |
DC | downstream connection termination: il client ha chiuso |
UO è quello che si diagnostica peggio senza queste metriche: il circuit breaker della DestinationRule scatta e le richieste vengono rifiutate dal sidecar prima di raggiungere l’applicazione, che quindi nei suoi log non vede nulla.
Consumo dei sidecar
# GiBsum by (namespace) ( container_memory_working_set_bytes{container="istio-proxy"}) / 1024^3# core CPUsum by (namespace) ( rate(container_cpu_usage_seconds_total{container="istio-proxy"}[5m]))Un istio-proxy che consuma molta memoria riceve troppi endpoint da istiod: si limita con una risorsa Sidecar che restringe la visibilità del namespace.
Verifica della connettività
Le metriche dicono quanto traffico passa, non se una destinazione è raggiungibile. Per quello servono i comandi.
NS=<namespace>; POD=<pod>
# Risoluzione DNSoc rsh -n $NS $POD getent hosts <host>oc rsh -n $NS $POD cat /etc/resolv.conf
# Porta TCP aperta (senza installare nulla)oc rsh -n $NS $POD timeout 5 bash -c "</dev/tcp/<host>/<porta>" && echo OPEN || echo CLOSED
# Con debug pod se il container è minimaleoc debug -n $NS pod/$POD -- sh -c 'timeout 5 bash -c "</dev/tcp/<host>/<porta>" && echo OPEN || echo CLOSED'
# Connessioni aperte, con processooc rsh -n $NS $POD ss -tnp
# Conteggio per statooc rsh -n $NS $POD ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
# MTU effettivo dell'interfacciaoc rsh -n $NS $POD ip link show eth0
# Endpoint dietro un Serviceoc get endpointslice -n $NS -l kubernetes.io/service-name=<svc>
# NetworkPolicy applicabilioc get networkpolicy -n $NS -o yamlMolte connessioni in TIME_WAIT non sono un problema. Molte in CLOSE_WAIT sì: l’applicazione non chiude i socket, ed è un file descriptor leak che porterà a Too many open files.
Approfondimento sui casi con mesh ed EgressIP: Test di connettività da pod.
Limiti delle metriche di rete in container
Va detto, perché evita di cercare risposte dove non ci sono:
- Non c’è latenza. cAdvisor conta byte e pacchetti, non tempi di round-trip. Per la latenza servono le metriche applicative o quelle di Envoy.
- Non c’è la destinazione. Da
container_network_*non si può sapere con chi sta parlando un pod. Servono le metriche della mesh, i NetFlow di OVN, oss -tnpdal pod. - Il traffico host-network non compare. I pod con
hostNetwork: trueusano l’interfaccia del nodo: cercali innode_network_*. - Le NetworkPolicy non hanno metriche di drop. Un pacchetto bloccato da una policy semplicemente non arriva, e non compare da nessuna parte. La verifica è per esclusione.
Alert
apiVersion: monitoring.coreos.com/v1kind: PrometheusRulemetadata: name: network-health-custom namespace: openshift-monitoring labels: role: alert-rulesspec: groups: - name: network.pod rules: - alert: PodPacketsDropped expr: | sum by (namespace, pod) ( rate(container_network_receive_packets_dropped_total[5m]) + rate(container_network_transmit_packets_dropped_total[5m]) ) > 1 for: 15m labels: severity: warning annotations: summary: "{{ $labels.pod }} ({{ $labels.namespace }}): {{ $value | printf \"%.1f\" }} pacchetti/s scartati"
- name: network.node rules: - alert: NodeConntrackNearlyFull expr: node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.80 for: 15m labels: severity: warning annotations: summary: "{{ $labels.instance }}: conntrack all'{{ $value | humanizePercentage }}" description: "Le nuove connessioni verranno scartate in modo intermittente e l'applicazione le vedrà come timeout."
- alert: NodeNICErrors expr: | sum by (instance, device) ( rate(node_network_receive_errs_total{device!~"lo|veth.*"}[5m]) + rate(node_network_transmit_errs_total{device!~"lo|veth.*"}[5m]) ) > 0 for: 15m labels: severity: warning annotations: summary: "{{ $labels.instance }} {{ $labels.device }}: errori sull'interfaccia fisica" description: "Hardware o driver: cavo, SFP, MTU mismatch, offload. Escalation infrastruttura."
- name: network.ovn rules: - alert: OVNComponentRestarting expr: | increase(kube_pod_container_status_restarts_total{ namespace="openshift-ovn-kubernetes" }[1h]) > 0 labels: severity: critical annotations: summary: "{{ $labels.pod }} in openshift-ovn-kubernetes riavviato" description: "I pod sui nodi interessati possono avere rete parziale o assente."
- alert: OVNDaemonSetIncomplete expr: | kube_daemonset_status_number_ready{namespace="openshift-ovn-kubernetes"} != kube_daemonset_status_desired_number_scheduled{namespace="openshift-ovn-kubernetes"} for: 15m labels: severity: critical annotations: summary: "{{ $labels.daemonset }}: manca su alcuni nodi" description: "Un nodo senza ovnkube-node ha rete rotta pur risultando Ready."
- name: network.ingress rules: - alert: RouteBackendDown expr: haproxy_backend_up == 0 for: 10m labels: severity: critical annotations: summary: "Route {{ $labels.route }} ({{ $labels.namespace }}): nessun backend attivo" description: "Gli utenti ricevono 503. La causa è la readiness dei pod, non il router."
- alert: RouteHighErrorRate expr: | sum by (namespace, route) (rate(haproxy_backend_http_responses_total{code="5xx"}[5m])) / sum by (namespace, route) (rate(haproxy_backend_http_responses_total[5m])) > 0.05 for: 10m labels: severity: warning annotations: summary: "Route {{ $labels.route }}: {{ $value | humanizePercentage }} di risposte 5xx" description: "Errori generati dal backend applicativo, non dal router."
- alert: RouterQueueGrowing expr: haproxy_backend_current_queue > 10 for: 15m labels: severity: warning annotations: summary: "Route {{ $labels.route }}: {{ $value }} richieste in coda" description: "Il backend non tiene il ritmo. Throughput insufficiente o maxconn troppo basso."Soglie di riferimento
| Metrica | Sano | Attenzione | Critico |
|---|---|---|---|
| Drop pacchetti | 0 | > 0 | > 0.1% del traffico |
| Errori NIC | 0 | > 0 | > 0 |
| Conntrack | < 50% | 50 – 80% | > 80% |
| Saturazione NIC | < 50% | 50 – 70% | > 70% |
| 5xx per route | < 0.1% | 0.1 – 1% | > 5% |
| Coda HAProxy | 0 | 1 – 10 | > 10 |
| Latenza connect HAProxy | < 10 ms | 10 – 100 ms | > 100 ms |
| Restart componenti OVN | 0 | > 0 | > 0 |
Vedi anche
- Test di connettività da pod
- Pod / Container — traffico del singolo pod
- Nodo — interfacce e softirq
- Control plane — API server e cluster operator di rete