Віртуальні IP та Проксі для Service

Кожен вузол у кластері Kubernetes запускає компонент kube-proxy (якщо ви не розгорнули власний альтернативний компонент замість kube-proxy).

Компонент kube-proxy відповідає за реалізацію механізму віртуальних IP для Service типу відмінного від ExternalName. Кожен екземпляр kube-proxy відстежує додавання та видалення обʼєктів Service and EndpointSlice у панелі управління. Для кожного сервісу kube-proxy викликає відповідні API (залежно від режиму kube-proxy) для налаштування вузла для перехоплення трафіку на clusterIP та port сервісу, і перенаправляє цей трафік на одну з точок доступу Service (зазвичай це Pod, але можливо також будь-яка інша IP-адреса, надана користувачем). Цикл керування забезпечує, що правила на кожному вузлі надійно синхронізуються зі станом Service та EndpointSlice, вказаним API сервером.

Механізм віртуальних IP для Service, використовуючи режим iptables

Інколи виникає питання, чому Kubernetes покладається на проксіювання для пересилання вхідного трафіку до бекендів. Що щодо інших підходів? Наприклад, чи можливо налаштувати DNS-записи, які мають кілька A-значень (або AAAA для IPv6), і покладатися на розвʼязання імен по колу?

Є кілька причин для використання проксіювання для Service:

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

Далі на цій сторінці ви можете прочитати про те, як працюють різні реалізації kube-proxy. В цілому, слід зазначити, що при запуску kube-proxy можуть бути змінені правила на рівні ядра (наприклад, можуть бути створені правила iptables), які не будуть очищені, в деяких випадках, до перезавантаження. Отже, запуск kube-proxy повинен здійснюватися тільки адміністратором, який розуміє наслідки наявності низькорівневого, привілейованого мережевого проксі-сервісу на компʼютері. Хоча виконуваний файл kube-proxy підтримує функцію cleanup, ця функція не є офіційною і тому доступна лише для використання "як є".

Деякі деталі у цьому довіднику стосуються прикладу: бекенд Pod для stateless навантаження з обробки образів, що працює з трьома репліками. Ці репліки замінні — фронтенди не турбує, який бекенд вони використовують. Хоча фактичні Podʼи, що складають бекенд-набір, можуть змінюватися, клієнти фронтенду не повинні бути обізнані про це і не повинні відстежувати набір бекендів самостійно.

Режими проксі

kube-proxy запускається в різних режимах, які визначаються його конфігурацією.

На Linux вузлах доступні режими для kube-proxy такі:

iptables
Режим, в якому kube-proxy налаштовує правила пересилання пакетів за допомогою iptables.
ipvs
Режим, в якому kube-proxy налаштовує правила пересилання пакетів за допомогою ipvs.
nftables
Режим, в якому kube-proxy налаштовує правила пересилання пакетів за допомогою nftables.

У Windows доступний лише один режим для kube-proxy:

kernelspace
Режим, в якому kube-proxy налаштовує правила пересилання пакетів у ядрі Windows.

Режим проксі iptables

Цей режим проксі доступний лише на вузлах Linux.

У цьому режимі kube-proxy налаштовує правила пересилання пакетів за допомогою API iptables підсистеми netfilter ядра. Для кожної точки доступу він встановлює правила iptables, які типово випадково вибирають бекенд Pod.

Приклад

Як приклад, розглянемо програму обробки образів, описану раніше на сторінці. Коли створюється бекенд Service, панель управління Kubernetes призначає віртуальну IP-адресу, наприклад, 10.0.0.1. Для цього прикладу припустимо, що порт Service — 1234. Усі екземпляри kube-proxy у кластері спостерігають за створенням нового Service.

Коли kube-proxy на вузлі бачить новий Service, він встановлює серію правил iptables, які перенаправляють з віртуальної IP-адреси на додаткові правила iptables, визначені для кожного Service. Правила для кожного Service посилаються на інші правила для кожної точки доступу бекенду, а правила для кожної точки доступу перенаправляють трафік (використовуючи NAT призначення) до бекендів.

