Хост працює через тунель, а контейнер поруч не дістає нічого. Публікувати порт із контейнера, який має власний клієнт VPN, ще гірше: запит надходить, а відповідь ніколи не виходить. Обидва — рішення про маршрутизацію на хості, а Docker лише посланець.

Три питання визначають, який із двох випадків перед вами, і це триває близько хвилини.

Дві несправності, які виглядають однаково

Перша — проблема зворотного шляху. Опублікований порт транслюється в контейнер, запит надходить, і відповідь маршрутизується через маршрут за замовчуванням хоста, який клієнт OpenVPN спрямував на tun0. Відповідь виходить з адреси, якої віддалена сторона не очікує, і відкидається. Друга — конфлікт префіксів: стандартний міст Docker володіє 172.17.0.0/16, а корпоративний тунель проштовхує той самий діапазон.

Одна виправляється таблицею маршрутизації, друга перенумерацією моста. Редагувати, не знаючи, який випадок перед вами, — так і ламають робочий контейнер.

Виріште за допомогою трьох питань

Питання перше: чи зникає несправність, коли ви зупиняєте VPN? Якщо при вимкненому тунелі все працює, підозрюйте зворотний шлях. Питання друге: чи перелічує ip route show table all той самий префікс двічі, один раз на мосту й один раз на tun0? Це і є конфлікт. Питання третє: уражена адреса — це контейнер, гість NAT чи гість за мостом?

Третє питання важливе, бо кожен має інше правильне виправлення, а застосування виправлення для контейнера до гостя libvirt марнує цілий вечір.

ip route
ip route show table all | grep -E '172\.1[7-9]|10\.8'
docker network inspect bridge --format '{{.IPAM.Config}}'

Зворотний шлях: таблиця для однієї адреси джерела

Коли трафік контейнера має виходити через фізичний інтерфейс, поки сам хост використовує тунель, маршрутизація за джерелом — найменша зміна. Додайте правило, що збігається з адресою контейнера, і надішліть його в окрему таблицю. Більше нічого на хості не рухається.

ip rule add from 172.22.0.3 lookup 10
ip route add default via 172.22.0.1 table 10

Кожен пакет, джерелом якого є ця адреса, спершу звертається до таблиці 10, і таблиця 10 надсилає його на шлюз моста замість тунелю.

Перевірте за допомогою ip route get 1.1.1.1 from 172.22.0.3. Відповідь має називати інтерфейс моста, а не tun0. Правила, додані в такий спосіб, зникають після перезавантаження, тож помістіть їх у unit або мережевий хук, якому належить контейнер.

Той самий шаблон працює для контейнера WireGuard, де зворотному шляху теж потрібне явне правило.

Конфлікт префіксів: перенумеруйте міст

Таблиця маршрутизації надсилає один префікс в одне місце. Якщо VPN проштовхує 172.17.0.0/16, а міст Docker уже там, перемагає менша метрика: Docker встановлює свій підключений маршрут із метрикою 0, а проштовхнутий маршрут надходить із 50. Тоді тунель виглядає зламаним, поки Docker продовжує працювати, або навпаки, залежно від порядку встановлення. Перенумеруйте міст замість боротьби з метрикою.

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

Після зміни перезапустіть Docker і заново створіть мережі, збудовані на старому пулі. Зміна метрики лише переносить конфлікт на наступне завантаження.

Віртуальним машинам знову потрібна інша відповідь

Гість libvirt у стандартній мережі NAT успадковує маршрутизацію хоста і перестає виходити назовні, щойно тунель хоста заволодіє маршрутом за замовчуванням. Переведення гостя на мостове або macvtap-пристрій дає йому власний шлях у фізичній мережі. У virt-manager додайте обладнання, виберіть Network, задайте джерелом macvtap-пристрій хоста, залиште virtio моделлю, а потім вимкніть старий інтерфейс NAT.

Гість macvtap зазвичай не може дістатися свого хоста. Це очікувана поведінка, а не несправність, і їй місце в нотатці, яку ви залишаєте.

Для гостя, якому потрібна лише локальна мережа хоста, у клієнті постачальника може бути відсутній перемикач: з Mullvad mullvad lan set allow відновлює локальну доступність, не торкаючись libvirt. А коли контейнер має бути доступним лише через тунель, прив'яжіть опублікований порт до адреси тунелю, -p 10.8.0.5:8080:8080, замість публікації на кожній адресі.

Схожі статті