Контејнерите одговараат на канцелариската локална мрежа, а потоа престануваат да одговараат во мигот кога ќе се поврзе корпоративниот VPN. Во контејнерот ништо не се промени: нема рестарт, нема ажурирање на сликата, нема измена на конфигурацијата. Она што се промени е табелата за рутирање на домаќинот, каде рутата што ја додаде тунелот сега ја покрива адресата што ја додели Docker. Пред да уредувате подмрежа или да барате исклучок од VPN, поставете ги двата плана на адреси еден до друг, бидејќи поправките одземаат многу различно време.

Прочитајте ја рутата пред да ја менувате конфигурацијата

Започнете со мрежата што Docker навистина ја изгради. Блокот IPAM е планот на адреси, а подмрежата е линијата што е важна:

docker network inspect project_default --format '{{json .IPAM.Config}}'
# [{"Subnet":"172.18.0.0/16","Gateway":"172.18.0.1"}]

Compose стандардно доделува /16 на секој нов проект, па два сервиса можат да се сместат во опсег од 65,536 адреси. Токму таа ширина е причината зошто преклопувањата се чести: случајно избран /16 е доволно голем да проголта локација до која стигнувате преку тунелот, и никој не забележува додека тунелот не се подигне.

Потоа споредете го изборот на рута за една адреса на контејнер, еднаш со исклучен тунел и еднаш со вклучен:

ip route get 172.18.0.7
# 172.18.0.7 dev br-3f2a9c src 172.18.0.1

Два вида одговор водат до различни места. Ако излезот ги наведува tun0, wg0 или друг уред за тунел, VPN префиксот е барем исто толку специфичен како рутата преку мостот и пакетот никогаш не стигнува до контејнерот. Ако сѐ уште го наведува мостот, домаќинот може да стигне до контејнерот, и вашата грешка е филтрирање, DNS или повратен пат што паѓа само во една насока.

Зошто судирот на /16 лесно се постигнува

Docker ги црпи мрежите преку мост од приватните базени, а стандардниот базен излегува од блокот 172.16.0.0/12 на парчиња од /16. Корпоративните мрежи често го користат истиот приватен простор, а VPN-от за далечински пристап ги турка тие префикси до секој клиент што се поврзува. Кога двете страни веруваат дека поседуваат 172.18.0.0/16, една табела за рутирање содржи две противречни тврдења.

Должината на префиксот одлучува за победникот, а не редоследот на рутите. Тунел што турка 10.0.0.0/8 не ја победува рутата преку мостот 172.18.0.0/16, бидејќи /8 е помалку специфичен. Тунел што турка 172.18.0.0/16, или 172.18.5.0/24 во него, победува. Затоа еден лаптоп работи на канцелариската мрежа, а не успева на Wi-Fi во хотел со истиот VPN: клиентот добива различни префикси.

Истата табела управува и со спротивната насока. Контејнер на кој му треба внатрешен домаќин на 10.8.4.20 го испраќа пакетот до својата порта на мостот, а домаќинот потоа го рутира во тунелот. Тој пат обично работи бидејќи домаќинот го извршува NAT, но паѓа кога корпоративната страна ја прифаќа само VPN адресата на лаптопот, или кога филтрирањето на повратниот пат го отфрла асиметричниот одговор.

Споредете ги трите поправки

Има само три излези, и тие се разликуваат по тоа кој треба да ги одобри и што се крши додека применувате еден.

RepairWho owns itWhat it costs
Renumber the container networkYouRecreates the network, restarts services, invalidates literal addresses in configs and scripts
Exclude your range from the tunnelNetwork teamChanges what every laptop sees, needs a change request and a client profile update
Reach the service through a published portYou and the clientOne port only, no direct container-to-container routing across the tunnel

Пренумерувањето е единствената поправка што можете да ја завршите без тикет, затоа повеќето написи запираат тука. Евтино е на млад проект, а скапо откако миграциска алатка или зачуван текстуален низ за поврзување ќе покаже на буквална адреса. Избројте ги тие референци пред да го уредите YAML, а не потоа.