Коли клієнт підключається до віртуальної IP-адреси Service, вступає в дію правило iptables. Вибирається бекенд (або на основі спорідненості сесії, або випадково), і пакети перенаправляються до бекенду без переписування IP-адреси клієнта.

Цей самий основний потік виконується, коли трафік надходить через node-port або через балансувальник навантаження, хоча в цих випадках IP-адреса клієнта змінюється.

Оптимізація продуктивності режиму iptables

У режимі iptables, kube-proxy створює кілька правил iptables для кожного Service та кілька правил iptables для кожної IP-адреси точки доступу. У кластерах з десятками тисяч Podʼів та Service це означає десятки тисяч правил iptables, і kube-proxy може потребувати багато часу на оновлення правил у ядрі, коли Service (або їх EndpointSlices) змінюються. Ви можете налаштувати поведінку синхронізації kube-proxy за допомогою параметрів у розділі iptables файлу конфігурації kube-proxy (який ви вказуєте через kube-proxy --config <path>):

...
iptables:
  minSyncPeriod: 1s
  syncPeriod: 30s
...
minSyncPeriod

Параметр minSyncPeriod встановлює мінімальний інтервал між спробами ресинхронізації правил iptables з ядром. Якщо він дорівнює 0s, то kube-proxy завжди негайно синхронізує правила при зміні будь-якого Service чи Endpoint. Це працює добре в дуже малих кластерах, але призводить до зайвої роботи, коли велика кількість змін відбувається за короткий період часу. Наприклад, якщо у вас є Service, який підтримується Deployment зі 100 Podʼів, і ви видаляєте Deployment, то з minSyncPeriod: 0s, kube-proxy буде по одному видаляти точки доступу Service з правил iptables, загалом 100 оновлень. З більшим значенням minSyncPeriod, події видалення багатьох Podʼів можуть агрегуватися разом, наприклад, kube-proxy може зробити 5 оновлень, кожне з яких видаляє по 20 точок доступу, що значно економить процесорний час і прискорює синхронізацію всіх змін.

Чим більше значення minSyncPeriod, тим більше роботи можна агрегувати, але недолік полягає в тому, що кожна окрема зміна може очікувати до повного minSyncPeriod, перш ніж буде оброблена, що означає, що правила iptables витрачають більше часу несинхронізованими з поточним станом API-сервера.

Стандартне значення 1s працює добре в більшості кластерів, але в дуже великих кластерах може бути необхідно встановити більше значення. Особливо, якщо метрика sync_proxy_rules_duration_seconds kube-proxy показує середній час значно більше 1 секунди, збільшення minSyncPeriod може зробити оновлення ефективнішими.

Оновлення конфігурації старого параметра minSyncPeriod

У попередніх версіях kube-proxy всі правила для всіх Service оновлювалися кожною синхронізацією, що призводило до проблем продуктивності (затримок оновлення) у великих кластерах, і рекомендоване рішення полягало в налаштуванні більшого значення minSyncPeriod. Починаючи з Kubernetes v1.28, режим iptables kube-proxy використовує більш мінімалістичний підхід, здійснюючи оновлення тільки там, де фактично змінилися Service або EndpointSlices.

Якщо ви раніше перевизначали параметр minSyncPeriod, вам слід спробувати видалити це перевизначення і дозволити kube-proxy використовувати стандартні значення (1s) або принаймні менше значення, ніж ви використовували до оновлення.

Якщо ви не запускаєте kube-proxy з Kubernetes 1.31, перевірте поведінку і повʼязані поради для версії, яку ви фактично використовуєте.

syncPeriod

