Un host, due carichi di lavoro e un requisito che li separa: un client di download che deve uscire da una VPN commerciale e un'interfaccia di amministrazione che deve continuare a usare la connessione dell'host. Installare il client VPN sull'host viola subito il requisito, perché entrambi i carichi condividono allora una sola uscita. Il modello che funziona davvero è spostare il tunnel nel suo container e lasciare che solo i carichi che ne hanno bisogno si uniscano allo spazio dei nomi di rete di quel container. Tutto il resto mantiene il percorso Docker ordinario, e i dettagli che seguono sono conseguenze di chi possiede lo spazio dei nomi.

Perché uno spazio dei nomi condiviso cambia le regole

Un container che si unisce allo spazio dei nomi di un altro non ottiene la propria pila di rete. Vede le stesse interfacce, la stessa tabella di routing e lo stesso loopback del container a cui si è unito, ed è proprio per questo che il modello è utile: il carico risolve e si connette normalmente, e il tunnel sottostante cattura il traffico senza che l'applicazione lo sappia. Il costo è che ogni impostazione di rete ha ora un solo proprietario, e il container che si unisce non lo è.

Quella regola di proprietà risponde alla maggior parte delle domande di configurazione prima ancora che vengano poste. Se un'impostazione vive nella pila di rete, appartiene al container laterale. Se descrive il processo, resta con il carico.

Il loopback è la parte che sorprende le persone. Dentro il container che si unisce, localhost si risolve nel loopback del container laterale, non in uno privato proprio, così un servizio che si lega a 127.0.0.1 aspettandosi isolamento ora condivide quell'indirizzo con il container del tunnel.

Pubblica le porte sul container che possiede lo spazio dei nomi

La mappatura delle porte appartiene al proprietario dello spazio dei nomi anche quando il processo in ascolto gira nell'altro container. Dichiara la mappatura sul container laterale e lascia che il carico mantenga intatta la propria configurazione di processo. Una mappatura sul servizio che si unisce non può avere effetto, che il motore la rifiuti o la ignori silenziosamente a seconda di come viene avviato il container, ed è per questo che un'interfaccia raggiungibile un attimo fa scompare appena si applica il modello.

services:
  gluetun:
    image: qmcgaw/gluetun
    cap_add: [NET_ADMIN]
    ports: ["8080:8080"]
  client-vpn:
    image: example/client
    network_mode: "service:gluetun"
  client-direct:
    image: example/client
    ports: ["8081:8080"]

Leggi quel blocco come tre decisioni invece di tre servizi. Il container laterale possiede il tunnel e la porta pubblicata; il client che si unisce non dichiara alcuna rete; il client diretto conserva una mappatura propria sulla rete predefinita. La capacità NET_ADMIN è ciò che permette al container laterale di creare interfacce e modificare rotte, ed è la ragione per cui questo container ha bisogno di più privilegi dei carichi che serve.

Il servizio che resta diretto conserva la propria rete

Il carico che non deve passare dal tunnel conserva il bridge predefinito o una rete definita dall'utente propria, con la propria porta pubblicata e la propria uscita. È tentante collegarlo alla rete del container laterale perché i due container possano parlarsi per nome, ma quel singolo passo sposta silenziosamente il suo traffico nel tunnel. Se devono raggiungersi, costruisci una rete definita dall'utente separata, collega entrambi ad essa e lascia il container laterale come unica via d'uscita.

Tieni separate le due domande: quali container possono raggiungersi e quale esce da dove. Fonderle è il modo più comune in cui questo progetto torna a essere una VPN per tutto l'host.

Una matrice dei guasti per la prima ora

La maggior parte dei primi tentativi fallisce in uno di quattro modi, e ciascuno ha una causa diversa. Controllali in questo ordine, perché i primi due spiegano quasi tutti i rapporti.

SymptomLikely cause
Web UI unreachable after the changePort mapping declared on the joining container instead of the sidecar
Both containers show the provider's exit addressThe direct service was attached to the sidecar network
Internal names stop resolvingResolver settings live on the host, not in the shared namespace
Health check fails but the app worksThe check probes localhost, which now means the sidecar

La quarta riga è quella che le persone diagnosticano erroneamente come bug dell'applicazione. Una sonda scritta contro il loopback proprio del carico ora sta testando il container del tunnel, quindi o fallisce o segnala un servizio completamente sbagliato.

Quando un solo nome host ha bisogno del tunnel

A volte un tunnel completo è troppo: un nome interno deve passare per una VPN aziendale mentre un socket locale o una connessione display continua a funzionare. Un tunnel completo nel container rompe quel percorso e tutto ciò che è indirizzato all'host, quindi instrada solo il prefisso che ne ha bisogno. Un wrapper di routing diviso attorno al client lo fa, inviando il nome host indicato attraverso il tunnel e lasciando intatta la rotta precedente per tutto il resto.

Scegli questo quando devi raggiungere un solo servizio e non stai cercando di spostare tutto il traffico del container. È uno strumento diverso dal container laterale e risponde a una domanda diversa.

Verifica, poi fai in modo che sopravviva a un riavvio

Chiedi a ogni container da quale indirizzo sembra provenire. Quello nel tunnel dovrebbe stampare l'indirizzo del provider e quello diretto l'uscita dell'host. Risposte identiche significano che il servizio diretto ha ereditato lo spazio dei nomi sbagliato o che una VPN a livello di host sta ancora catturando tutto, e queste due correzioni sono diverse. Esegui di nuovo il controllo dopo ogni modifica al compose, perché un solo blocco di servizio copiato basta a reintrodurre il problema.

Tre cose tendono a rompersi più avanti. Il DNS segue il proprietario dello spazio dei nomi, quindi le impostazioni di resolver e dominio di ricerca appartengono al container laterale e non all'host. Una VPN con inoltro di porte cambia la porta di ascolto alla riconnessione, quindi la porta inoltrata del provider e la porta di ascolto lato container devono essere riscritte nella configurazione del client o nella mappatura delle porte, di solito tramite un piccolo aggiornatore che legge l'API del provider. E qualsiasi sonda scritta contro localhost ora interroga il container del tunnel invece del carico.

Scrivi il modello, inclusi quale container possiede lo spazio dei nomi e quali porte gli appartengono. La persona successiva aggiungerà un servizio, copierà il blocco sbagliato e riprodurrà il primo guasto di questo articolo.

Articoli correlati