Contenidor Docker inaccessible a la VPN? Compareu les subxarxes
Docker assigna una subxarxa que la VPN també reclama. Compareu els dos plans d'adreces i trieu una reparació que sobrevisqui a una reconnexió.
Els contenidors responen a la LAN de l'oficina i deixen de respondre en el moment que es connecta la VPN de l'empresa. Res del contenidor no ha canviat: ni reinici, ni actualització d'imatge, ni edició de configuració. El que ha canviat és la taula d'encaminament de l'amfitrió, on una ruta que ha afegit el túnel ara cobreix l'adreça que Docker va assignar. Abans d'editar una subxarxa o demanar una exclusió de la VPN, poseu els dos plans d'adreces l'un al costat de l'altre, perquè les reparacions costen quantitats de temps molt diferents.
Llegiu la ruta abans de canviar la configuració
Comenceu per la xarxa que Docker ha construït realment. El bloc IPAM és el pla d'adreces, i la subxarxa és la línia que importa:
docker network inspect project_default --format '{{json .IPAM.Config}}'
# [{"Subnet":"172.18.0.0/16","Gateway":"172.18.0.1"}]Compose assigna per defecte una /16 a cada projecte nou, així que dos serveis poden seure dins d'un rang de 65,536 adreces. Aquesta amplada és la raó per la qual els solapaments són habituals: una /16 triada a l'atzar és prou gran per engolir un lloc al qual arribeu pel túnel, i ningú no se n'adona fins que el túnel s'aixeca.
A continuació compareu la selecció de ruta per a una adreça de contenidor, un cop amb el túnel baixat i un cop amb el túnel pujat:
ip route get 172.18.0.7
# 172.18.0.7 dev br-3f2a9c src 172.18.0.1Dues formes de resposta porten a llocs diferents. Si la sortida anomena tun0, wg0 o un altre dispositiu de túnel, un prefix de VPN és com a mínim tan específic com la ruta del pont i el paquet no arriba mai al contenidor. Si encara anomena el pont, l'amfitrió pot arribar al contenidor, i la vostra fallada és el filtratge, el DNS o un camí de retorn que falla només en una direcció.
Per què una col·lisió de /16 és fàcil de trobar
Docker treu les xarxes de pont dels conjunts privats, i el conjunt per defecte surt del bloc 172.16.0.0/12 en talls de /16. Les xarxes corporatives sovint utilitzen el mateix espai privat, i una VPN d'accés remot empeny aquests prefixos a cada client que es connecta. Quan tots dos costats creuen que posseeixen 172.18.0.0/16, una taula d'encaminament conté dues afirmacions contradictòries.
La longitud del prefix decideix el guanyador, no l'ordre en què apareixen les rutes. Un túnel que empeny 10.0.0.0/8 no guanya una ruta de pont 172.18.0.0/16, perquè /8 és menys específic. Un túnel que empeny 172.18.0.0/16, o 172.18.5.0/24 a dins, sí que guanya. Per això un portàtil funciona a la xarxa de l'oficina i falla al Wi-Fi de l'hotel amb la mateixa VPN: el client rep prefixos diferents.
La mateixa taula governa l'altra direcció. Un contenidor que necessita un amfitrió intern a 10.8.4.20 envia el paquet a la seva porta d'enllaç de pont, i l'amfitrió llavors l'encamina cap al túnel. Aquest camí normalment funciona perquè l'amfitrió fa la NAT, però falla quan el costat corporatiu només accepta l'adreça VPN del portàtil, o quan el filtratge de camí invers descarta la resposta asimètrica.
Compareu les tres reparacions
Només hi ha tres sortides, i difereixen en qui les ha d'aprovar i què es trenca mentre n'apliqueu una.
| Repair | Who owns it | What it costs |
|---|---|---|
| Renumber the container network | You | Recreates the network, restarts services, invalidates literal addresses in configs and scripts |
| Exclude your range from the tunnel | Network team | Changes what every laptop sees, needs a change request and a client profile update |
| Reach the service through a published port | You and the client | One port only, no direct container-to-container routing across the tunnel |
Renumerar és l'única reparació que podeu acabar sense un tiquet, i per això la majoria dels escrits s'hi aturen. És barata en un projecte jove i cara quan una eina de migració o una cadena de connexió desada apunta a una adreça literal. Compteu aquestes referències abans d'editar el YAML, no després.
Una exclusió del túnel és la resposta més neta quan el solapament seu en un rang que la vostra empresa posseeix de veritat. També és la més lenta, i és inútil per a un contractista que no pot canviar el perfil del client. Un port publicat o un petit proxy invers eviten la discussió: el client parla amb una adreça que el túnel ja encamina correctament, i només aquell port ha de ser accessible.
Fixeu un rang a propòsit
Per a un sol projecte, declareu la subxarxa al fitxer compose perquè el projecte deixi de treure del conjunt compartit:
networks:
default:
ipam:
config:
- subnet: 10.201.7.0/24Agafeu aquest rang d'un registre que mantingui el vostre equip, no d'un exemple que hàgiu trobat cercant. Comproveu-lo contra els prefixos que empeny la VPN, les LAN domèstiques des de les quals treballa la gent i les altres xarxes de contenidors del mateix amfitrió. Després planeu la recreació, perquè una xarxa existent conserva la seva subxarxa antiga: docker compose down, després up -d. docker network rm refusa mentre hi ha punts finals enganxats, i qualsevol ipv4_address entrada del fitxer ha de caure dins del rang nou.
Per a les xarxes que Docker crea tot sol, definiu un conjunt de dimoni a /etc/docker/daemon.json:
{
"default-address-pools": [
{ "base": "10.201.0.0/16", "size": 24 },
{ "base": "10.202.0.0/16", "size": 24 }
]
}El conjunt s'aplica a les xarxes creades després que el dimoni es reiniciï, i els ponts que ja existeixen conserven les seves adreces. Això és convenient i fàcil d'oblidar, així que tracteu un projecte antic com si encara se solapés fins que algú recreï la seva xarxa. La documentació de Docker sobre xarxes del motor descriu les regles d'assignació si heu de defensar el conjunt en una revisió.
El pont de Linux i el Docker Desktop fallen de manera diferent
En un amfitrió Linux, els contenidors seuen en ponts dins de l'espai de noms de l'amfitrió. Una taula ho decideix tot, així que la comparació anterior és tota la història: llegiu la ruta del pont, llegiu la ruta del túnel i vegeu quina guanya per a una adreça real de contenidor.
Docker Desktop posa els contenidors darrere d'una VM amb la seva pròpia NAT. L'amfitrió no té cap ruta a l'adreça del contenidor; arriba al servei per un port publicat, normalment lligat a 127.0.0.1. Un client de VPN pot, per tant, trencar el servei sense cap solapament de subxarxes, ja sigui instal·lant una ruta per al rang intern de la VM o bloquejant el trànsit de loopback mentre el túnel és connectat. Si ip route get a l'amfitrió informa que no hi ha ruta per a l'adreça del contenidor, això és l'esperat i no el defecte.
La conseqüència pràctica és on mireu primer. A Linux, comenceu per la taula d'encaminament. A Desktop, comenceu pel port publicat i les regles de tallafoc del client de VPN, i després comproveu si la subxarxa interna de la VM xoca amb alguna cosa que empeny el túnel.
Verifiqueu amb el túnel pujat
Reconnecteu la VPN dues vegades abans de donar-ho per arreglat, perquè un perfil que empeny rutes en connectar i les retira en desconnectar pot semblar correcte després del primer intent. Després executeu les comprovacions que el client realment executa:
ip route getdes de l'amfitrió, amb l'adreça real del contenidor.- Una petició des d'un altre contenidor, per demostrar que el servei mateix és sa.
curl -sv http://127.0.0.1:8080/des del client amb el túnel pujat, despréstraceroute -na l'adreça del contenidor des d'una màquina de la LAN.sysctl net.ipv4.conf.all.rp_filtersi la petició arriba a l'amfitrió però la resposta desapareix.
Finalment, escriviu el rang triat al mateix registre que vau fer servir per triar-lo, amb la data i el projecte que el posseeix. El proper solapament vindrà d'un projecte que ningú no ha documentat, i l'única defensa és que el rang es va reservar a propòsit en lloc de treure'l a l'atzar.