Параметр syncPeriod контролює кілька операцій синхронізації, які не повʼязані безпосередньо зі змінами в окремих Service та EndpointSlices. Зокрема, він визначає, як швидко kube-proxy помічає, якщо зовнішній компонент втрутився в правила iptables kube-proxy. У великих кластерах kube-proxy також виконує певні операції очищення лише один раз протягом syncPeriod, щоб уникнути непотрібної роботи.

Зазвичай збільшення syncPeriod не має значного впливу на продуктивність, але раніше іноді було корисно встановлювати його дуже великим значенням (наприклад, 1h). Проте це більше не рекомендується і, ймовірно, таке налаштування спричинить більше проблем з функціональністю, ніж покращить продуктивність.

Режим проксі IPVS

Цей режим проксі доступний лише на вузлах Linux.

У режимі ipvs kube-proxy використовує ядро IPVS та API iptables для створення правил для перенаправлення трафіку з IP-адрес Service на IP-адреси точок доступу.

Режим проксі IPVS базується на функції перехоплення netfilter, аналогічній режиму iptables, але використовує хеш-таблицю як основну структуру даних та працює в просторі ядра. Це означає, що kube-proxy в режимі IPVS перенаправляє трафік з меншою затримкою порівняно з режимом iptables, зі значно кращою продуктивністю при синхронізації правил проксі. У порівнянні з режимом проксі iptables, режим IPVS також підтримує вищу пропускну здатність мережевого трафіку.

IPVS надає більше опцій для балансування трафіку до бекендів Pods:

  • rr (Round Robin): Трафік рівномірно розподіляється між серверами.

  • wrr (Weighted Round Robin): Трафік маршрутизується до серверів на основі їх ваг. Сервери з вищими вагами отримують нові зʼєднання і більше запитів, ніж сервери з меншими вагами.

  • lc (Least Connection): Більше трафіку призначається серверам з меншою кількістю активних зʼєднань.

  • wlc (Weighted Least Connection): Більше трафіку маршрутизується до серверів з меншою кількістю зʼєднань відносно їх ваг, тобто кількість зʼєднань, поділена на вагу.

  • lblc (Locality based Least Connection): Трафік для тієї ж самої IP-адреси надсилається на той же сервер, якщо він не перевантажений і доступний; в іншому випадку трафік надсилається на сервери з меншою кількістю зʼєднань з можливістю збереження для майбутнього призначення.

  • lblcr (Locality Based Least Connection with Replication): Трафік для тієї ж самої IP-адреси надсилається на сервер з найменшою кількістю зʼєднань. Якщо всі сервери перевантажені, вибирається один із меншою кількістю зʼєднань і додається до множини цільових серверів. Якщо множина цільових серверів не змінюється протягом визначеного часу, то найбільш навантажений сервер вилучається з множини, щоб уникнути високого рівня реплікації.

  • sh (Source Hashing): Трафік відправляється на сервер за допомогою статично призначеної хеш-таблиці на основі джерела IP-адрес.

  • dh (Destination Hashing): Трафік відправляється на сервер за допомогою статично призначеної хеш-таблиці на основі цільових адрес.

  • sed (Shortest Expected Delay): Трафік пересилається на сервер з найменшим очікуваним затримкою. Очікувана затримка обчислюється як (C + 1) / U, де C — кількість зʼєднань на сервері, а U — фіксована сервісна швидкість (вага) сервера.

  • nq (Never Queue): Трафік відправляється на сервер, що простоює, якщо є такий, замість очікування швидкішого; якщо всі сервери зайняті, алгоритм переходить до поведінки sed.

Механізм віртуальної IP-адреси для Services, використовуючи режим IPVS

Режим проксі nftables

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.31 [beta]

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

У цьому режимі kube-proxy налаштовує правила пересилання пакетів за допомогою API nftables ядра підсистеми netfilter. Для кожної точки доступу встановлюються правила nftables, які стандартно вибирають бекенд Pod випадковим чином.

