Від LB Ingress до ZTM — новий підхід до відкриття кластерних сервісів

pic

Зображення з https://www.pexels.com/

28 грудня (у минулу суботу) я мав честь взяти участь у заході “Cloud Native + AI Meetup Guangzhou”, який був спільно організований спільнотами KubeSphere та Higress. Під час заходу я виступив з презентацією на тему “Від LB Ingress до ZTM: Новий підхід до виставлення кластерних сервісів”. Тут я поділюсь вмістом моєї доповіді з незначно зміненою назвою.

Необхідність виставлення кластерних сервісів

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

Services надають Pods стабільне DNS-ім’я та віртуальну IP-адресу, не покладаючись на тимчасові IP-адреси Pods. Тому для внутрішньої комунікації в кластері доступ через ClusterIP Service працює без проблем.

Однак ClusterIP Service доступний лише всередині кластера, і до нього неможливо звертатися ззовні. DNS-ім’я сервісу можна резолвити лише всередині кластера. Ця мережева ізоляція, яка виступає як механізм захисту, гарантує, що доступ до Pods і сервісів обмежений лише всередині кластера.

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

Методи виставлення кластерних сервісів

Kubernetes надає кілька абстракцій для виставлення кластерних сервісів. Для зовнішнього доступу існують LoadBalancer, NodePort та більш розвинене Ingress (яке може поступово бути замінене Gateway API, але обидва інтерфейси є суттєво подібними в реалізації. Далі під терміном “Ingress” мається на увазі управління входом трафіку на високому рівні в Kubernetes).

Кожен підхід працює по-різному, має свої переваги та недоліки і підходить для різних сценаріїв.

LoadBalancer

pic

LoadBalancer є одним з поширених способів виставлення кластерних сервісів. У хмарних середовищах використання балансувальника навантаження від постачальника хмарних послуг може розподіляти трафік до кількох Pods у кластері. У локальних середовищах можна використовувати відкриті балансувальники навантаження. Наше обговорення зосереджене головним чином на відкритих балансувальниках.

kubectl get service  
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE  
nginx LoadBalancer 10.43.177.15 192.168.2.1 80:32186/TCP 2m18s

У відкритих балансувальниках сервісів є два основних типи реалізації. Перший включає кілька прикладів, таких як MetaLB, OpenELB від QingCloud, kube-vip та PureLB. Ці реалізації є по суті подібними: кожна з них запускає контролер Pod на кожному вузлі кластера. Цей контролер Pod слухає зміни для сервісів типу LoadBalancer, після чого налаштовує VIP для них та прив’язує VIP до мережевого інтерфейсу вузла.
Нарешті, VIP оголошується у зовнішній мережі через ARP (рівень 2) або BGP (рівень 3).

Якщо існує кілька маршрутів до певного VIP, для розподілу трафіку між кількома вузлами часто використовується маршрутизація Equal-Cost Multi-Path (ECMP), що забезпечує балансування навантаження.

pic

Другий тип реалізації є відносно простішим, наприклад, ServiceLB в K3s (раніше Klipper), який базується на iptables та HostNetwork. Коли він виявляє, що сервіс типу LoadBalancer було створено, ServiceLB створює DaemonSet (DS) для цього сервісу. DS створює проксі-контейнер на кожному вузлі, використовуючи мережевий режим hostNetwork та hostPort для порту сервісу.

Точкою входу є IP кожного вузла. Коли проксі-контейнер отримує трафік, він перенаправляє його до clusterIP сервісу через iptables, а потім до Pods.

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

NodePort

pic

Якщо LoadBalancer є більш розвиненим підходом, то NodePort є найбільш прямолінійним. NodePort — це тип сервісу, який відкриває фіксований порт (30000–32767) на кожному вузлі в кластері, перенаправляючи трафік на цей порт до Pods у бекенді.

Для кожного сервісу типу NodePort Kubernetes призначає порт. kube-proxy, що працює на кожному вузлі, налаштовує правила iptables на основі інформації про сервіс і Pods. Таким чином, коли трафік надходить на порт NodePort вузла, iptables збігає його з відповідним сервісом і перенаправляє до Pods.

