To pomlad sem večino enega jutra preživel pri lovljenju vsebnika, ki ni mogel razrešiti niti enega notranjega imena, medtem ko je brskalnik ob njem odpiral wiki brez pritožb. Tunel je bil vzpostavljen, brskalnik je to dokazoval, vsebnik pa je stal v drugem omrežnem imenskem prostoru z drugo tabelo poti in drugim resolverjem. Sledi vrstni red, ki ga zdaj preverjam: najprej tabele poti, nato razreševanje imen, nato posredovanje in nazadnje platforma gostitelja. Ustavite se pri prvem koraku, ki že ne uspe, ker dodajanje pravil nižje v skladu skrije mejo, namesto da bi jo premaknilo.

Primerjajte tri tabele poti, preden spremenite pravilo

Vsebnik na privzetem mostu Dockerja ima eno privzeto pot proti prehodu docker0 in ne ve, da tun0 obstaja. Gostitelj ima tun0, poti, ki jih je potisnil VPN, in morda pravilo politike, ki pošilja preskusni promet skozi drugačen vmesnik, kot pričakujete. WSL doda tretjo tabelo za svojim lastnim navideznim vmesnikom. Natisnite vse tri, preden katero koli uredite.

ContextCommandWhat a wrong answer looks like
Hostip route get 10.8.0.20Leaves a physical interface instead of tun0
Containerip routeOnly 172.17.0.0/16 via 172.17.0.1
Container DNScat /etc/resolv.confA public resolver, or an upstream the tunnel never pushed
WSLip addr; ip routeOnly the WSL subnet, no Windows VPN adapter

Če je edina pot vsebnika most in se tun0 nikoli ne pojavi v njegovem imenskem prostoru, nič spodaj ne bo pomagalo: nobena sprememba imenskega strežnika ne ustvari poti in nobena pot ne ustvari identitete tunela, ki bi jo partner sprejel. Vrstni red je pomemben, ker sta okvara DNS in okvara poti od znotraj lupine videti enako.

Usmerite resolver na tunel namesto na javnega

Na gostitelju resolvectl status navaja strežnike DNS po povezavi, in readlink -f /etc/resolv.conf vam pove, ali je datoteka stub systemd, datoteka NetworkManager ali nekaj, kar je prepisal odjemalec ponudnika. Znotraj vsebnika v omrežju, ki ga določi uporabnik, /etc/resolv.conf imenuje 127.0.0.11, vgrajeni resolver Dockerja, ki posreduje tistemu upstreamu, s katerim je bil konfiguriran demon. Vsebnik na privzetem mostu pa je ob ustvarjanju dobil kopijo datoteke gostitelja in jo obdrži.

Ta kopija je razlog, da tunel, ki se dvigne po zagonu vsebnika, pusti vsebnik spraševati stari upstream. Bodisi posredujte resolver VPN izrecno z docker run --dns 10.8.0.53, bodisi nastavite "dns": ["10.8.0.53"] v /etc/docker/daemon.json in znova zaženite demon, bodisi znova ustvarite vsebnik, ko je tunel vzpostavljen. Ponovno ustvarjanje je običajno cenejše od razhroščevanja resolverja, ki je bil pred uro pravilen.

Zamenjava z javnim resolverjem je popravilo, ki ohrani simptom. Razreši internet in spodleti v vsaki zasebni coni, lahko pa tudi tiho obide filtriranje, zaradi katerega tunel obstaja. Če poskusite pisati v /etc/resolv.conf delujočega vsebnika, pričakujte Device or resource busy: Docker to datoteko bind-mounta, zato urejanje najprej zahteva odklop. Nastavitev --dns ob ustvarjanju je zaporedje, ki preživi ponovni zagon.

Posredujte in prevajajte, ko si vsebniki izposojajo tunel

S privzetim mostom je gostitelj usmerjevalnik med docker0 in tun0 in privzeto ne opravi nobene od obeh nalog. Vklopite posredovanje in prevedite izvorni naslov, da partner vidi naslov tunela gostitelja namesto naslova, do katerega nima povratne poti (zamenjajte tun0 s tem, kako vaš odjemalec imenuje vmesnik):

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
iptables -A FORWARD -i docker0 -o tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -o docker0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Pravila FORWARD so pomembna na gostiteljih, katerih politika posredovanja je DROP. Docker vstavi svoje verige, zato preizkušajte s paketom, ne z branjem iptables -S: iz vsebnika naj ip route get 10.8.0.20 imenuje prehod mostu, in nc -vz 10.8.0.20 443 naj se poveže ali poteče na tunelu, ne na resolverju.

Brez MASQUERADE partner potrebuje povratno pot do 172.17.0.0/16, ki je večina VPN za oddaljeni dostop ne bo potisnila. Tu tudi odpove načrt pri odjemalcu, ki temelji na politikah: če prestreza le promet določenih UID ali cgroups, vaša pravila posredovanja nikoli ne vidijo paketa znotraj tunela, in popravek sodi v usmerjevalno politiko odjemalca, ne v iptables. Pravila, dodana ročno, izginejo ob ponovnem zagonu, zato jih vstavite v enoto systemd ali tabelo netfilter-persistent in znova preizkusite po ponovnem zagonu, saj lahko tunel, ki se dvigne pozno, ta pravila odnese.