API nftables є наступником API iptables і призначений для забезпечення кращої продуктивності та масштабованості порівняно з iptables. Режим проксі nftables може обробляти зміни в точках доступу сервісу швидше та ефективніше, ніж режим iptables, і також може ефективніше обробляти пакети в ядрі (хоча це стає помітним лише в кластерах з десятками тисяч сервісів).

В Kubernetes 1.31, режим nftables все ще відносно новий і може бути несумісний з усіма мережевими втулками; ознайомтесь з документацією до вашого мережевого втулка.

Міграція з iptables на nftables

Користувачі, які хочуть перейти зі стандартного режиму iptables на режим nftables, повинні знати, що деякі функції в режимі nftables працюють трохи інакше:

  • Інтерфейси NodePort: У режимі iptables, стандартно, сервіси NodePort доступні на всіх локальних IP-адресах. Це зазвичай не те, чого хочуть користувачі, тому режим nftables стандартно використовує параметр --nodeport-addresses primary, що означає, що сервіси NodePort доступні лише на основних IPv4 та/або IPv6 адресах вузла. Ви можете змінити це, вказавши явне значення для цієї опції: наприклад, --nodeport-addresses 0.0.0.0/0, щоб слухати на всіх (локальних) IP-адресах IPv4.

  • Сервіси NodePort на 127.0.0.1: У режимі iptables, якщо діапазон --nodeport-addresses включає 127.0.0.1 (і не передано опцію --iptables-localhost-nodeports false), тоді сервіси NodePort будуть доступні навіть на "localhost" (127.0.0.1). У режимі nftables (та режимі ipvs) це не працюватиме. Якщо ви не впевнені, чи залежите від цієї функціональності, ви можете перевірити метрику kube-proxy iptables_localhost_nodeports_accepted_packets_total; якщо вона не дорівнює 0, це означає, що якийсь клієнт підключився до сервісу NodePort через 127.0.0.1.

  • Взаємодія NodePort з брандмауерами: Режим iptables kube-proxy намагається бути сумісним із занадто агресивними брандмауерами; для кожного сервісу NodePort він додаватиме правила для прийому вхідного трафіку на цьому порту, на випадок, якщо цей трафік буде заблокований брандмауером. Цей підхід не працює з брандмауерами на основі nftables, тому режим nftables kube-proxy не робить нічого в цьому напрямку; якщо у вас є локальний брандмауер, ви повинні переконатися, що він належним чином налаштований для пропуску трафіку Kubernetes (наприклад, дозволивши вхідний трафік на весь діапазон NodePort).

  • Обхід помилок Conntrack: Ядра Linux версій до 6.1 мають помилку, яка може призвести до закриття довготривалих TCP-зʼєднань до IP-адрес сервісів з помилкою "Connection reset by peer". Режим iptables kube-proxy встановлює обхід для цієї помилки, але пізніше було виявлено, що цей обхід викликає інші проблеми в деяких кластерах. Режим nftables стандартно не встановлює жодного обходу, але ви можете перевірити метрику kube-proxy iptables_ct_state_invalid_dropped_packets_total, щоб зʼясувати, чи залежить ваш кластер від цього обходу, і якщо це так, ви можете запустити kube-proxy з опцією --conntrack-tcp-be-liberal, щоб оминути цю проблему в режимі nftables.

Режим проксі kernelspace

Цей режим проксі доступний лише на вузлах Windows.

kube-proxy налаштовує правила фільтрації пакетів у Windows у віртуальній платформі фільтрації (Virtual Filtering Platform, VFP), яка є розширенням віртуального комутатора Windows (vSwitch). Ці правила обробляють інкапсульовані пакети в межах віртуальних мереж на рівні вузлів і переписують пакети таким чином, щоб IP-адреса призначення (і інформація на рівні 2) була правильною для маршрутизації пакета до вірного призначення. Windows VFP аналогічний інструментам, таким як Linux nftables або iptables. Він розширює Hyper-V Switch, який спочатку був реалізований для підтримки мережевого звʼязку віртуальних машин.

