Dev контейнерът не достига хост, достъпен само през VPN: къде да търсим
Браузърът и контейнерът имат различни контексти на резолвер, прокси и маршрути. Открийте кой от тях използва процесът, който се проваля, преди да промените която и да е настройка на VPN.
Частният API се отваря в настолния ви браузър и се проваля в контейнера за разработка. Това не е противоречие и рядко причината е самият VPN. Заявката от браузъра и заявката, която се проваля, са направени от различни процеси, с различни резолвери, проксита и маршрути, а често и от напълно различни мрежови пространства от имена. „На моя лаптоп“ може да означава Windows хоста, WSL дистрибуция, виртуалната машина на Docker Desktop и контейнер вътре в нея — четири контекста, всеки от които може да отговори различно на едно и също име на хост. Разберете кой от тях използва процесът, който се проваля, преди да пипнете дори една настройка.
Открийте процеса, преди да промените настройка
Започнете с контейнерния двигател, а не с VPN клиента. Попитайте с кой контекст говори командният ред и на коя операционна система работи този двигател, защото Linux контейнер, управляван от настолна виртуална машина, минава по различен път от такъв, управляван от локален демон:
docker context ls
docker info --format '{{.OperatingSystem}} / {{.Name}}'
docker run --rm alpine ip route
В Windows wsl -l -v ви казва дали дистрибуцията работи под WSL 2, което я поставя зад собствен виртуален суич. Тази подробност решава дали контейнерът споделя маршрутната таблица на хоста, или стои зад NAT, който се нуждае от пренасочен порт или име на хост, за да достигне хоста.
Задръжте една заявка постоянна и сравнявайте
Изберете една безобидна крайна точка на частния хост и я използвайте за всяко сравнение: от браузъра, от терминал на хоста, от WSL дистрибуцията и отвътре в контейнера. Записвайте четири неща за всеки опит: разрешения адрес, дали е използвано прокси, класа на отказа и изминалото време. Търсенето на име, установяването на връзка, TLS валидацията и HTTP статусът са четири различни проблема и смесването им в „не работи“ прахосва цяла сутрин.
Изпълнете сравнението вътре в контейнера, който се проваля, с таймаут, за да не задържи тиха защитна стена терминала с минути. Нов контейнер възпроизвежда мрежовия контекст на двигателя, но не и пространството от имена, прокси променливите или резолвера на приложението, затова docker exec в истинския контейнер е авторитетният тест, а страничният контейнер е само начин да изолирате дали разликата е в двигателя, или в контейнера:
docker exec -it app /bin/sh -c "getent hosts api.internal; curl -v --max-time 8 https://api.internal/ 2>&1 | tail -20"
docker run --rm --network container:app curlimages/curl:latest -sv --max-time 8 https://api.internal/ 2>&1 | tail -20
Базовият образ alpine носи busybox и не носи curl и точно такава подробност проваля копиран диагностичен блок: изберете образ с клиента или го добавете в същото изпълнение. Сравнението с несвързани публични сайтове не изолира нищо. Ако https://example.com работи от контейнера, научихте, че контейнерът има интернет достъп, и нищо за това дали достига частен адрес през тунела. По същия начин отварянето на нов терминал доказва само, че новият терминал работи, а не че споделя среда за изпълнение с приложението, което се е провалило.
Docker Desktop може да работи с VPN
Собствената документация на Docker за VPN и свързаност с хоста описва това като поддържана настройка и честното резюме е, че работи, вместо да е автоматично счупена. Не приемайте, че настолната виртуална машина заобикаля тунела на хоста по дизайн; при много настройки трафикът правилно следва тунела на хоста и точно затова фолклорът „Docker игнорира VPN“ дава уверени и грешни съвети.
Това, което все още има значение, е използваният backend, политиката за разделен тунел на клиента и конфигурацията на резолвера, която виртуалната машина е получила. VPN клиент, който инсталира маршрути, но не и DNS, или който push-ва DNS сървър, недостъпен за виртуалната машина, предизвиква отказ при търсене на име вътре в контейнера, докато хостът работи, защото има допълнителен резолвер или кеширан отговор. Това е проблем с резолвера в костюм на контейнер. Той преживява всяко повторно свързване на VPN, което опитате, защото тунелът вече носи трафика, който сте поискали да носи.
Припокриване на адреси и MTU са различни откази
Два отказа заслужават собствена диагностика, защото често се бъркат с политика за достъп. Първият е припокриване на адреси: ако VPN push-ва диапазон, който се сблъсква с подсетта на подразбиращия се bridge на контейнерна мрежа, маршрутът на контейнера за този диапазон сочи към локалния bridge и никога не достига тунела. Инспектирайте реалните подсети, вместо да гадаете:
docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
ip route get 10.20.30.40
Вторият е проблем с MTU. Ако връзката се установи и TLS завърши, но по-големите отговори зациклят, имате проблем с размера на пакета, не с оторизацията, и подмяната на DNS записи никога няма да го поправи. Тествайте с малка заявка и с голяма, преди да промените нещо, и запишете двата резултата.
Решението за припокриване е друга контейнерна подсетта или ограничен маршрут, избран от този, който притежава адресния план. Решението за зацикляне на MTU е ограничаване или намаляване на MTU на тунела или интерфейса до стойност, която оцелява по пътя, приложено на слоя, който контролирате.
Прокси конфигурацията е за процес, не за машина
Вътре в контейнера localhost именува собствения мрежов контекст на този контейнер, така че прокси, работещо на хоста, не е достъпно там под това име. Docker Desktop предоставя host.docker.internal за достъп до хоста, а в Linux го добавяте изрично с --add-host=host.docker.internal:host-gateway. Във всеки случай това име ви дава маршрут до хоста; то не създава прокси услуга и не ви оторизира да използвате такава.
Използвайте прокси адреса и порта, предоставени за реалната среда, и проверете кой ги чете. Променливите, експортирани в интерактивен shell, не конфигурират автоматично всяко разширение на редактора, езиков сървър, инструмент за изграждане и фонова демон. Важен е процесът, направил неуспешната заявка, затова инспектирайте неговата среда, а не тази на терминала ви.
Накрая, накарайте поправката да се обясни сама. Полезното решение назовава границата, която е била грешна, настройката, която я е променила, и набора от процеси, които то вече засяга. Рестартирането на VPN, редактора и двигателя последователно може да промени симптома, но не оставя нищо, което следващият човек да използва.