Skip to content

EgressIP Troubleshooting (OVN-Kubernetes)

EgressIP fa uscire il traffico dei pod di uno o più namespace con un IP sorgente fisso e prevedibile, invece del nodeIP. Serve quando un backend esterno (es. core banking) accetta connessioni solo da IP autorizzati a firewall. Questa pagina copre OVN-Kubernetes; per OpenShiftSDN (legacy) vedi la sezione in fondo.

Modello

Su OVN l’oggetto è cluster-scoped: EgressIP. Ogni oggetto ha uno o più egressIPs e un namespaceSelector (opzionale podSelector). OVN assegna ciascun IP a un nodo marcato egress-assignable, che diventa il punto di uscita (ARP/GARP dell’IP su quella NIC). Se il nodo cade, OVN riassegna l’IP a un altro nodo assegnabile.

pod (ns con label matchata) ──▶ nodo egress-assignable ──▶ esterno [src IP = egressIP]

I punti di rottura tipici, in ordine di frequenza:

  1. Selettore non matcha — la label sul namespace non combacia con namespaceSelector → i pod escono col nodeIP.
  2. Nessun nodo assegnabile — nessun nodo ha la label k8s.ovn.org/egress-assignablestatus vuoto, IP non assegnato.
  3. Subnet mismatch — l’egressIP non è nella subnet della NIC del nodo → assegnazione fallisce.
  4. Nodo egress che flappa — nodo NotReady/drain → riassegnazione, traffico perso nel transitorio → errori intermittenti.

Diagnosi rapida

Sei su OVN o SDN?

Terminal window
oc get network.operator cluster -o jsonpath='{.spec.defaultNetwork.type}{"\n"}'

OVNKubernetes → usa questa pagina. OpenShiftSDN → salta alla sezione SDN.

Stato di tutti gli EgressIP (assegnato o no)

Terminal window
oc get egressip

Vista tabellare con IP + nodo assegnato:

Terminal window
oc get egressip -o custom-columns='NAME:.metadata.name,EGRESSIPS:.spec.egressIPs,ASSIGNED_NODE:.status.items[*].node,ASSIGNED_IP:.status.items[*].egressIP'

Se status.items è vuoto per un oggetto → l’IP non è assegnato a nessun nodo: causa in #2 o #3.

Selettori di ogni EgressIP (matchLabels)

One-liner jsonpath — matchLabels di namespace e pod:

Terminal window
oc get egressip -o jsonpath='{range .items[*]}{.metadata.name}{"\tnsSelector="}{.spec.namespaceSelector.matchLabels}{"\tpodSelector="}{.spec.podSelector.matchLabels}{"\n"}{end}'

Versione jq robusta ai null (non crasha su EgressIP senza selettore):

Terminal window
oc get egressip -o json | jq -r '.items[] | [.metadata.name, (.spec.egressIPs|join(",")), ((.spec.namespaceSelector.matchLabels // {})|to_entries|map("\(.key)=\(.value)")|join(",")), ((.spec.podSelector.matchLabels // {})|to_entries|map("\(.key)=\(.value)")|join(","))] | @tsv'

Copre anche matchExpressions (se non usi matchLabels):

Terminal window
oc get egressip -o jsonpath='{range .items[*]}{.metadata.name}{"\tnsLabels="}{.spec.namespaceSelector.matchLabels}{" nsExpr="}{.spec.namespaceSelector.matchExpressions}{"\tpodLabels="}{.spec.podSelector.matchLabels}{" podExpr="}{.spec.podSelector.matchExpressions}{"\n"}{end}'

Selettore + IP + nodo assegnato in una riga (per correlare selettore e assegnazione):

Terminal window
oc get egressip -o json | jq -r '.items[] | "\(.metadata.name)\tselector=\(.spec.namespaceSelector.matchLabels)\tassigned=\(.status.items // [] | map("\(.egressIP)@\(.node)") | join(","))"'

Nodi egress-assignable

Terminal window
oc get nodes -l k8s.ovn.org/egress-assignable

Se non torna nulla → nessun nodo può ospitare egressIP: nessuno degli oggetti verrà assegnato. Marca un nodo:

Terminal window
oc label node <NODE> k8s.ovn.org/egress-assignable=""

Rimuovere la label:

Terminal window
oc label node <NODE> k8s.ovn.org/egress-assignable-

Match namespace ↔ selettore

Label attuali dei namespace target:

