Один хост, два робочі навантаження й вимога, яка їх розділяє: клієнт завантаження, який має виходити через комерційний VPN, і інтерфейс керування, який має далі використовувати з'єднання хоста. Встановлення VPN-клієнта на хості одразу порушує вимогу, бо тоді обидва навантаження ділять один вихід. Схема, яка справді працює, — перенести тунель у власний контейнер і дозволити лише тим навантаженням, яким він потрібен, приєднатися до мережевого простору імен цього контейнера. Усе інше зберігає звичайний шлях Docker, а деталі, що йдуть далі, — наслідки того, хто володіє простором імен.

Чому спільний простір імен змінює правила

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

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

Loopback — та частина, яка дивує людей. Усередині контейнера, що приєднується, localhost розв'язується в loopback бічного контейнера, а не у власний приватний, тож служба, яка прив'язується до 127.0.0.1 в очікуванні ізоляції, тепер ділить цю адресу з контейнером тунелю.

Публікуйте порти на контейнері, який володіє простором імен

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

services:
  gluetun:
    image: qmcgaw/gluetun
    cap_add: [NET_ADMIN]
    ports: ["8080:8080"]
  client-vpn:
    image: example/client
    network_mode: "service:gluetun"
  client-direct:
    image: example/client
    ports: ["8081:8080"]

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

Служба, яка залишається прямою, зберігає власну мережу

Навантаження, яке не має проходити через тунель, зберігає міст за замовчуванням або власну мережу, визначену користувачем, зі своїм опублікованим портом і своїм виходом. Спокусливо під'єднати його до мережі бічного контейнера, щоб два контейнери могли говорити за іменем, але цей єдиний крок тихо переносить його трафік у тунель. Якщо їм треба досягати одне одного, побудуйте окрему мережу, визначену користувачем, під'єднайте обидва до неї й залиште бічний контейнер єдиним шляхом назовні.

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

Матриця відмов на першу годину

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

SymptomLikely cause
Web UI unreachable after the changePort mapping declared on the joining container instead of the sidecar
Both containers show the provider's exit addressThe direct service was attached to the sidecar network
Internal names stop resolvingResolver settings live on the host, not in the shared namespace
Health check fails but the app worksThe check probes localhost, which now means the sidecar

Четвертий рядок — той, який люди помилково діагностують як помилку застосунку. Перевірка, написана проти власного loopback навантаження, тепер тестує контейнер тунелю, тож вона або зазнає невдачі, або повідомляє про цілком неправильну службу.

Коли одному імені хоста потрібен тунель

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

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

Перевірте, а потім зробіть так, щоб це пережило перезапуск

Запитайте кожен контейнер, з якої адреси він, судячи з усього, приходить. Той, що в тунелі, має вивести адресу постачальника, а прямий — вихід хоста. Однакові відповіді означають, що пряма служба успадкувала неправильний простір імен або VPN на рівні хоста все ще перехоплює все, і ці дві правки різні. Запускайте перевірку знову після кожної правки compose, бо одного скопійованого блоку служби достатньо, щоб повернути проблему.

Три речі зазвичай ламаються пізніше. DNS іде за власником простору імен, тому налаштування розв'язувача й домену пошуку належать бічному контейнеру, а не хосту. VPN із переадресацією портів змінює свій порт прослуховування під час повторного підключення, тому переадресований порт постачальника й порт прослуховування на боці контейнера треба записати назад у конфігурацію клієнта або в зіставлення портів, зазвичай невеликим оновлювачем, який читає API постачальника. І будь-яка перевірка, написана проти localhost, тепер запитує контейнер тунелю, а не навантаження.

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

Схожі статті