Ginugol ko ang halos buong umaga nitong tagsibol sa paghabol sa isang container na hindi ma-resolve kahit isang panloob na pangalan, habang ang browser sa tabi nito ay nagbubukas ng wiki nang walang reklamo. Nakataas ang tunnel, pinatunayan ito ng browser, at ang container ay nasa ibang network namespace na may ibang talahanayan ng ruta at ibang resolver. Ang sumusunod ay ang pagkakasunod-sunod na sinusuri ko ngayon: una ang mga talahanayan ng ruta, pangalawa ang paglutas ng pangalan, pangatlo ang pagpapasa at panghuli ang plataporma ng host. Huminto sa unang hakbang na nabigo na, dahil ang pagdaragdag ng mga patakaran sa ilalim ng stack ay nagtatago ng hangganan sa halip na ilipat ito.

Ihambing ang tatlong talahanayan ng ruta bago baguhin ang isang patakaran

Ang container sa default na tulay ng Docker ay may isang default na rutang papunta sa gateway na docker0 at walang ideya na may tun0. Ang host ay may tun0, ang mga rutang itinulak ng VPN, at marahil isang patakaran na nagpapadala ng test traffic sa ibang interface kaysa inaasahan mo. Nagdaragdag ang WSL ng ikatlong talahanayan sa likod ng sarili nitong virtual adapter. I-print ang lahat ng tatlo bago i-edit ang alinman.

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

Kung ang tanging ruta ng container ay ang tulay at hindi kailanman lumalabas ang tun0 sa namespace nito, wala sa ibaba ang makakatulong: walang pagbabago ng nameserver ang gumagawa ng ruta, at walang ruta ang gumagawa ng pagkakakilanlan ng tunnel na tatanggapin ng peer. Mahalaga ang pagkakasunod-sunod dahil ang pagkabigo ng DNS at pagkabigo ng ruta ay magkapareho ang hitsura mula sa loob ng shell.

Ituro ang resolver sa tunnel sa halip na sa pampubliko

Sa host, resolvectl status naglilista ng mga DNS server bawat link, at readlink -f /etc/resolv.conf ay nagsasabi kung ang file ay systemd stub, NetworkManager file, o isang bagay na muling isinulat ng client ng vendor. Sa loob ng container sa network na tinukoy ng user, /etc/resolv.conf pinangalanan ang 127.0.0.11, ang built-in na resolver ng Docker, na nagpapasa sa upstream kung saan naka-configure ang daemon. Ang container sa default na tulay ay nakatanggap ng kopya ng file ng host noong nilikha ito, at pinapanatili ito.

Ang kopyang iyon ang dahilan kung bakit ang tunnel na tumataas pagkatapos magsimula ang container ay iniiwan ang container na nagtatanong sa lumang upstream. Alinman sa ipasa ang resolver ng VPN nang tahasan gamit ang docker run --dns 10.8.0.53, o itakda ang "dns": ["10.8.0.53"] sa /etc/docker/daemon.json at i-restart ang daemon, o muling likhain ang container kapag nakataas na ang tunnel. Ang muling paglikha ay karaniwang mas mura kaysa i-debug ang resolver na tama isang oras ang nakalipas.

Ang paglalagay ng pampublikong resolver ay ang pag-aayos na nagpapanatili ng sintomas. Nire-resolve nito ang internet at nabigo sa bawat pribadong zone, at maaari nitong tahimik na laktawan ang pag-filter na dahilan ng tunnel. Kung susubukan mong magsulat sa loob ng /etc/resolv.conf ng tumatakbong container, asahan ang Device or resource busy: bind-mount ng Docker ang file na iyon, kaya ang pag-edit ay nangangailangan muna ng unmount. Ang pagtatakda ng --dns sa paglikha ang pagkakasunod-sunod na nakakaligtas sa restart.

Ipasa at isalin kapag nanghihiram ng tunnel ang mga container

Sa default na tulay, ang host ay router sa pagitan ng docker0 at tun0, at sa default ay hindi nito ginagawa ang alinman sa dalawang gawain. I-on ang pagpapasa at isalin ang source address upang makita ng peer ang tunnel address ng host sa halip na isang walang return route (palitan ang tun0 ng pangalang ibinibigay ng client mo sa interface):

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

Mahalaga ang mga patakaran ng FORWARD sa mga host na ang patakaran sa pagpapasa ay DROP. Naglalagay ang Docker ng sarili nitong mga chain, kaya subukan gamit ang packet sa halip na basahin ang iptables -S: mula sa container, ip route get 10.8.0.20 dapat pangalanan ang gateway ng tulay, at nc -vz 10.8.0.20 443 dapat kumonekta o mag-timeout sa tunnel sa halip na sa resolver.

Kung walang MASQUERADE, kailangan ng peer ng return route patungong 172.17.0.0/16, na hindi itinutulak ng karamihan ng remote-access VPN. Dito rin nasisira ng policy-based na client ang plano: kung hinuhuli lamang nito ang trapik mula sa partikular na UID o cgroups, hindi kailanman nakikita ng mga patakaran ng pagpapasa mo ang packet sa loob ng tunnel, at ang pag-aayos ay nasa routing policy ng client at hindi sa iptables. Nawawala ang mga patakarang idinagdag sa kamay kapag nag-reboot, kaya ilagay ang mga ito sa systemd unit o netfilter-persistent table at muling subukan pagkatapos ng reboot, dahil ang tunnel na huling tumataas ay maaaring magwalis sa kanila.

