L'host naviga attraverso il tunnel e il container accanto non raggiunge nulla. Pubblicare una porta da un container che esegue il proprio client VPN è peggio: la richiesta arriva e la risposta non esce mai. Entrambe sono decisioni di routing sull'host, e Docker è solo il messaggero.

Tre domande stabiliscono quale dei due casi hai davanti, e richiedono circa un minuto.

Due guasti che si presentano allo stesso modo

Il primo è un problema del percorso di ritorno. La porta pubblicata viene tradotta nel container, la richiesta arriva e la risposta viene instradata tramite la route predefinita dell'host, che il client OpenVPN ha puntato su tun0. La risposta parte da un indirizzo che il peer remoto non si aspetta, e viene scartata. Il secondo è una collisione di prefissi: il bridge predefinito di Docker possiede 172.17.0.0/16 e un tunnel aziendale spinge lo stesso intervallo.

Uno si corregge con una tabella di routing, l'altro rinumerando un bridge. Modificare prima di sapere quale sia quale è il modo di rompere un container che funzionava.

Decidi con tre domande

Domanda uno: il guasto sparisce quando fermi la VPN? Se tutto funziona a tunnel abbassato, sospetta il percorso di ritorno. Domanda due: ip route show table all elenca lo stesso prefisso due volte, una su un bridge e una su tun0? È quella la collisione. Domanda tre: l'indirizzo colpito è un container, un ospite NAT o un ospite in bridge?

La terza domanda conta perché ognuno ha una correzione corretta diversa, e applicare la correzione del container a un ospite libvirt spreca una serata.

ip route
ip route show table all | grep -E '172\.1[7-9]|10\.8'
docker network inspect bridge --format '{{.IPAM.Config}}'

Percorso di ritorno: una tabella per un indirizzo di origine

Quando il traffico del container deve uscire dall'interfaccia fisica mentre l'host stesso usa il tunnel, il routing basato sull'origine è la modifica più piccola. Aggiungi una regola che corrisponda all'indirizzo del container e inviala a una tabella dedicata. Nient'altro sull'host si sposta.

ip rule add from 172.22.0.3 lookup 10
ip route add default via 172.22.0.1 table 10

Ogni pacchetto la cui origine è quell'indirizzo consulta prima la tabella 10, e la tabella 10 lo invia al gateway del bridge invece che al tunnel.

Verifica con ip route get 1.1.1.1 from 172.22.0.3. La risposta deve nominare l'interfaccia del bridge, non tun0. Le regole aggiunte così spariscono al riavvio, quindi mettile nell'unit o nell'hook di rete che possiede il container.

Lo stesso schema funziona per un container WireGuard, dove anche il percorso di risposta richiede una regola esplicita.

Collisione di prefissi: rinumerare il bridge

Una tabella di routing invia un prefisso in un solo posto. Se la VPN spinge 172.17.0.0/16 mentre il bridge di Docker è già lì, vince la metrica più bassa: Docker installa la sua route connessa con metrica 0, e la route spinta arriva a 50. Il tunnel sembra allora rotto mentre Docker continua a funzionare, o il contrario, secondo l'ordine di installazione. Rinumerare il bridge invece di combattere con la metrica.

{
  "bip": "10.200.0.1/24",
  "default-address-pools": [{"base": "10.201.0.0/16", "size": 24}]
}

Riavvia Docker dopo la modifica e ricrea le reti costruite con il pool vecchio. Cambiare la metrica sposta solo il conflitto al prossimo avvio.

Le VM richiedono ancora un'altra risposta

Un ospite libvirt sulla rete NAT predefinita eredita il routing dell'host e smette di raggiungere l'esterno quando il tunnel dell'host possiede la route predefinita. Passare l'ospite a un dispositivo in bridge o macvtap gli dà il proprio percorso sulla rete fisica. In virt-manager aggiungi hardware, scegli Network, imposta l'origine sul dispositivo host macvtap, mantieni virtio come modello, poi disattiva la vecchia interfaccia NAT.

Un ospite macvtap di solito non riesce a raggiungere il proprio host. È un comportamento atteso e non un guasto, e appartiene alla nota che lasci.

Per un ospite che ha bisogno solo della LAN dell'host, il client del fornitore può avere l'interruttore mancante: con Mullvad, mullvad lan set allow ripristina la raggiungibilità locale senza toccare libvirt. E quando un container deve essere raggiungibile solo attraverso il tunnel, lega la porta pubblicata all'indirizzo del tunnel, -p 10.8.0.5:8080:8080, invece di pubblicarla su ogni indirizzo.

Articoli correlati