Исклучокот од тунелот е најчистиот одговор кога преклопувањето е во опсег што вашата компанија навистина го поседува. Тој е и најбавниот, и е бескорисен за изведувач што не може да го смени профилот на клиентот. Објавен порт или мал обратен прокси го избегнува спорот: клиентот разговара со адреса што тунелот веќе ја рутира правилно, и само тој порт треба да биде достапен.

Закачете опсег намерно

За еден проект, декларирајте ја подмрежата во compose-датотеката за проектот да престане да црпи од заедничкиот базен:

networks:
  default:
    ipam:
      config:
        - subnet: 10.201.7.0/24

Земете го тој опсег од регистар што го води вашиот тим, а не од пример што го најдовте при пребарување. Проверете го наспроти префиксите што ги турка VPN-от, домашните мрежи од кои луѓето работат и другите контејнерски мрежи на истиот домаќин. Потоа испланирајте го пресоздавањето, бидејќи постоечката мрежа ја задржува старата подмрежа: docker compose down, потоа up -d. docker network rm одбива додека има прикачени крајни точки, и секој запис ipv4_address во датотеката мора да падне во новиот опсег.

За мрежи што Docker ги создава сам, поставете базен на демонот во /etc/docker/daemon.json:

{
  "default-address-pools": [
    { "base": "10.201.0.0/16", "size": 24 },
    { "base": "10.202.0.0/16", "size": 24 }
  ]
}

Базенот се применува на мрежи создадени откако демонот ќе се рестартира, а мостовите што веќе постојат ги задржуваат своите адреси. Тоа е погодно и лесно се заборава, затоа третирајте го стариот проект како сѐ уште да се преклопува додека некој не ја пресоздаде неговата мрежа. Docker документацијата за вмрежување на двигателот ги опишува правилата за доделување ако треба да го одбраните базенот при преглед.

Linux мостот и Docker Desktop паѓаат различно

На Linux домаќин, контејнерите стојат на мостови во именскиот простор на домаќинот. Една табела одлучува за сѐ, па споредбата погоре е целата приказна: прочитајте ја рутата преку мостот, прочитајте ја рутата низ тунелот и видете која победува за вистинска адреса на контејнер.

Docker Desktop ги става контејнерите зад виртуелна машина со сопствен NAT. Домаќинот воопшто нема рута до адресата на контејнерот; до сервисот стигнува преку објавен порт, обично врзан за 127.0.0.1. Затоа VPN клиентот може да го расипе сервисот без никакво преклопување на подмрежи: или со поставување рута за внатрешниот опсег на виртуелната машина, или со блокирање на loopback сообраќајот додека тунелот е поврзан. Ако ip route get на домаќинот пријави дека нема рута за адресата на контејнерот, тоа е очекувано, а не грешката.

Практичната последица е каде прво гледате. На Linux, започнете со табелата за рутирање. На Desktop, започнете со објавениот порт и правилата на огнениот ѕид на VPN клиентот, потоа проверете дали внатрешната подмрежа на виртуелната машина се судира со нешто што го турка тунелот.

Проверете со вклучен тунел

Поврзете го VPN-от двапати пред да го наречете поправено, бидејќи профил што додава рути при поврзување и ги повлекува при исклучување може да изгледа исправен по првиот обид. Потоа извршете ги проверките што клиентот навистина ги извршува:

  1. ip route get од домаќинот, користејќи ја вистинската адреса на контејнерот.
  2. Барање од друг контејнер, за да се докаже дека самиот сервис е здрав.
  3. curl -sv http://127.0.0.1:8080/ од клиентот со вклучен тунел, потоа traceroute -n до адресата на контејнерот од машина на локалната мрежа.
  4. sysctl net.ipv4.conf.all.rp_filter ако барањето стигне до домаќинот, но одговорот исчезне.

На крајот, запишете го избраниот опсег во истиот регистар од кој го избравте, со датумот и проектот што го поседува. Следното преклопување ќе дојде од проект што никој не го документирал, а единствената одбрана е опсегот да бил резервиран намерно, а не извлечен случајно.

Поврзани статии