Коли Pod на вузлі надсилає трафік на віртуальну IP-адресу, а kube-proxy вибирає Pod на іншому вузлі як ціль для балансування навантаження, режим проксі kernelspace переписує цей пакет так, щоб він був призначений для цільового бекенд Pod. Служба мережевого хоста Windows (HNS) забезпечує конфігурацію правил переписування пакетів таким чином, щоб зворотній трафік виглядав так, ніби він прийшов від віртуальної IP-адреси, а не конкретного бекенду Pod.

Прямий вивід сервера для режиму kernelspace

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.14 [alpha]

Як альтернативу базовому способу роботи, вузол, на якому розміщено бекенд Pod для Service, може застосовувати пряме переписування пакетів безпосередньо, а не покладати це завдання на вузол, на якому працює клієнтський Pod. Це називається прямим виводом сервера.

Для використання цієї можливості вам необхідно запускати kube-proxy з аргументом командного рядка --enable-dsr і включити функціональних можливостейWinDSR.

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

Сесійна спорідненість

У цих моделях проксі, трафік, що направляється на IP:Port Service, передається до відповідного бекенду без того, щоб клієнти щось знали про Kubernetes, Service або Podʼи.

Якщо ви хочете забезпечити, щоб зʼєднання від певного клієнта завжди передавалися до одного й того ж Podʼа, ви можете вибрати сесійну спорідненість на основі IP-адрес клієнта, встановивши .spec.sessionAffinity в ClientIP для Service (типово None).

Тайм-аут збереження сесії

Ви також можете встановити максимальний час збереження сесії, встановивши .spec.sessionAffinityConfig.clientIP.timeoutSeconds відповідно для Service. (стандартне значення 10800, що відповідає 3 годинам).

Призначення IP-адрес Service

На відміну від IP-адрес Podʼів, які фактично маршрутизуються до фіксованого призначення, IP-адреси Service насправді не відповідають одному окремому хосту. Замість цього, kube-proxy використовує логіку обробки пакетів (наприклад, Linux iptables), щоб визначити віртуальні IP-адреси, які потрібно перенаправляти за потреби.

Коли клієнти підключаються до VIP, їхній трафік автоматично транспортується до відповідної точки доступу. Змінні середовища та DNS для Service насправді заповнюються відносно віртуальної IP-адреси Service (і порту).

Уникнення конфліктів

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

Щоб дозволити вам вибирати IP-адреси для ваших Service, ми повинні забезпечити, що жодні два Service не зможуть конфліктувати. Kubernetes досягає цього, призначаючи кожному Service його власну IP-адресу з діапазону service-cluster-ip-range, який налаштований для API Server.

Відстеження призначення IP-адрес

Для того щоб гарантувати, що кожен Service отримує унікальну IP-адресу, внутрішній розподілювач атомарно оновлює глобальний map призначення в etcd перед створенням кожного Service. Обʼєкт map повинен існувати в реєстрі для того, щоб Service отримували призначення IP-адрес, інакше створення завершиться невдачею з повідомленням про неможливість призначити IP-адресу.

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

Відстеження призначення IP-адрес за допомогою Kubernetes API

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.31 [beta]

Якщо ви включите функціональні можливості MultiCIDRServiceAllocator та API-групу networking.k8s.io/v1alpha1, панель управління замінить наявний розподілювач etcd переглянутою реалізацією, яка використовує обʼєкти IPAddress та ServiceCIDR замість внутрішнього глобального map призначення. Кожен IP-адрес кластера, повʼязаний з Service, посилається на обʼєкт IPAddress.

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

Однією з основних переваг переглянутого розподілювача є видалення обмежень розміру для діапазону IP-адрес, який може бути використаний для IP-адрес кластера Service. З увімкненою MultiCIDRServiceAllocator, для IPv4 відсутні обмеження, а для IPv6 ви можете використовувати маски підмереж, що є /64 або менше (на відміну від /108 зі старої реалізації).