Terminal window
oc get ns <NS_A> <NS_B> <NS_C> --show-labels

Verifica che la label attesa dal selettore (es. eg-<nome>=enable) sia presente sul ns. Aggiungerla:

Terminal window
oc label ns <NS> eg-<nome>=enable

Elenco dei namespace che matchano una label specifica (conferma di chi è agganciato):

Terminal window
oc get ns -l eg-<nome>=enable

Analisi approfondita

YAML completo con status

Terminal window
oc get egressip <NAME> -o yaml

Blocco status.items[] = fonte di verità su quale IP è su quale nodo. Se assente/parziale, l’assegnazione non è avvenuta.

Subnet check

L’egressIP deve stare nella subnet della NIC primaria del nodo assegnabile. Confronta con:

Terminal window
oc get node <NODE> -o jsonpath='{.status.addresses}{"\n"}'

E l’annotazione OVN con host-subnet / gateway del nodo:

Terminal window
oc get node <NODE> -o jsonpath='{.metadata.annotations.k8s\.ovn\.org/node-primary-ifaddr}{"\n"}'

Log OVN per riassegnazioni / errori

Eventi di assegnazione EgressIP sui nodi:

Terminal window
oc -n openshift-ovn-kubernetes logs -l app=ovnkube-node --tail=200 | grep -iE 'egressip|<EGRESS_IP>' | tail -40

Il control-plane (cluster manager) decide le assegnazioni:

Terminal window
oc -n openshift-ovn-kubernetes logs -l app=ovnkube-control-plane --tail=300 | grep -iE 'egressip' | tail -40

Nodi non sani che spiegano l’intermittenza

Terminal window
oc get nodes | grep -iE 'NotReady|SchedulingDisabled'

Un nodo egress che flappa causa riassegnazioni e perdita di connessioni nel transitorio → errori intermittenti verso il backend esterno.

Verifica end-to-end

Da quale IP escono davvero i pod

Il test che chiude la diagnosi: fai uscire un pod del namespace verso un echo che rimanda l’IP sorgente osservato. Sostituisci <ECHO_URL> con un endpoint raggiungibile che riflette l’IP client.

Terminal window
oc -n <NS> debug -it <POD> --image=nicolaka/netshoot -- bash -c 'for i in 1 2 3 4 5; do curl -s --max-time 5 <ECHO_URL> || echo TIMEOUT; done'
  • Ritorna sempre l’egressIP atteso → egress OK.
  • Alterna egressIP e nodeIP, o egressIP e TIMEOUT → egress intermittente (nodo che flappa o riassegnazioni).
  • Ritorna il nodeIP → il pod non è agganciato all’egress (selettore/label).

Reachability + latenza verso il backend esterno

Terminal window
oc -n <NS> debug -it <POD> --image=nicolaka/netshoot -- bash -c 'for i in $(seq 1 10); do time nc -zw5 <HOST_ESTERNO> <PORTA>; done'

Timeout intermittenti qui, correlati a un tasso di errore percentuale nel service mesh, sono la firma di un egress degradato.

OpenShiftSDN (legacy)

Su SDN non esiste l’oggetto EgressIP cluster-scoped: l’egress si configura sul NetNamespace (automatic) o su HostSubnet (manual).

Egress IP per namespace:

Terminal window
oc get netnamespace -o custom-columns='NS:.metadata.name,EGRESSIPS:.egressIPs'

Egress IP disponibili per nodo:

Terminal window
oc get hostsubnet -o custom-columns='NODE:.metadata.name,HOSTIP:.hostIP,EGRESSCIDRS:.egressCIDRs,EGRESSIPS:.egressIPs'

Assegnare un egress IP a un namespace (automatic assignment, l’IP deve essere in un egressCIDRs di un nodo):

Terminal window
oc patch netnamespace <NS> --type=merge -p '{"egressIPs":["<IP>"]}'

Note di gestione

  • I nomi degli oggetti e gli schemi di label vanno standardizzati: selettori incoerenti (0p-admintool=enable vs eg-4b-corporatebanking=enable vs name=...) sono la causa numero uno di ns non agganciati. Adotta un pattern unico, es. eg-<progetto>=enable.
  • Un EgressIP con namespaceSelector vuoto non matcha nessun namespace: è un oggetto orfano, va corretto o rimosso.
  • Assegnare più IP allo stesso oggetto distribuisce l’uscita su più nodi (HA); assicurati che ci siano almeno 2 nodi egress-assignable.