Ուղղեք Docker-ի և WSL-ի երթևեկությունը, որը անտեսում է հոսթի VPN-ը
Կոնտեյներները և WSL-ը պահում են իրենց երթուղիները, լուծիչը և փոխանցման ուղին, ուստի աշխատող հոսթի թունելը նրանց թողնում է հին DNS-ով կամ առանց ելքի։ Ուղղեք յուրաքանչյուր շերտ։
Այս գարնանը մի առավոտվա մեծ մասը ծախսեցի մի կոնտեյների հետևից ընկնելով, որը չէր կարողանում լուծել ոչ մի ներքին անուն, մինչդեռ կողքի բրաուզերը բացում էր վիքին առանց բողոքի։ Թունելը բարձրացված էր, բրաուզերը դա ապացուցում էր, և կոնտեյները մնում էր այլ ցանցային անվանատարածքում՝ այլ երթուղային աղյուսակով և այլ լուծիչով։ Այն, ինչ հաջորդում է, այն հերթականությունն է, որ հիմա ստուգում եմ՝ նախ երթուղային աղյուսակները, երկրորդ՝ անվան լուծումը, երրորդ՝ փոխանցումը, և վերջում՝ հոսթի հարթակը։ Կանգ առեք առաջին քայլի վրա, որն արդեն ձախողվում է, որովհետև կույտի ավելի ներքև կանոններ ավելացնելը թաքցնում է սահմանը՝ փոխարենը տեղափոխելու։
Համեմատեք երեք երթուղային աղյուսակները, նախքան կանոնը փոխելը
Docker-ի լռելյայն կամուրջի վրա գտնվող կոնտեյներն ունի մեկ լռելյայն երթուղի՝ ուղղված docker0 դարպասին, և գաղափար չունի, որ tun0 գոյություն ունի։ Հոսթն ունի tun0, VPN-ի մղած երթուղիները և, հնարավոր է, քաղաքականության կանոն, որն ստուգիչ երթևեկությունն ուղարկում է ձեր սպասածից տարբեր ինտերֆեյսով։ WSL-ը երրորդ աղյուսակն ավելացնում է իր իսկ վիրտուալ ադապտերի հետևում։ Տպեք բոլոր երեքը, նախքան դրանցից որևէ մեկը խմբագրելը։
| Context | Command | What a wrong answer looks like |
|---|---|---|
| Host | ip route get 10.8.0.20 | Leaves a physical interface instead of tun0 |
| Container | ip route | Only 172.17.0.0/16 via 172.17.0.1 |
| Container DNS | cat /etc/resolv.conf | A public resolver, or an upstream the tunnel never pushed |
| WSL | ip addr; ip route | Only the WSL subnet, no Windows VPN adapter |
Եթե կոնտեյների միակ երթուղին կամուրջն է, և tun0-ը երբեք չի հայտնվում նրա անվանատարածքում, ներքևում ոչինչ չի օգնի՝ ոչ մի անվանասերվերի փոփոխություն երթուղի չի ստեղծում, և ոչ մի երթուղի չի ստեղծում թունելի ինքնություն, որը կընդունի զուգընկերը։ Հերթականությունը կարևոր է, որովհետև DNS-ի ձախողումը և երթուղու ձախողումը կեղևի ներսից նույնն են թվում։
Ուղղեք լուծիչը դեպի թունելը՝ հանրայինի փոխարեն
Հոսթի վրա, resolvectl status թվարկում է DNS սերվերները ըստ կապի, և readlink -f /etc/resolv.conf ասում է՝ արդյոք ֆայլը systemd-ի stub-ն է, NetworkManager-ի ֆայլ, թե ինչ-որ բան, որը վերաշարադրել է մատակարարի հաճախորդը։ Օգտատիրոջ կողմից սահմանված ցանցում գտնվող կոնտեյների ներսում, /etc/resolv.conf անվանում է 127.0.0.11՝ Docker-ի ներկառուցված լուծիչը, որը փոխանցում է այն upstream-ին, որով կարգավորվել է դեմոնը։ Լռելյայն կամուրջի կոնտեյները փոխարենը ստեղծման պահին ստացել է հոսթի ֆայլի պատճենը և պահում է այն։
Այդ պատճենն է պատճառը, որ կոնտեյների մեկնարկից հետո բարձրացող թունելը կոնտեյներին թողնում է հարցնել հին upstream-ին։ Կամ փոխանցեք VPN-ի լուծիչը բացահայտորեն docker run --dns 10.8.0.53-ով, կամ սահմանեք "dns": ["10.8.0.53"] -ը /etc/docker/daemon.json -ում և վերագործարկեք դեմոնը, կամ թունելը բարձրանալուց հետո նորից ստեղծեք կոնտեյները։ Վերստեղծումը սովորաբար ավելի էժան է, քան մեկ ժամ առաջ ճիշտ լուծիչի վրիպազերծումը։
Հանրային լուծիչով փոխարինելը այն վերանորոգումն է, որը պահպանում է ախտանիշը։ Այն լուծում է ինտերնետը և ձախողվում ամեն մասնավոր գոտում, և կարող է լուռ շրջանցել այն զտումը, որի համար թունելը գոյություն ունի։ Եթե փորձեք գրել աշխատող կոնտեյների /etc/resolv.conf-ի ներսում, սպասեք Device or resource busy-ի. Docker-ը bind-mount է անում այդ ֆայլը, ուստի խմբագրումը նախ պահանջում է ապամոնտաժում։ --dns -ը ստեղծման պահին սահմանելը այն հաջորդականությունն է, որը վերապրում է վերագործարկումը։
Փոխանցեք և թարգմանեք, երբ կոնտեյներները վերցնում են թունելը
Լռելյայն կամուրջի դեպքում հոսթը երթուղիչ է docker0-ի և tun0-ի միջև, և լռելյայն ոչ մի այդ աշխատանքը չի կատարում։ Միացրեք փոխանցումը և թարգմանեք աղբյուրի հասցեն, որպեսզի զուգընկերը տեսնի հոսթի թունելի հասցե՝ փոխարենը այն հասցեի, որին վերադարձի երթուղի չունի (փոխարինեք tun0-ը նրանով, ինչ ձեր հաճախորդն անվանում է ինտերֆեյսը)։
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 ACCEPTFORWARD կանոնները կարևոր են այն հոսթերի վրա, որոնց փոխանցման քաղաքականությունը DROP է։ Docker-ը տեղադրում է իր իսկ շղթաները, ուստի փորձարկեք փաթեթով, այլ ոչ թե կարդալով iptables -S-ը. կոնտեյներից, ip route get 10.8.0.20 պետք է անվանվի կամրջի դարպասը, և nc -vz 10.8.0.20 443 պետք է միանա կամ ժամկետանց լինի թունելի վրա, այլ ոչ թե լուծիչի։
Առանց MASQUERADE-ի զուգընկերն ունի վերադարձի երթուղու կարիք դեպի 172.17.0.0/16, որը հեռավոր հասանելիության VPN-ների մեծ մասը չի մղի։ Այստեղ է նաև, որ քաղաքականության վրա հիմնված հաճախորդը կոտրում է պլանը. եթե այն գրավում է միայն որոշակի UID-ների կամ cgroups-ների երթևեկությունը, ձեր փոխանցման կանոնները երբեք չեն տեսնի փաթեթը թունելի ներսում, և ուղղումը պատկանում է հաճախորդի երթուղային քաղաքականությանը, ոչ թե iptables-ին։ Ձեռքով ավելացված կանոնները անհետանում են վերագործարկման ժամանակ, ուստի դրեք դրանք systemd միավորում կամ netfilter-persistent աղյուսակում և նորից փորձարկեք վերագործարկումից հետո, քանի որ ուշ բարձրացող թունելը կարող է քշել դրանք։
Տեղադրեք թունելը կոնտեյների ներսում, երբ նպատակը մեկուսացումն է
Եթե մի կոնտեյներ պետք է դուրս գա որոշակի հանգույցով, գործարկեք հաճախորդը այդ կոնտեյներում։ Դրան պետք է --cap-add NET_ADMIN և --device /dev/net/tun, և այդ ժամանակ այն ունի իր tun0-ը, երթուղիները և հրապատը։ Եթե այլ կոնտեյներներ անցնում են դրա միջով, այն նաև կարիք ունի փոխանցման և MASQUERADE կանոնի կոնտեյների ներսում, և այդ զուգընկերներին պետք է բացահայտ երթուղի կամ պրոքսի, որն ուղղված է դրան. Docker-ի լռելյայն կամուրջը այդ երթուղին ձեզ փոխարենը չի ավելացնում։
Հոսթի ցանցը, docker run --network host, էժան տարբերակն է. կոնտեյները միանում է հոսթի անվանատարածքին և ուղղակիորեն տեսնում թունելի երթուղիները։ Այն նաև վերացնում է ցանցի մեկուսացումը, հրավիրում պորտերի բախումների և գործնականում Linux-ի տարբերակ է։ Հրապարակված պորտը փոխարինող չէ։ -p 8080:80 -ը ծառայությունը հասանելի է դարձնում հոսթից. այն ներքին 10.x հասցեները հասանելի չի դարձնում կոնտեյների ներսից, և երկուսը շփոթելը հենց այն ճանապարհն է, որով երթուղային խնդիրը դառնում է բաց տվյալների բազայի պորտ։
Տարբերեք անվան ձախողումը համընկնող ենթացանցից
Docker-ի լռելյայն կամուրջը 172.17.0.0/16 է, և շատ կորպորատիվ VPN լողավազաններ գտնվում են 172.16.0.0/12-ի ներսում։ Հենց թունելը տիրում է այդ տիրույթին, կոնտեյների համար նախատեսված երթևեկությունը կարող է ուղղվել թունելի մեջ։ Անունները ձախողվում են, սխալը DNS-ի է նման, և խնդիրը հասցեներն են։ Ստուգեք նպատակակետը, ոչ թե լուծիչը. ip route get 172.17.0.5 հոսթի վրա, ապա համեմատեք կամրջի նախածանցը VPN լողավազանի և docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'-ի հետ։
Վերանորոգումը տիրույթներից մեկը տեղափոխելն է. կամ Docker-ի համար այլ լռելյայն հասցեների լողավազան daemon.json -ում, կամ այլ լողավազան կենտրոնացուցիչում։ Եվս մեկ անվանասերվեր ավելացնելը այստեղ ոչինչ չի անում, և ssh -b-ը նույնպես չի անում. հաճախորդին ինտերֆեյսին կապելը փոխում է աղբյուրի հասցեն, ոչ թե նպատակակետ երթուղին, որն ուղղված է թունելի մեջ։ Արագ աշխատանքի բաժանում. անուն, որը լուծվում է հոսթի վրա, բայց ոչ կոնտեյներում, լուծիչի խնդիր է, մինչդեռ ուղիղ IP կապը, որը կախվում է կոնտեյներում, բայց աշխատում է հոսթի վրա, երթուղու կամ փոխանցման շղթայի խնդիր է։
WSL-ը և Docker Desktop-ը չեն հետևում Linux-ի կանոններին
Իր լռելյայն NAT ռեժիմում WSL-ը նստում է իր իսկ վիրտուալ ադապտերի հետևում և չի ստանում Windows VPN-ի ներքին երթուղիները կամ DNS վերջածանցները, դրա համար էլ բրաուզերը աշխատում է, իսկ ping -ը՝ տարածման ներսում, ոչ։ Հայելային ցանցը, որը հասանելի է Windows 11-ի վերջին կառուցվածքներում, փոխարենը կիսում է հոսթի ինտերֆեյսները, սակայն այն պետք է միացվի .wslconfig -ում, և տարածումը պետք է վերագործարկվի wsl --shutdown-ով։ Հաստատեք ակտիվ ռեժիմը wslinfo --networking-mode -ով, նախքան ուղղում կիրառելը, որովհետև NAT-ի պատասխանը սխալ է հայելային ռեժիմի համար և հակառակը։
Docker Desktop-ը ավելացնում է ևս մեկ շերտ։ Windows-ում Linux կոնտեյներները նստում են NAT-ի իրականացման հետևում, որը պատմականորեն կոչվում է vpnkit, և նրանց ուղին տարբերվում է բնիկ Linux հոսթից։ Windows կոնտեյներները միանում են Hyper-V վիրտուալ անջատիչի միջոցով, և կորպորատիվ հաճախորդը կարող է արգելափակել երթևեկությունն այդ անջատիչից, ուստի նույն մեքենայի Linux կոնտեյներները կարող են հասնել ցանցին, մինչդեռ Windows կոնտեյներները ոչինչ չունեն։ Ֆիզիկական ադապտերին կապված արտաքին անջատիչը սովորական լուծումն է, և այն փոխում է կոնտեյների ցանցային ինքնությունը այնպես, ինչպես քաղաքականությունը կարող է չթույլատրել։
Նախքան ևս մեկ կանոն գրելը, անցեք չորս շերտերը հերթականությամբ և կանգ առեք այնտեղ, որտեղ դրանցից մեկը սխալ է.
- Կոնտեյների ներսում. արդյո՞ք
ip route-ը հասնում է մասնավոր նախածանցին, և արդյո՞ք/etc/resolv.conf-ը անվանում է upstream, որը լուծում է այն։ - Հոսթի վրա. միացված է՞ փոխանցումը, NAT-ը կապվա՞ծ է թունելի ինտերֆեյսին, և փոխանցման շղթան ընդունո՞ւմ է կամուրջից թունել։
- Զուգընկերոջ մոտ. գիտե՞ նա վերադարձի ուղի, թե՞ դուք հույսը դնում եք NAT-ի վրա՝ կոնտեյների ենթացանցը թաքցնելու համար։
- Հարթակի վրա. WSL-ը NAT, թե՞ հայելային ռեժիմում է, և կոնտեյնը Linux է, թե՞ Windows։
Կրկին գործարկեք յուրաքանչյուր փորձարկում թարմ կոնտեյներում կամ կեղևում։ Երկար գործող պրոցեսը՝ պահված պատասխանով կամ հաստատված կապով, կշարունակի ձախողվել նաև այն բանից հետո, երբ կարգավորումը ճիշտ է, և այդ ձախողումը ճիշտ նման է վերանորոգման, որը չի աշխատել։