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

Я зустрів це на вузлі Debian з образом OpenVPN, встановленим через chart, і тунель був легкою частиною. Клієнт отримав оренду 10.8.0.x, 10.8.0.1 відповів, а 10.96.0.10, кластерна служба DNS, завершилася за тайм-аутом. У журналі сервера нічого не виглядало хворим, і саме тому люди починають переписувати правила iptables, яких їм ніколи не потрібно було торкатися.

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

Чого клієнт може і не може досягти

Адреса, що відповідає, належить кінцевій точці тунелю, і процес VPN володіє нею локально, тож пересилання взагалі не бере участі. Усе інше, включно з іншим подом, VIP служби або інтернетом, потребує, щоб ядро перемістило пакет з tun0 на eth0. Коли це переміщення відхилено, симптом — рівномірна тиша, а не відмова, бо ніщо не генерує ICMP-помилку назад у тунель. Ви отримуєте тайм-аути, а не повідомлення про недосяжність, і це підказка, що ніхто взагалі не маршрутизує.

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

Прочитайте налаштування всередині namespace

Кожен под отримує власний мережевий namespace, а net.ipv4.ip_forward — це sysctl для кожного namespace. Зміна його на вузлі нічого не каже про контейнер, і це надійний спосіб провести день не на тій машині.

kubectl exec -it deploy/openvpn -- sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0

Нуль підтверджує діагноз. Значення також не успадковується з конфігурації часу виконання вузла: воно починається з типового образу щоразу, коли створюється контейнер. Тому виправлення, застосоване вручну з kubectl exec ... sysctl -w, зникає при наступному перезапуску і повертається як несправність, що виглядає періодичною.

Увімкнути так, щоб маніфест це зберіг

Довговічний варіант — init-контейнер, який працює в тому самому pod sandbox і записує значення до запуску контейнера VPN. Контейнери в поді поділяють мережевий namespace, тож налаштування переноситься в основний контейнер.

initContainers:
- name: enable-forwarding
  image: busybox:1.36
  command: ["sysctl", "-w", "net.ipv4.ip_forward=1"]
  securityContext:
    privileged: true

Саме privileged: true — той рядок, проти якого заперечують рецензенти, і вони праві. Запис sysctl потребує або привілею, або вузько обмеженої можливості, а кластер з обмежувальним Pod Security Standard може взагалі відмовити в привілейованому init-контейнері. Якщо admission відхилить под, ви дізнаєтеся про це під час створення, що принаймні чесно і легко читається.

Чистіший варіант — список securityContext.sysctls на рівні пода, який дозволяє kubelet застосовувати sysctl з простором імен, не даючи привілеїв жодному контейнеру. Він охоплює лише імена зі списку дозволених кластера. Чи є net.ipv4.ip_forward у цьому списку, залежить від того, як налаштовано kubelet, а под, що запитує sysctl поза ним, відхиляється при admission або застрягає в CreateContainerConfigError, поки sandbox повторюється. Перевірте список дозволених, перш ніж вважати, що поле зламане.

Перш ніж будувати будь-який із підходів вручну, подивіться, чи chart уже виставляє перемикач, часто у вигляді чогось на кшталт ipForwardInitContainer: true. Використання значення з chart залишає ваш файл перевизначення малим і переживає наступне оновлення, чого ручні правки Deployment не роблять.

Друга половина: зворотний шлях і політика

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

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

Коли клієнтам потрібно досягати лише служб усередині кластера, завершення VPN на VIP служби — компактніший дизайн, ніж маршрутизація в мережу подів. Він також повністю тримає пул клієнтів поза таблицею маршрутизації CNI.

Ізолювати збійний перехід від клієнта

Працюйте назовні й зупиніться на першому тихому кроці. Почніть із піра VPN, потім спробуйте адресу якогось пода, потім VIP служби й лише після цього публічне призначення. Кожен успіх зсуває межу на один перехід, а кожна невдача називає шар, який варто оглянути. Після будь-якого розгортання увійдіть через exec і прочитайте sysctl знову, бо замінений под починається з типового образу, а виправлення, якого ніколи не було в маніфесті, вже зникло.

Документація Kubernetes про використання sysctl у кластері перелічує, які імена можна задати через контекст безпеки пода, і це перше місце, куди дивитися, коли admission відхиляє зміну.

Схожі статті