Доступ до призначень IP-адрес через API означає, що ви, як адміністратор кластера, можете дозволяти користувачам переглядати призначені їх Service IP-адреси. Розширення Kubernetes, такі як Gateway API, можуть використовувати IPAddress API для розширення вбудованих мережевих можливостей Kubernetes.

Нижче наведений короткий приклад того, як користувач може запитувати IP-адреси:

kubectl get services
NAME         TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   2001:db8:1:2::1   <none>        443/TCP   3d1h
kubectl get ipaddresses
NAME              PARENTREF
2001:db8:1:2::1   services/default/kubernetes
2001:db8:1:2::a   services/kube-system/kube-dns

Kubernetes також дозволяє користувачам динамічно визначати доступні діапазони IP для Service за допомогою обʼєктів ServiceCIDR. Під час початкового налаштування, обʼєкт ServiceCIDR зі стандартним іменем kubernetes створюється зі значенням аргументу командного рядка --service-cluster-ip-range для kube-apiserver:

kubectl get servicecidrs
NAME         CIDRS         AGE
kubernetes   10.96.0.0/28  17m

Користувачі можуть створювати або видаляти нові обʼєкти ServiceCIDR для управління доступними діапазонами IP для Service:

cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1beta1
kind: ServiceCIDR
metadata:
  name: newservicecidr
spec:
  cidrs:
  - 10.96.0.0/24
EOF
servicecidr.networking.k8s.io/newcidr1 created
kubectl get servicecidrs
NAME             CIDRS         AGE
kubernetes       10.96.0.0/28  17m
newservicecidr   10.96.0.0/24  7m

Діапазони IP-адрес для віртуальних IP-адрес Service

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.26 [stable]

Kubernetes розділяє діапазон ClusterIP на дві групи, в залежності від розміру налаштованого service-cluster-ip-range, використовуючи таку формулу: min(max(16, cidrSize / 16), 256). Ця формула означає ніколи менше 16 або більше 256, з поступовим збільшенням між ними.

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

Політики трафіку

Ви можете встановити поля .spec.internalTrafficPolicy і .spec.externalTrafficPolicy, щоб контролювати, як Kubernetes маршрутизує трафік до справних ("готових") бекендів.

Політика втурішнього трафіку

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.26 [stable]

Ви можете встановити поле .spec.internalTrafficPolicy, щоб контролювати маршрутизацію трафіку від внутрішніх джерел. Допустимі значення: Cluster і Local. Встановіть поле в Cluster, щоб маршрутизувати внутрішній трафік до всіх готових точок доступу і в Local, щоб маршрутизувати тільки до готових точок доступу, що знаходяться на вузлі. Якщо політика трафіку встановлена в Local, а на вузлі відсутні локальні точки доступу, kube-proxy відкидає трафік.

Політика зовнішнього трафіку

Ви можете налаштувати поле .spec.externalTrafficPolicy для контролю напрямку трафіку зовнішніх джерел. Допустимі значення: Cluster і Local. Встановіть поле на значення Cluster, щоб направляти зовнішній трафік до всіх готових точок доступу, і Local, щоб направляти тільки до готових локальних точок доступу на вузлі. Якщо політика трафіку встановлена на Local і відсутні локальні точки доступу, kube-proxy не передає жодного трафіку для відповідного Service.

Якщо вибрано Cluster, всі вузли є потенційними цілями балансування навантаження, поки вузол не видаляється і kube-proxy працює коректно. У цьому режимі: перевірки стану балансувальника навантаження налаштовані на доступність порту та шляху готовності проксі сервісу. Для kube-proxy це оцінюється як: ${NODE_IP}:10256/healthz. kube-proxy повертає HTTP-код 200 або 503. Точка доступу перевірки стану балансувальника навантаження kube-proxy повертає 200 у випадку:

  1. kube-proxy працює коректно, що означає:
    • він може успішно просувати програмування мережі і не має проблем з таймаутом (таймаут визначається як: 2 × iptables.syncPeriod); і
  2. вузол не видаляється (не встановлено мітки видалення для вузла).