Що стосується сценаріїв, то NodePort підходить для малих кластерів або тестових середовищ, де не потрібне балансування навантаження; достатньо безпосередньо виставити IP та порт вузла. Його недоліки полягають у відсутності автоматичного балансування навантаження, виставленні IP вузлів і відносно слабкій безпеці.

Ingress

pic

Ingress — це вбудований об'єкт керування трафіком у Kubernetes, який визначає правила маршрутизації для HTTP або HTTPS. Ingress реалізується через Ingress Controller, який динамічно оновлює конфігурацію балансувальника навантаження на основі ресурсів Ingress для розподілу трафіку. З часом Ingress може бути замінений Gateway API, який пропонує більш гнучке розширення, але обидва підходи схожі на практиці: обидва залежать від проксі та контролера.

Тут ми використовуємо більш знайомий приклад Ingress:

apiVersion: networking.k8s.io/v1  
kind: Ingress  
metadata:  
 name: example  
spec:  
 rules:  
 - http:  
 paths:  
 - backend:  
 service:  
 name: foo  
 port:  
 number: 8080  
 path: /foo  
 - backend:  
 service:  
 name: bar  
 port:  
 number: 8080  
 path: /bar

Ingress призначений для роботи як єдина точка входу для кластера, керуючи кількома сервісами через маршрутизацію за доменами або шляхами. На відміну від LoadBalancer або NodePort, Ingress працює на 7 рівні моделі OSI, підтримуючи такі протоколи, як HTTP та HTTPS. Він надає розширені функції керування трафіком, такі як TLS offloading, обмеження швидкості, canary-релізи, переривання з'єднань та редиректи. Також можна реалізувати більш гнучке управління трафіком через складні правила маршрутизації.

Що стосується сценаріїв, то Ingress підходить для випадків, які потребують складних правил маршрутизації та підтримки HTTPS. Його недоліки включають відносно складну конфігурацію та необхідність наявності Ingress Controller.
Крім того, сам проксі Ingress все одно потрібно виставляти зовні, що вимагає додаткового LoadBalancer.

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

Мережа з нульовим відкриттям (ZTM)

Мережа з нульовим відкриттям, ZTM (Zero Trust Mesh), є децентралізованим тунельним мережевим програмним забезпеченням на основі HTTP/2, яке розроблено для сценаріїв, таких як віддалена робота та IoT-мережі на периферії. Це відкрите програмне забезпечення.

pic

ZTM може працювати на будь-якій існуючій IP-мережі, включаючи, але не обмежуючись, LAN, публічним Інтернетом, мережами контейнерів тощо. ZTM надає базовий мережевий фундамент для захисту комунікацій додатків, включаючи підключення, керування доступом на основі портів, зашифровані тунелі mTLS, ідентифікацію на основі сертифікатів, керування доступом, балансування навантаження та інші основні мережеві та безпекові можливості.

ZTM може працювати на різноманітних пристроях і підтримує кілька архітектур процесорів, таких як x86, ARM, MIPS, RISC-V і LoongArch, а також операційні системи, такі як Linux, Windows, macOS, FreeBSD і Android.

Архітектура ZTM

pic

Архітектура ZTM є досить простою:

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

Підключаючись до хаба ZTM, агенти можуть створювати безпечну мережу з нульовою довірою через будь-яку існуючу мережу — LAN, Інтернет, мережу контейнерів тощо — забезпечуючи безпечну комунікацію між пристроями.

У термінології ZTM ця мережа називається Mesh. Mesh — це логічна мережа, що утворюється кількома агентами, підключеними через зашифровані тунелі. Агент може підключатися до кількох Mesh-мереж для з'єднання з кількома мережами.

Можливості ZTM

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

ZTM App

Фреймворк zt-app — це фреймворк для розробки додатків, побудований на ZTM, який пропонує стандартизований інтерфейс розробки, що полегшує створення децентралізованих додатків для розробників. Цілі його проектування — «простота, легкість у використанні, безпека», надаючи зручні інструменти для розробки.