Postavite tunel v notranjost vsebnika, ko je cilj izolacija

Če mora en vsebnik izstopiti skozi določeno vozlišče, zaženite odjemalca v tem vsebniku. Potrebuje --cap-add NET_ADMIN in --device /dev/net/tun, in nato ima svoj tun0, poti in požarni zid. Če drugi vsebniki hodijo skozenj, potrebuje tudi posredovanje in pravilo MASQUERADE znotraj vsebnika, tisti partnerji pa potrebujejo izrecno pot ali proxy, ki kaže nanj; privzeti most Dockerja te poti ne doda namesto vas.

Omrežje gostitelja, docker run --network host, je poceni različica: vsebnik se pridruži imenskemu prostoru gostitelja in vidi poti tunela neposredno. Opusti pa izolacijo omrežja, vabi k trkom vrat in je v praksi možnost Linuxa. Objavljena vrata niso nadomestilo. -p 8080:80 naredi storitev dostopno z gostitelja; ne naredi notranjih naslovov 10.x dostopnih znotraj vsebnika, in mešanje obojega je pot, po kateri težava z usmerjanjem postane izpostavljena vrata podatkovne baze.

Ločite okvaro imena od prekrivajoče se podomrežje

Privzeti most Dockerja je 172.17.0.0/16, in veliko korporativnih bazenov VPN leži znotraj 172.16.0.0/12. Ko ima tunel to območje, se promet, namenjen vsebniku, lahko usmeri v tunel. Imena odpovedo, napaka je videti kot DNS, in težava je v naslovih. Preverite cilj, ne resolverja: ip route get 172.17.0.5 na gostitelju, nato primerjajte predpono mostu z bazenom VPN in z docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'.

Popravilo je premakniti eno od območij: bodisi drug privzeti bazen naslovov za Docker v daemon.json bodisi drug bazen na koncentratorju. Dodajanje še enega imenskega strežnika tu ne naredi ničesar, in ssh -b tudi ne: vezava odjemalca na vmesnik spremeni izvorni naslov, ne ciljne poti, ki vodi v tunel. Hitra delitev dela: ime, ki se razreši na gostitelju, a ne v vsebniku, je težava resolverja, medtem ko je neposredna povezava IP, ki v vsebniku obvisi, a na gostitelju deluje, težava poti ali verige posredovanja.

WSL in Docker Desktop ne spoštujeta pravil Linuxa

V svojem privzetem načinu NAT WSL sedi za svojim lastnim navideznim vmesnikom in ne prejme notranjih poti ali pripon DNS VPN Windows, zato brskalnik deluje in ping znotraj distribucije ne. Zrcalno omrežje, na voljo v nedavnih gradnjah Windows 11, namesto tega deli vmesnike gostitelja, vendar ga je treba omogočiti v .wslconfig in distribucijo znova zagnati z wsl --shutdown. Potrdite aktivni način z wslinfo --networking-mode preden uporabite popravek, ker je odgovor NAT napačen za zrcalni način in obratno.

Docker Desktop doda še en sloj. Vsebniki Linuxa v Windowsih sedijo za izvedbo NAT, ki se ji zgodovinsko reče vpnkit, in njihova pot se razlikuje od domorodnega gostitelja Linux. Vsebniki Windows se povežejo prek navideznega stikala Hyper-V, in poslovni odjemalec lahko blokira promet s tega stikala, zato lahko vsebniki Linuxa na istem stroju dosežejo omrežje, medtem ko vsebniki Windows nimajo ničesar. Zunanje stikalo, vezano na fizični vmesnik, je običajna rešitev in spremeni omrežno identiteto vsebnika na načine, ki jih politika morda ne dovoli.

Preden napišete novo pravilo, prehodite štiri sloje po vrsti in se ustavite tam, kjer je eden od njih napačen:

  • Znotraj vsebnika: ali ip route doseže zasebno predpono in ali /etc/resolv.conf imenuje upstream, ki jo razreši?
  • Na gostitelju: ali je posredovanje vklopljeno, ali je NAT vezan na vmesnik tunela in ali veriga posredovanja sprejme most v tunel?
  • Pri partnerju: ali pozna povratno pot, ali se zanašate na NAT, da skrije podomrežje vsebnika?
  • Na platformi: ali je WSL v načinu NAT ali zrcalnem in ali je vsebnik Linux ali Windows?

Vsak preskus znova zaženite v novem vsebniku ali lupini. Dolgo delujoč proces s predpomnjenim odgovorom ali vzpostavljeno povezavo bo še naprej propadal, ko bo konfiguracija pravilna, in ta okvara je videti natanko kot popravek, ki ni deloval.

Sorodni članki