Контейнерът ви все още отговаря на контролния мост, но всеки изходящ пакет излиза през офисния macvlan. Нищо не се е счупило. Две връзки дават по един шлюз и единственият маршрут по подразбиране отиде към мрежата, която не сте имали предвид, така че услугата продължава да работи, докато трафикът ѝ поема по-дълъг път. Когато някой го забележи, доказателството е таблица за маршрутизация, а не съобщение за грешка.

Обичайното обяснение е, че Docker е избрал мрежата случайно. На практика старото решение следваше азбучния ред на имената на прикачените мрежи, което превръщаше маршрутизацията в страничен ефект от етикет. gw_priority заменя това с число, което избирате нарочно, и преминаването към него отнема около минута, след като схемата е записана.

Защо маршрутът по подразбиране попада в грешната мрежа

Всяка мрежа, към която се присъединява услуга, може да предложи свой шлюз, а контейнерът все пак получава точно един маршрут по подразбиране. Преди Compose 2.33.1 равенството се решаваше чрез сортиране на имената на мрежите, така че етикет като control, който идва преди office, решаваше накъде отива трафикът. Нищо в контейнера не записва, че решението е произволно, и точно затова то преминава през преглед на кода и по-късно излиза наяве като странен път. Полагането на политика във файла compose е единственият начин изборът да стане проверим.

Наистина две неща променят коя мрежа печели: стойностите на gw_priority, които задавате, и кои мрежи изобщо са прикачени. Добавете трета мрежа и наборът от кандидати расте; махнете macvlan и не остава нищо, което да се конкурира с моста. Нито едно от двете не се вижда в журналите на приложението, защото грешният маршрут по подразбиране рядко прекъсва връзката напълно. Той само кара отговорите да пристигат от адрес, който другата страна може да не очаква.

Закрепете шлюза с gw_priority

Compose показва gw_priority за всяка връзка услуга-мрежа от версия 2.33.1 и печели по-високото число. Няма отделен ключ за шлюз на услуга, затова стойността принадлежи в блока networks на услугата. Примерът по-долу дава маршрута по подразбиране на control, като оставя office достъпна за нейната директно свързана LAN.

services:
  vpn:
    networks:
      control:
        gw_priority: 1
      office:
        gw_priority: 0

networks:
  control:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.50.0/24
  office:
    driver: macvlan
    driver_opts:
      parent: eno1.120
      macvlan_mode: bridge
    ipam:
      config:
        - subnet: 192.168.120.0/24
          ip_range: 192.168.120.192/27
          gateway: 192.168.120.1

Четете блока като две отделни управления: gw_priority решава маршрута по подразбиране, а секцията ipam решава адресирането. Промяната само на subnet оставя избора на изход непокътнат и това е най-честият начин тази поправка да бъде приложена наполовина. Дръжте приоритетите до мрежата, която управляват, за да не се налага следващият читател да търси решението.

Не бъркайте gw_priority с обикновеното свойство priority до него. То подрежда създаването на връзки и не казва нищо за маршрутизацията, затова не може да избере шлюз по подразбиране и не поправя именуването на интерфейсите. Ако някой препоръча да вдигнете priority, за да насочите трафика, препоръката е грешна, дори когато полученият ред случайно изглежда правилен.

Проверете коя мрежа наистина носи маршрута по подразбиране

Проверявайте вътре в работещия контейнер, защото таблицата за маршрутизация на хоста описва хоста, а не пространството от имена, което ползва услугата. Пуснете първо проверката на конфигурацията, за да се провали печатна грешка преди рестарт, после прочетете маршрута, който контейнерът наистина е инсталирал.

docker compose config --quiet
docker exec vpn ip -4 route show default
docker exec vpn cat /proc/net/route

Правилният резултат посочва мостовото устройство и 172.30.50.1; грешният посочва 192.168.120.1 и устройството macvlan. Ако образът не съдържа пакет iproute2, файлът /proc все пак отчита маршрута по подразбиране, с дестинация 00000000 и байтове на шлюза в обратен ред. Сравнете колоната за интерфейс с docker inspect, когато имената на устройствата не са ясни.

Macvlan е физически порт, а не клонинг на мост

Macvlan дава на контейнера втора идентичност в мрежата и точно това прави достъпа до локални устройства работещ. Също означава, че портът на комутатора и хипервизорът трябва да приемат допълнителен MAC адрес, а много облачни мрежи тихо отказват това. Тествайте един контейнер, преди да планирате флот, защото отказан MAC обикновено изглежда като връзка, която е вдигната и не пропуска нищо.

Настройката macvlan_mode: bridge е режим на драйвера macvlan, а не софтуерният мост на Docker, а passthru е отделен специализиран режим, а не стандартен. Linux също пречи на macvlan контейнер да достигне собствения си хост през същия родител и точно затова контролният мост се запазва, вместо да се очаква една връзка да свърши и двете работи.

Наименувайте родителя на VLAN, преди Compose да го види

Docker третира родител с точка като eno1.120 като подинтерфейс 802.1Q и сам създава VLAN устройството. Това удобство има граници: производното име зависи от името на физическия интерфейс, а дългите имена могат да избутат резултата отвъд очакванията на околните инструменти. Създаването на именуван VLAN интерфейс в мрежовата конфигурация на хоста и насочването на parent към него прави двата края предвидими.

Запомнете, че ключът под networks е име на Compose, а не Linux устройство. Търсенето на хост на интерфейс с име office ще се провали, защото ядрото вижда само родителския интерфейс и двойката veth зад контейнера.

Освободете място за VPN отгоре

VPN клиентът се прикачва след като тези мрежи съществуват, така че може да добави по-конкретни маршрути, правила за политика и филтри независимо от gw_priority. Планирайте отдалечените префикси спрямо двете локални подмрежи, включително отговорите, които контролният път изисква. Когато отдалечен префикс се застъпва с офис LAN, поправете адресния план, вместо да изтръгнете цял частен диапазон от тунела.

Проверете отново адресите, маршрутите и пътя на услугата след стартиране на VPN и отново след повторно свързване, защото именно при повторно свързване изчезва ръчно добавен маршрут. Запишете очакваната таблица преди първия тест, за да бъде сравнението след това diff, а не упражнение по памет. Пазете постоянната собственост върху мрежата в Compose и оставете VPN конфигурацията да притежава само своята политика.

Подобни статии