ZTM написаний на PipyJS, кастомізованому JavaScript, призначеному для Pipy. Розробники можуть зручно створювати додатки ZTM, використовуючи PipyJS.

У ZTM є кілька вбудованих ключових додатків:

  • zt-tunnel: Створює безпечні TCP/UDP тунелі між кінцевими точками.
  • zt-proxy: Проксі SOCKS/HTTP, яке отримує трафік від однієї кінцевої точки і перенаправляє його на іншу.
  • zt-script: Виконує скрипти віддалено на кінцевих точках.
  • zt-terminal: Надає віддалений доступ до терміналу кінцевих точок.

Тунель (zt-tunnel)

Тунель з нульовою довірою усуває обмеження фізичної відстані та мережевої ізоляції, дозволяючи отримати доступ до пристроїв з будь-якої точки.
zt-tunnel має два основні поняття:

  • Outbound: Точка виходу тунелю, розташована в мережі цільового пристрою.
  • Inbound: Точка входу тунелю, розташована в мережі сторони, що підключається.

pic

Наприклад, розглянемо сценарій, коли ми маємо дві ізольовані мережі, які підключені до мережі ZTM. У нашій офісній мережі є два пристрої: пристрій Windows, який підтримує Remote Desktop, і пристрій Linux, який підтримує SSH. Ми називаємо ці пристрої віддаленими пристроями.

Коли нам потрібно отримати доступ до цих двох пристроїв ззовні, ми просто створюємо два Outbounds (з назвами tcp/rdp і tcp/ssh-vm) на агенті ZTM в офісній мережі, кожен з яких вказує на один з віддалених пристроїв.

На агенті ZTM в зовнішній мережі ми створюємо два Inbounds, кожен з яких вказує на один з вищезгаданих Outbounds і вказує порт. Коли нам потрібно отримати доступ до віддалених пристроїв, ми повинні звернутися лише до адреси локального агента та вказаного порту входу, наприклад, curl http://192.168.1.30:8080.

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

Проксі (zt-proxy)

Використання zt-tunnel для доступу до пристроїв вимагає створення Outbounds та Inbounds для кожного сервісу, що може бути складним. zt-proxy може спростити цей процес, дозволяючи доступ до пристроїв через проксі.

pic

zt-proxy може забезпечити HTTP або SOCKS проксі для сторони, що підключається. На агенті ZTM в цільовій мережі просто додаються адреси цільових пристроїв для проксі (як підмережі IP, так і доменні імена з підстановочними знаками). Тоді зовнішньому користувачеві потрібно лише знати цільову IP-адресу або доменне ім'я, і він може отримати доступ до пристроїв через проксі.

Використовуючи підмережі IP або доменні імена, можна додавати пристрої пакетно, що робить цей підхід підходящим для сценаріїв з багатьма пристроями. З проксі можна отримати доступ до віддалених пристроїв так, ніби ви знаходитеся в одній мережі LAN.

Після ознайомлення з основами ZTM, тепер ми можемо розглянути, як використовувати його для відкриття кластерних сервісів.

Використання ZTM для відкриття кластерних сервісів

Дехто вже міг здогадатися, що ZTM можна використовувати для з’єднання мереж як всередині, так і поза кластером — або навіть для кількох кластерів.

Використовуючи хаб ZTM, ми можемо розгорнути агентів ZTM як всередині, так і поза кластером для встановлення безпечного підключення. Навіть в двох ізольованих мережах ми можемо отримати доступ до внутрішніх сервісів кластера через тунель HTTP/2, наданий ZTM.

Відкриття кластерних сервісів через zt-tunnel

pic

У цьому сценарії ми використовуємо мережу Mesh ZTM для підключення ізольованих мереж всередині та поза кластером. Всередині кластера ми можемо створити Outbound через zt-tunnel для будь-якого сервісу, який потрібно відкрити зовні, а потім створити Inbound на зовнішньому агенті ZTM. Таким чином, ми можемо отримати доступ до внутрішнього сервісу кластера через тунель ZTM.

Коли Inbound і Outbound тунелю налаштовані, ми можемо отримати доступ до сервісу A кластера, використовуючи IP-адресу агента та вказаний порт Inbound тунелю, наприклад, curl http://192.168.1.30:8080.

