Контејнерот не стигнува до API достапно само преку VPN? Проксирајте го на домаќинот
Тунелот живее на домаќинот, па контејнерот нема рута до приватната адреса. Објавете тесен обратен прокси и повикајте го како host.docker.internal.
Вашата Compose услуга истекува време кон API што прелистувачот на истиот компјутер го отвора без никаква жалба. Таа разлика е трагата: барањето што работи излегува од домаќин со VPN тунел, а барањето што виси излегува од контејнер со сопствен мрежен стек. Ништо во контејнерот не ги знае рутите на тунелот, па приватното одредиште останува недостапно како и да се напише името. Решението е намерен скок преку домаќинот, а не попаметна табела за рутирање.
Започнете со тоа зошто двата пата се разликуваат, потоа одлучете каде треба да живее тунелот.
Зошто домаќинот работи, а контејнерот не
Подигнувањето на тунелот му дава на домаќинот интерфејс, збир рути и обично запис во резолверот што го обезбедува VPN. Контејнерот не наследува ништо од тоа: тој започнува со еден интерфејс на мостот на моторот и стандардна рута што покажува кон тој мост. Рутите инсталирани на домаќинот се невидливи за сè што работи во тој именски простор.
Затоа симптомите изгледаат неконзистентни, а не само расипани. Домаќинот го решава приватното име и се поврзува, бидејќи таму постојат и името и рутата. Контејнерот го праќа својот пакет до приватна адреса до која ништо на патот преку мостот не може да стигне, и барањето истекува. Додавањето на името во датотеката hosts на контејнерот не менува ништо, бидејќи самата адреса е недостапна од каде што стои контејнерот.
Стигнете до домаќинот од внатрешноста на контејнерот
Процес во контејнерот што ѕвони на localhost ѕвони на контејнерот. Docker Desktop го објавува host.docker.internal како име што покажува назад кон машината што го води моторот; Linux моторите го оставаат недефинирано освен ако услугата го побара, а токму тоа го прави мапирањето подолу. Со тоа апликацијата цели на име и порта наместо на приватната адреса.
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
INTERNAL_API_HOST: "host.docker.internal:8666"Тунелот останува на страната на домаќинот од скокот, а портата во таа променлива е онаа на која проксито ќе слуша. Контејнерот што го губи тунелот сега паѓа на еден познат скок наместо да опита рута што никогаш ја немал.
Изберете каде живее тунелот
За Compose услуга што бара приватно API можни се три облици, и тие се разликуваат по тоа кој процес го поседува тунелот. VPN клиент може да работи внатре во сликата на контејнерот, што бара изложување на уред за тунел и давање на мрежната административна способност што оди со него. Апликацијата може да го дели мрежниот именски простор на посебен контејнер за тунел, така што двата процеса гледаат еден стек и една табела за рутирање. Или тунелот може да остане на домаќинот, со тесен преправувач од домаќинот во контејнерот.
Првите два влечат профилни датотеки, однесување при повторно поврзување и политика на резолверот во проектот и ја прават секоја услуга во датотеката зависна од здравјето на тунелот. Тоа е премногу поврзување за еден повик до API. За развојен стек што чита една внатрешна крајна точка, преправувачот на страната на домаќинот е најмалата промена што сепак ги чува акредитивите таму каде што ги управува тимот на платформата.
Објавете еден тесен пат на домаќинот
Започнете од тоа што го наследува преправувачот: стартувајте го со сметката што го поседува тунелот и неговите излезни сокети ги преземаат рутите на домаќинот и резолверот на домаќинот. Еден nginx location блок покрива еден пат.
server {
listen 8666;
location /search/ {
proxy_pass http://10.20.30.40:8090/;
proxy_set_header Host internal-api.example;
proxy_read_timeout 60s;
}
}Третирајте ја адресата и портата како замени и ставете го парот на кој API навистина слуша. Секој натамошен upstream заслужува свој location блок, и секој блок треба да ги пушта само патиштата што ги повикува оваа услуга, за да не стане проксито општа врата во приватната мрежа. Врзете го слушачот за адресата на мостот за клиенти што доаѓаат преку host-gateway, на loopback само кога клиентот го дели мрежниот именски простор на домаќинот, и никогаш на 0.0.0.0. Изберете и порта што сè уште е слободна: веќе зафатен број го остава проксито да не слуша додека контејнерот продолжува да истекува, што не може да се разликува од мрежниот дефект со кој почнавте.
Порти, имиња и одлуката за TLS
Решавањето на имиња се дели исто како рутирањето. Јавните пребарувања на контејнерот одат преку резолверот на моторот, па приватно име што се решава на домаќинот нема да се реши внатре во контејнерот. Проксито е компонентата што го решава приватното име, бидејќи го наследува резолверот на домаќинот.
TLS е одлуката што се одложува и потоа го објаснува следниот дефект. Ако проксито ги препраќа бајтите недопрени, контејнерот го гледа сопствениот сертификат на API и му треба внатрешно CA во неговото складиште за доверба. Ако проксито го завршува TLS, таа доверба се преместува на домаќинот и апликацијата почнува да гради врски од добиениот host заглавје. Изберете еден распоред и примените го на секој ресурс, бидејќи пренасочувањето издадено од другиот покажува на име на домаќин што контејнерот не може да го реши.
Проверете од внатрешноста на услугата
Испратете го барањето од контејнерот, не од домаќинот: обичен curl до патот на проксито, потоа сопствената проверка на здравјето на апликацијата. Кога проксито одговара, но апликацијата сè уште не успева, споредете три работи: основниот URL што го гради, која било прокси променлива во неговата околина и CA во кое верува. Сите се во околината и дневниците на контејнерот, и поправањето на кој било од нив го остава VPN на мира.
Запишете го избраниот распоред во README на проектот додека е сè уште свеж. Инаку следниот човек што ќе налета на овој тајмаут ќе го помине истото попладне откривајќи повторно дека тунелот живее на домаќинот.