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:
- Selettore non matcha — la label sul namespace non combacia con
namespaceSelector→ i pod escono col nodeIP. - Nessun nodo assegnabile — nessun nodo ha la label
k8s.ovn.org/egress-assignable→statusvuoto, IP non assegnato. - Subnet mismatch — l’egressIP non è nella subnet della NIC del nodo → assegnazione fallisce.
- Nodo egress che flappa — nodo NotReady/drain → riassegnazione, traffico perso nel transitorio → errori intermittenti.
Diagnosi rapida
Sei su OVN o SDN?
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)
oc get egressipVista tabellare con IP + nodo assegnato:
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:
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):
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):
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):
oc get egressip -o json | jq -r '.items[] | "\(.metadata.name)\tselector=\(.spec.namespaceSelector.matchLabels)\tassigned=\(.status.items // [] | map("\(.egressIP)@\(.node)") | join(","))"'Nodi egress-assignable
oc get nodes -l k8s.ovn.org/egress-assignableSe non torna nulla → nessun nodo può ospitare egressIP: nessuno degli oggetti verrà assegnato. Marca un nodo:
oc label node <NODE> k8s.ovn.org/egress-assignable=""Rimuovere la label:
oc label node <NODE> k8s.ovn.org/egress-assignable-Match namespace ↔ selettore
Label attuali dei namespace target:
oc get ns <NS_A> <NS_B> <NS_C> --show-labelsVerifica che la label attesa dal selettore (es. eg-<nome>=enable) sia presente sul ns. Aggiungerla:
oc label ns <NS> eg-<nome>=enableElenco dei namespace che matchano una label specifica (conferma di chi è agganciato):
oc get ns -l eg-<nome>=enableAnalisi approfondita
YAML completo con status
oc get egressip <NAME> -o yamlBlocco 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:
oc get node <NODE> -o jsonpath='{.status.addresses}{"\n"}'E l’annotazione OVN con host-subnet / gateway del nodo:
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:
oc -n openshift-ovn-kubernetes logs -l app=ovnkube-node --tail=200 | grep -iE 'egressip|<EGRESS_IP>' | tail -40Il control-plane (cluster manager) decide le assegnazioni:
oc -n openshift-ovn-kubernetes logs -l app=ovnkube-control-plane --tail=300 | grep -iE 'egressip' | tail -40Nodi non sani che spiegano l’intermittenza
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.
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
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:
oc get netnamespace -o custom-columns='NS:.metadata.name,EGRESSIPS:.egressIPs'Egress IP disponibili per nodo:
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):
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=enablevseg-4b-corporatebanking=enablevsname=...) sono la causa numero uno di ns non agganciati. Adotta un pattern unico, es.eg-<progetto>=enable. - Un
EgressIPconnamespaceSelectorvuoto 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.