Якщо потрібно отримати доступ до інших сервісів, просто створіть додаткові Outbounds та Inbounds для них.

Відкриття кластерних сервісів через zt-proxy

pic

Якщо потрібно відкрити багато сервісів, zt-proxy може спростити цей процес.
Коли мережа Mesh підключена, ви можете налаштувати zt-proxy в кластері для націлювання на внутрішній DNS кластера, наприклад, *.svc.cluster.local, тим самим відкриваючи всі сервіси в кластері як цілі проксі — або ж можна обмежити це лише сервісами в конкретному просторі імен.

Потім ви можете отримати доступ до внутрішніх сервісів кластера, використовуючи проксі зовнішнього агента, наприклад:

curl -x http://192.168.1.30:8080 http://svc-a.svc:8080

Контролюючи DNS-імена сервісів, що підлягають відкриттю, ви можете керувати діапазоном відкритих сервісів.

Демонстрація

Щоб продемонструвати, як ZTM відкриває кластерні сервіси, ось проста демонстрація.

pic

У цій демонстрації створено два абсолютно ізольовані кластери за допомогою K3d, які потім з'єднуються через ZTM. Після цього демонструється, як використовувати як тунелі ZTM, так і проксі для забезпечення доступу до сервісів між кластерами.

Не соромтеся спробувати, якщо вам цікаво.

Порівняння рішень

Після того, як ми ознайомилися з різними способами відкриття кластерних сервісів і пояснили ZTM, давайте порівняємо ці підходи.

| Функція | NodePort | LoadBalancer | ZTM |
|-----------------------------------|------------|---------------|----------------------------|
| Технічний принцип | iptables DNAT (BGP/ARP) | HTTP/2 зворотний тунель | HTTP/2 зворотний тунель |
| Метод доступу | IP вузла + фіксований порт | Хмарний / open-source LB + зовнішній IP | Тунель, проксі |
| Мережеві вимоги | Вузол повинен мати фіксовану або доступну IP-адресу | Зовнішня IP-адреса, мережеве середовище BGP/ARP | Немає прямого мережевого доступу |
| Застосовні сценарії | Маленькі кластери / тестові середовища з швидким доступом | Публічні хмарні кластери, що потребують високо доступного й стабільного зовнішнього доступу | Безпечні сценарії нульової експозиції, віддалений і міжкластерний доступ |
| Легкість використання | Прості й прямі налаштування, мало конфігурацій | Автоматизоване налаштування, залежне від хмарних платформ або open-source балансувальників навантаження | Потрібно розгорнути агент ZTM і хаб |

Більше варіантів використання ZTM

Віддалене виконання команд (zt-terminal)

pic

zt-terminal — це термінал з нульовою довірою, який на основі "пристрій + сертифікат" для ідентифікації та контролю доступу забезпечує віддалений командний інтерфейс. Після авторизації один пристрій може виконувати команди оболонки на іншому пристрої.

На стороні віддаленої мережі налаштовуємо користувача, який може виконувати команди:

ztm terminal config --add-user zt-user1

Потім на локальній мережі можна отримати доступ до оболонки на вказаному пристрої:

ztm terminal open ep-office

Розподілений обмін файлами (zt-cloud)

pic

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

Інші сценарії

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

  • Проникнення в інтранет
  • Віддалена робота
  • Безпечний доступ до хмарних ресурсів
  • Віддалене налагодження
  • Міжкластерне з'єднання
  • Віддалений доступ до пристроїв
  • Обмін файлами

Висновок

У цій доповіді ми обговорили необхідність відкриття кластерних сервісів і поширені методи для цього в Kubernetes. Потім ми представили основи ZTM, його можливості та як використовувати ZTM для відкриття кластерних сервісів.

Сподіваюся, ця доповідь допомогла вам зрозуміти основні концепції та можливості ZTM, а також як використовувати ZTM для відкриття кластерних сервісів.

Перекладено з: From LB Ingress to ZTM — A New Approach to Cluster Service Exposure

Leave a Reply

Your email address will not be published. Required fields are marked *