Причина того, що kube-proxy повертає 503 і позначає вузол як непридатний, коли він видаляється, полягає в тому, що kube-proxy підтримує очищення зʼєднання для вузлів, що припиняють роботу. З точки зору управління Kubernetes керування навантаженням при видаленні вузла відбувається декілька важливих аспектів.

Під час видалення:

  • kube-proxy почне не проходити свою перевірку готовності і фактично позначає вузол як непридатний для трафіку балансувальника навантаження. Невдача перевірки стану балансувальника навантаження призводить до того, що балансувальники навантаження, які підтримують очищення зʼєднань, дозволяють завершити існуючі зʼєднання та блокують створення нових зʼєднань.

Після видалення:

  • Контролер сервісу в менеджері хмарних контролерів Kubernetes видаляє вузол зі згаданого набору потенційних цілей. Видалення будь-якого екземпляра зі списку бекендів балансувальника навантаження миттєво припиняє всі зʼєднання. Це також причина того, що kube-proxy спочатку не проходить перевірку стану, коли вузол видаляється.

Для вендорів Kubernetes важливо враховувати, що якщо будь-який вендор налаштовує перевірку готовності kube-proxy як перевірку життєздатності, kube-proxy почне постійно перезапускатися при видаленні вузла до його повного видалення. kube-proxy використовує шлях /livez, який, на відміну від /healthz, не враховує стан видалення вузла, але лише прогрес програмування мережі. /livez є рекомендованим шляхом для визначення перевірки життєздатності kube-proxy.

Користувачі, які використовують kube-proxy, можуть перевірити стан готовності/життєздатності, оцінюючи метрики: proxy_livez_total/proxy_healthz_total. Обидві метрики публікують дві серії: одна з міткою 200 і одна з міткою 503.

Для Local Services: kube-proxy повертає 200, якщо

  1. kube-proxy працює коректно/готовий, і
  2. є локальна точка доступу на вузлі, який розглядається.

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

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

Трафік до термінальних точок доступу доступу

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.28 [stable]

Якщо в kube-proxy включений функціоналу ProxyTerminatingEndpoints і політика трафіку встановлена на Local, kube-proxy на даному вузлі використовує більш складний алгоритм для вибору точок доступу доступу Service. З цим включеним функціоналом, kube-proxy перевіряє наявність локальних точок доступу доступу і те, чи всі локальні кінцеві точки позначені як термінальні. Якщо всі локальні кінцеві точки позначені як термінальні, тоді kube-proxy направлятиме трафік на ці термінальні кінцеві точки. В іншому випадку kube-proxy завжди віддає перевагу направленню трафіку на кінцеві точки, які не є термінальними.

Це поведінка направлення для терміналних точок доступу доступу існує для того, щоб NodePort і LoadBalancer сервіси могли відповідно завершувати зʼєднання при використанні externalTrafficPolicy: Local.

Під час виконання постійного (rolling) оновлення, вузли, які підтримують балансувальник навантаження, можуть переходити від N до 0 реплік цього розгортання. У деяких випадках зовнішні балансувальники навантаження можуть надсилати трафік на вузол з 0 репліками між перевірками готовності. Направлення трафіку на термінальні точки доступу забезпечує, що вузли, які зменшують кількість точок доступу, можуть відповідним чином приймати та відводити трафік на ці термінальні точки доступу. До моменту завершення видалення точки доступу, зовнішній балансувальник навантаження має побачити, що перевірка готовності вузла не вдалася і повністю видалить вузол зі списку бекендів.

Розподіл трафіку

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.31 [beta]

Поле spec.trafficDistribution в Kubernetes Service дозволяє виразити уподобання щодо того, як треба маршрутизувати трафік до точок доступу Service. Реалізації, такі як kube-proxy, використовують поле spec.trafficDistribution як рекомендацію. Поведінка, повʼязана з певними уподобаннями, може трохи відрізнятися між різними реалізаціями.

