Трафикът на Docker контейнерите заобикаля VPN на хоста: как да го проверите
VPN на хоста покрива само пространството от имена на хоста. Използвайте тези проверки, за да разберете дали трафикът на контейнерите зад мост влиза в тунела, или излиза директно.
Браузърът на хоста показва адреса за изход на VPN, контейнерът съобщава вашата домашна връзка и някой нарича това изтичане. Нищо не е изтекло. Тунелът на хоста е набор от интерфейси, маршрути и правила, които принадлежат на мрежовото пространство от имена на хоста, а контейнерът зад мост е друго пространство от имена със свой собствен маршрут по подразбиране. Стоял съм върху Compose стек, в който VPN клиентът е бил свързан със седмици и нито един пакет на контейнер така и не е влизал в него.
Проверете пространството от имена преди иконата в системния трей
Пространствата от имена са целият аргумент. Когато Docker стартира контейнер в мрежа с мост, той създава мрежово пространство от имена, прикача един край на veth двойка вътре в него и дава на това пространство адрес и маршрут по подразбиране. Интерфейсът на тунела, както и да се нарича, живее в пространството от имена на хоста. Трафикът вътре в контейнера не може да го види и никоя настройка на клиента не променя това отвън.
Два поддържани хода ви извеждат от изолацията. --network host поставя контейнера в пространството от имена на хоста, така че той наследява маршрутите на хоста и следователно тунела. --network container:vpn споделя пространството от имена на друг контейнер и точно така повечето странични архитектури прекарват натоварване през VPN контейнер. И двете са явни избори; обикновено само едно от тях е това, което човекът, който внедрява, е имал предвид.
Режимът на хост не е безплатно надграждане. Контейнерът спира да има свой собствен адрес, публикуването на портове спира да важи, а процес, който държи NET_ADMIN там, може да пренапише маршрутизацията на хоста. Приемането на това може да е правилното решение. Да се приема, че вече е включено, е начинът, по който хората прекарват една вечер в отстраняване на проблеми с тунел, който никога не е бил по пътя.
Проследете пакета извън моста
Контейнерът зад мост изпраща пакета си към шлюза си по подразбиране, който е интерфейсът на моста на хоста. След това хостът препраща пакета и в конфигурацията по подразбиране преобразува адреса на източника в своя, преди пакетът да излезе. Именно тази стъпка на преобразуване тихо обезсилва политиката.
Докато пакетът стигне до крайната точка на тунела, той носи адреса на хоста. Всяко правило, политически маршрут или решение за разделен тунел, обвързано с оригиналния адрес на контейнера, спира да съвпада и два контейнера, предназначени да излязат през различни изходи, не могат да бъдат разграничени само по източник. Ако ви трябва маршрутизация за всеки контейнер, решението трябва да се вземе преди преобразуването или вътре в пространство от имена, което контролирате.
Docker поддържа тези правила сам, чрез каквато и firewall основа е бил конфигуриран демонът. Правила, написани на ръка извън поддържаната кука за препращан трафик, DOCKER-USER, могат да бъдат пренаредени или премахнати, когато демонът се рестартира или хостът се надгради. Документацията на Docker за филтриране на пакети показва реда на веригите; практическата точка е, че всяко правило се нуждае от собственик и от път за презареждане, който действително сте тествали.
Тествайте двете системи поотделно
Доказателствата от едно пространство от имена не казват нищо за другото. Заявка, изпълнена вътре в VPN контейнера, доказва, че тунелът работи за този контейнер. Това не е доказателство за хоста и същата команда, изпълнена от контейнер с --network host, не е доказателство за моста.
# host namespace
ip route get 1.1.1.1
ip -brief addr show
# a fresh container on the same bridge network
docker run --rm --network appnet alpine sh -c 'ip route; cat /etc/resolv.conf; ip -6 route'
След това повторете теста вътре в истинския контейнер на приложението, а не в подобен образ. Приложението може да носи допълнителен маршрут, променлива на средата за прокси или различен резолвер и всяко от тези неща променя отговора. Проверявайте разрешаването на имена и второто семейство адреси всеки път: контейнерите в потребителски дефинирани мостове се разрешават през вградения резолвер на Docker на 127.0.0.11, а маршрут по подразбиране IPv6 на моста може да изкара трафик навън, докато сте заети да тествате тунел само за IPv4.
Прочетете модела, преди да пипате идентификационни данни
Когато хостът работи, а контейнерът не, причината почти винаги е структурна и смяната на ключове или преинсталирането на клиента пропилява следобед. Подредете първо симптома и поправката обикновено се назовава сама.
| What you see | Usual cause | First check |
|---|---|---|
| Host exits through the VPN, container shows the ISP address | The container never entered the tunnel | Default route inside the container |
| Container works until the daemon restarts, then stops | Rules outside the supported hook, or a changed backend | Daemon's reported firewall backend and DOCKER-USER |
| Container loses internal hosts after the tunnel comes up | VPN prefix overlaps the Docker bridge subnet | ip route on the host, then docker network inspect |
| Small replies arrive, large ones hang | Tunnel MTU or missing MSS clamping | Link MTU on both ends of the tunnel |
| Container falls back to the ISP address when the tunnel drops | Nothing enforces the kill switch for forwarded traffic | Stop the tunnel with a request in flight |
Редът за припокриване заслужава собствено изречение. VPN профил, който избутва маршрут за 172.17.0.0/16 или за 10.0.0.0/8, който случайно съдържа вашия префикс на моста, кара тунела да претендира за подмрежата на контейнерите и отговорите към преобразуваните адреси ще поемат в грешна посока или ще изчезнат. Пренумерирането на мрежата на Docker обикновено е по-чисто от натрупването на изключения.
Направете покритието явно, а после го счупете нарочно
Два дизайна издържат на преглед. Споделете пространството от имена на VPN контейнера и всяко покрито натоварване използва един тунел с една граница за рестартиране, което е просто, докато на една услуга не ѝ потрябва различен изход или собствен DNS път. Или насочете мрежата на контейнерите към VPN шлюз на хоста: препращането включено, префиксът на моста насочен към тунела, обратният трафик обработен явно. Това купува контрол за всяка мрежа и ви струва набор от правила, които да поддържате през надгражданията на демона и клиента.
Както и да е, тестът, който има значение, е случаят на отказ. Спрете тунела със заявка на контейнер в полет и наблюдавайте накъде отива пакетът. Ако се върне към директния път, покритието никога не е било наложено, защото kill switch на клиента управлява собствения трафик на клиента, а не препращаните пакети от мост. След това рестартирайте демона и хоста и потвърдете резултата втори път; това е моментът, в който написаните на ръка правила изчезват.
Преди да го обявите за готово, потвърдете четири неща: интерфейсът на тунела е в същото пространство от имена като трафика, тестът на контейнера е проведен вътре в истинския контейнер, разрешаването на имена и двете семейства адреси са проверени и тестът за отказ на тунела все още се проваля затворено. След това запишете firewall основата, версията на клиента и собственика на всяко правило. Именно този запис не позволява на следващото надграждане да остави недокументирана смесица от стари допускания на място.