Ilagay ang tunnel sa loob ng container kapag ang layunin ay paghihiwalay

Kung ang isang container ay dapat lumabas sa pamamagitan ng partikular na node, patakbuhin ang client sa container na iyon. Kailangan nito ng --cap-add NET_ADMIN at --device /dev/net/tun, at pagkatapos ay pagmamay-ari nito ang sarili nitong tun0, mga ruta at firewall. Kung dumadaan ang ibang container dito, kailangan din nito ng pagpapasa at patakaran ng MASQUERADE sa loob ng container, at ang mga peer na iyon ay nangangailangan ng tahasang ruta o proxy na nakaturo rito; hindi idinadagdag ng default na tulay ng Docker ang rutang iyon para sa iyo.

Ang networking ng host, docker run --network host, ay ang murang bersyon: sumasali ang container sa namespace ng host at direktang nakikita ang mga ruta ng tunnel. Iniiwan din nito ang paghihiwalay ng network, humihikayat ng banggaan ng port, at sa pagsasagawa ay opsyon ito ng Linux. Ang na-publish na port ay hindi kapalit. -p 8080:80 ginagawang maabot ang isang serbisyo mula sa host; hindi nito ginagawang maabot ang mga panloob na address na 10.x mula sa loob ng container, at ang paghahalo ng dalawa ay ang paraan kung paano nagiging bukas na port ng database ang isang problema sa routing.

Ihiwalay ang kabiguan ng pangalan sa isang nagsasapaw na subnet

Ang default na tulay ng Docker ay 172.17.0.0/16, at maraming corporate VPN pool ang nasa loob ng 172.16.0.0/12. Kapag pagmamay-ari na ng tunnel ang saklaw na iyon, ang trapik na para sa container ay maaaring i-route sa tunnel sa halip. Nabigo ang mga pangalan, mukhang DNS ang error, at ang problema ay ang mga address. Suriin ang destinasyon, hindi ang resolver: ip route get 172.17.0.5 sa host, pagkatapos ihambing ang prefix ng tulay sa pool ng VPN at sa docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'.

Ang pag-aayos ay ilipat ang isa sa mga saklaw: alinman sa ibang default na pool ng address para sa Docker sa daemon.json o ibang pool sa concentrator. Walang ginagawa ang pagdaragdag ng isa pang nameserver dito, at ganoon din ang ssh -b: ang pagbigkis ng client sa isang interface ay nagbabago ng source address, hindi ng destinasyong ruta na papasok sa tunnel. Mabilis na paghahati ng trabaho: ang pangalang nare-resolve sa host ngunit hindi sa container ay problema ng resolver, habang ang direktang koneksyon ng IP na bumabitin sa container ngunit gumagana sa host ay problema ng ruta o chain ng pagpapasa.

Hindi sinusunod ng WSL at Docker Desktop ang mga patakaran ng Linux

Sa default na NAT mode nito, nakaupo ang WSL sa likod ng sarili nitong virtual adapter at hindi natatanggap ang mga panloob na ruta o DNS suffix ng VPN ng Windows, kaya gumagana ang browser at ping sa loob ng distribusyon ay hindi. Ang mirrored networking, na makukuha sa mga bagong build ng Windows 11, ay nagbabahagi ng mga interface ng host, ngunit kailangan itong i-enable sa .wslconfig at i-restart ang distribusyon gamit ang wsl --shutdown. Kumpirmahin ang aktibong mode gamit ang wslinfo --networking-mode bago maglapat ng pag-aayos, dahil mali ang sagot ng NAT para sa mirrored mode at kabaligtaran.

Nagdaragdag ng isa pang antas ang Docker Desktop. Ang mga container ng Linux sa Windows ay nakaupo sa likod ng implementasyon ng NAT na dating tinatawag na vpnkit, at naiiba ang landas nila sa native na host ng Linux. Kumokonekta ang mga container ng Windows sa pamamagitan ng virtual switch ng Hyper-V, at maaaring harangan ng corporate client ang trapik mula sa switch na iyon, kaya ang mga container ng Linux sa parehong makina ay maaaring makarating sa network habang ang mga container ng Windows ay wala. Ang panlabas na switch na nakatali sa pisikal na adapter ang karaniwang solusyon, at binabago nito ang pagkakakilanlan ng network ng container sa mga paraang maaaring hindi pinapayagan ng patakaran.

Bago magsulat ng isa pang patakaran, daanan ang apat na antas sa pagkakasunod-sunod at huminto kung saan mali ang isa sa kanila:

  • Sa loob ng container: naaabot ba ng ip route ang pribadong prefix, at pinangalanan ba ng /etc/resolv.conf ang upstream na nagre-resolve nito?
  • Sa host: bukas ba ang pagpapasa, nakatali ba ang NAT sa interface ng tunnel, at tinatanggap ba ng chain ng pagpapasa ang tulay patungong tunnel?
  • Sa peer: alam ba nito ang daan pabalik, o umaasa ka sa NAT upang itago ang subnet ng container?
  • Sa plataporma: nasa NAT o mirrored mode ba ang WSL, at Linux o Windows ba ang container?

Patakbuhin muli ang bawat pagsubok sa bagong container o shell. Ang matagal na prosesong may naka-cache na sagot o naitatag na koneksyon ay patuloy na mabibigo pagkatapos maging tama ang configuration, at ang kabiguan na iyon ay eksaktong kamukha ng pag-aayos na hindi gumana.

Kaugnay na mga artikulo