PreferClose з kube-proxy
Для kube-proxy це означає, що пріоритет в надсиланні трафіку надається точкам доступу в тій самій зоні, що й клієнт. Контролер EndpointSlice оновлює EndpointSlice з підказками для комунікації цього уподобання, яке kube-proxy використовує для прийняття рішень щодо маршрутизації. Якщо в зоні клієнта відсутні будь-які доступні точки доступу, трафік буде маршрутизовано на рівні всього кластера для цього клієнта.

У відсутність будь-якого значення для trafficDistribution, стандартна стратегія для kube-proxy полягає в розподілі трафіку до будь-якої точки доступу в кластері.

Порівняння з service.kubernetes.io/topology-mode: Auto

Поле trafficDistribution зі значенням PreferClose і анотація service.kubernetes.io/topology-mode: Auto спрямовані на пріоритет маршрутизації трафіку в межах однієї зони. Однак, є ключові відмінності у їхніх підходах:

  • service.kubernetes.io/topology-mode: Auto: Спробує розподілити трафік пропорціонально між зонами на основі ресурсів CPU, які можна виділити. Цей евристичний метод включає захисні заходи (такі як поведінка відкату для малих кількостей точок доступу) і може призвести до вимкнення функціоналу в певних сценаріях з причин навантаження балансування. Цей підхід жертвує деякою передбачуваністю на користь можливості балансування навантаження.

  • trafficDistribution: PreferClose: Цей підхід спрямований на більш простоту і передбачуваність: "Якщо є точки доступу в зоні, вони отримають весь трафік для цієї зони; якщо точок доступу у зоні немає, трафік буде розподілено на інші зони". Хоча цей підхід може пропонувати більшу передбачуваність, він означає, що вам потрібно керувати можливим перевантаженням.

Якщо встановлено анотацію service.kubernetes.io/topology-mode зі значенням Auto, вона матиме пріоритет перед полем trafficDistribution. (У майбутньому анотація може бути застарілою на користь поля trafficDistribution).

Взаємодія з політиками трафіку

Порівняно з полем trafficDistribution, поля політики трафіку (externalTrafficPolicy і internalTrafficPolicy) призначені для обовʼязкового дотримання локальних вимог до трафіку. Ось як поле trafficDistribution взаємодіє з ними:

  • Пріоритет політик трафіку: Для заданого Service, якщо політика трафіку (externalTrafficPolicy або internalTrafficPolicy) встановлена на Local, вона має пріоритет перед trafficDistribution: PreferClose для відповідного типу трафіку (зовнішнього або внутрішнього відповідно).

  • Вплив trafficDistribution: Для заданого Service, якщо політика трафіку (externalTrafficPolicy або internalTrafficPolicy) встановлена на Cluster (стандартне значення), або якщо поля не встановлені, тоді trafficDistribution: PreferClose керує поведінкою маршрутизації для відповідного типу трафіку (зовнішнього або внутрішнього відповідно). Це означає, що буде здійснена спроба направити трафік на точку доступу, яка знаходиться в тій же зоні, що й клієнт.

Міркування щодо використання управління розподілом трафіку

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

    • Обмеження розподілу топології Pod: Використовуйте обмеження розподілу топології Pod для рівномірнішого розподілу ваших Podʼів по зонам.

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

  • Реалізація залежно від імплементації: Кожна реалізація панелі даних може трохи по-різному обробляти це поле. Якщо ви використовуєте імплементацію, відмінну від kube-proxy, зверніться до документації саме цієї імплементації, щоб зрозуміти, як це поле обробляється.

Що далі

Щоб дізнатися більше про Service, читайте Підключення застосунків до Service.

Також ви можете:

Змінено August 15, 2024 at 4:40 PM PST: upstream sync (6ec9cfeefc)