Мережева модель Kubernetes складається з кількох частин:
Кожен Pod у кластері отримує власну унікальну в межах кластера IP-адресу.
Pod має власний приватний мережевий простір імен, який спільно використовують усі контейнери в цьому Podʼі. Процеси, що працюють у різних контейнерах одного Podʼа, можуть взаємодіяти між собою через localhost.
Мережа Podʼів (також називається мережею кластера) забезпечує взаємодію між Podʼами. Вона гарантує, що (за відсутності навмисної сегментації мережі):
Усі Podʼи можуть взаємодіяти з усіма іншими Podʼами, незалежно від того, чи перебувають вони на одному вузлі, чи на різних. Podʼи можуть взаємодіяти безпосередньо, без використання проксі-серверів чи трансляції адрес (NAT).
У Windows це правило не застосовується до Podʼів із мережею хоста.
Агенти на вузлі (такі як системні демони чи kubelet) можуть взаємодіяти з усіма Podʼами на цьому вузлі.
API Service дозволяє надати стабільну (довговічну) IP-адресу або імʼя хоста для сервісу, реалізованого одним або кількома Podʼами-бекендами, при цьому окремі Podʼи, що складають сервіс, можуть змінюватися з часом.
Kubernetes автоматично керує обʼєктами EndpointSlice, щоб надавати інформацію про Podʼи, які наразі обслуговують Service.
Реалізація проксі сервісів відстежує набір обʼєктів Service та EndpointSlice і програмує площину даних для маршрутизації трафіку сервісу до його бекендів, використовуючи API операційної системи або хмарного провайдера для перехоплення чи переписування пакетів.
API Gateway (або його попередник Ingress) дозволяє зробити Services доступними для клієнтів поза кластером.
Простіший, але менш гнучкий механізм вхідного трафіку кластера доступний через type: LoadBalancer в API Service, якщо ви використовуєте підтримуваного хмарного провайдера.
NetworkPolicy — це вбудований API Kubernetes, який дозволяє контролювати трафік між Podʼами або між Podʼами та зовнішнім світом.
У старіших контейнерних системах не було автоматичного звʼязку між контейнерами на різних хостах, тому часто доводилося явно створювати посилання між контейнерами або зіставляти порти контейнерів із портами хоста, щоб контейнери на інших хостах могли до них звертатися. У Kubernetes це не потрібно: модель Kubernetes передбачає, що Podʼи можна розглядати подібно до віртуальних машин або фізичних хостів з погляду виділення портів, іменування, виявлення сервісів, балансування навантаження, налаштування застосунків та міграції.
Лише кілька частин цієї моделі реалізовані безпосередньо в Kubernetes. Для решти Kubernetes визначає API, але відповідну функціональність надають зовнішні компоненти, деякі з яких є необовʼязковими:
Налаштування мережевого простору імен Podʼа виконує системне програмне забезпечення, яке реалізує Container Runtime Interface.
Мережею Podʼів керує реалізація мережі Podʼів. У Linux більшість середовищ виконання контейнерів використовують Container Networking Interface (CNI), щоб взаємодіяти з реалізацією мережі Podʼів, тому ці реалізації часто називають втулками CNI.
Kubernetes надає стандартну реалізацію проксіювання сервісів, яка називається kube-proxy, але деякі реалізації мережі Podʼів використовують власний проксі сервісів, тісніше інтегрований з рештою реалізації.
NetworkPolicy зазвичай також реалізується реалізацією мережі Podʼів. (Деякі простіші реалізації мережі Podʼів не реалізують NetworkPolicy, або адміністратор може налаштувати мережу Podʼів без підтримки NetworkPolicy. У таких випадках API буде присутній, але не матиме жодного ефекту.)
Існує багато реалізацій Gateway API: деякі специфічні для певних хмарних середовищ, деякі більше орієнтовані на середовища bare metal, а інші є більш універсальними.
Відкрийте доступ до застосунку, що працює у вашому кластері, через єдину зовнішню точку доступу, навіть якщо робоче навантаження розподілене між кількома бекендами.
У Kubernetes Service — це метод надання доступу ззовні до мережевого застосунку, який працює як один чи кілька Podʼів у вашому кластері.
Ключова мета Services у Kubernetes полягає в тому, що вам не потрібно змінювати наявний застосунок, щоб використовувати незнайомий механізм виявлення сервісів. Ви можете запускати код у Podʼах, незалежно від того, чи розроблений він для світу cloud native, чи це старіший застосунок, який ви контейнеризували. Ви використовуєте Service, щоб зробити цей набір Podʼів доступним у мережі, щоб клієнти могли з ним взаємодіяти.
Якщо ви використовуєте Deployment для запуску застосунку, цей Deployment може динамічно створювати та знищувати Podʼи. У будь-який момент ви не знаєте, скільки з цих Podʼів працюють і є справними; ви навіть можете не знати, як називаються ці справні Podʼи. Podʼи Kubernetes створюються та знищуються відповідно до бажаного стану вашого кластера. Podʼи є ефемерними ресурсами (не варто очікувати, що окремий Pod буде надійним і довговічним).
Кожен Pod отримує власну IP-адресу (Kubernetes очікує, що це забезпечать мережеві втулки). Для певного Deployment у вашому кластері набір Podʼів, що працює в один момент часу, може відрізнятися від набору Podʼів, що виконує цей застосунок мить потому.
Це призводить до проблеми: якщо певний набір Podʼів (назвемо їх «бекендами») надає функціональність іншим Podʼам (назвемо їх «фронтендами») всередині вашого кластера, як фронтенди дізнаються та відстежують, до якої IP-адреси підключатися, щоб фронтенд міг використовувати бекенд-частину робочого навантаження?
Тут на допомогу приходять Services.
Services у Kubernetes
API Service, що є частиною Kubernetes, — це абстракція, яка допомагає відкривати доступ до груп Podʼів через мережу. Кожен обʼєкт Service визначає логічний набір точок доступу (зазвичай ці точки доступу є Podʼами) разом із політикою того, як зробити ці Podʼи доступними.
Наприклад, розгляньмо stateless-бекенд для обробки зображень, який працює з 3 репліками. Ці репліки взаємозамінні: фронтендам не важливо, який бекенд вони використовують. Хоча конкретні Podʼи, що утворюють набір бекендів, можуть змінюватися, клієнтам-фронтендам не потрібно про це знати чи самостійно відстежувати набір бекендів.
Абстракція Service робить можливим таке відокремлення.
Набір Podʼів, на які спрямований Service, зазвичай визначається селектором, який ви задаєте. Щоб дізнатися про інші способи визначення точок доступу Service, дивіться Services без селекторів.
Якщо ваше робоче навантаження використовує HTTP, ви можете скористатися Ingress, щоб контролювати, як вебтрафік досягає цього навантаження. Ingress не є типом Service, але він діє як точка входу до вашого кластера. Ingress дозволяє обʼєднати правила маршрутизації в одному ресурсі, щоб відкрити доступ до кількох компонентів вашого робочого навантаження, які працюють у кластері окремо, через одного слухача.
API Gateway для Kubernetes надає додаткові можливості порівняно з Ingress і Service. Ви можете додати Gateway до свого кластера — це сімейство API розширення, реалізованих за допомогою CustomResourceDefinitions, — а потім використовувати їх для налаштування доступу до мережевих сервісів, що працюють у вашому кластері.
Виявлення сервісів у стилі cloud native
Якщо ви можете використовувати API Kubernetes для виявлення сервісів у своєму застосунку, ви можете надсилати запити до API-сервера щодо відповідних EndpointSlices. Kubernetes оновлює EndpointSlices для Service щоразу, коли змінюється набір Podʼів у цьому Service.
Для ненативних застосунків Kubernetes пропонує способи розмістити мережевий порт або балансувальник навантаження між вашим застосунком і бекенд-Podʼами.
У будь-якому разі ваше робоче навантаження може використовувати ці механізми виявлення сервісів, щоб знайти ціль, до якої воно хоче підʼєднатися.
Визначення Service
Service — це обʼєкт (так само, як Pod чи ConfigMap). Ви можете створювати, переглядати або змінювати визначення Service за допомогою API Kubernetes. Зазвичай для цих викликів API ви використовуєте інструмент, такий як kubectl.
Наприклад, припустимо, що у вас є набір Podʼів, кожен з яких слухає TCP-порт 9376 і має мітку app.kubernetes.io/name=MyApp. Ви можете визначити Service, щоб опублікувати цього слухача TCP:
Застосування цього маніфесту створює новий Service з назвою "my-service" зі стандартним типом Service ClusterIP. Service спрямовує трафік на TCP-порт 9376 будь-якого Podʼа з міткою app.kubernetes.io/name: MyApp.
Kubernetes призначає цьому Service IP-адресу (кластерний IP), яка використовується механізмом віртуальних IP-адрес. Докладніше про цей механізм читайте у Віртуальні IP та проксі для Service.
Контролер цього Service постійно шукає Podʼи, що відповідають його селектору, а потім вносить необхідні оновлення до набору EndpointSlices цього Service.
Service може зіставляти будь-який вхідний port із targetPort. Стандартно та для зручності targetPort має те саме значення, що й поле port.
Визначення портів
Визначення портів у Podʼах мають назви, і ви можете посилатися на ці назви в атрибуті targetPort Service. Наприклад, ми можемо привʼязати targetPort Service до порту Podʼа таким чином:
Це працює, навіть якщо в Service є суміш Podʼів, що використовують одну налаштовану назву, а той самий мережевий протокол доступний на різних номерах портів. Це дає багато гнучкості для розгортання та розвитку ваших Services. Наприклад, ви можете змінити номери портів, які відкривають Podʼи, у наступній версії програмного забезпечення вашого бекенду, не порушуючи роботу клієнтів.
Стандартним протоколом для Services є TCP; ви також можете використовувати будь-який інший підтримуваний протокол.
Оскільки багатьом Services потрібно відкривати більше ніж один порт, Kubernetes підтримує кілька визначень портів для одного Service. Кожне визначення порту може мати той самий protocol або інший.
Services без селекторів
Services найчастіше абстрагують доступ до Podʼів Kubernetes завдяки селектору, але коли вони використовуються з відповідним набором обʼєктів EndpointSlices без селектора, Service може абстрагувати інші види бекендів, зокрема ті, що працюють поза кластером.
Наприклад:
Ви хочете мати зовнішній кластер баз даних у промисловому середовищі, але в тестовому середовищі використовуєте власні бази даних.
Ви хочете спрямувати свій Service на Service в іншому просторі імен або в іншому кластері.
Ви мігруєте робоче навантаження до Kubernetes. Під час оцінювання цього підходу ви запускаєте в Kubernetes лише частину своїх бекендів.
У будь-якому з цих сценаріїв ви можете визначити Service без зазначення селектора для вибору Podʼів. Наприклад:
Оскільки цей Service не має селектора, відповідні обʼєкти EndpointSlice не створюються автоматично. Ви можете зіставити Service з мережевою адресою та портом, де він працює, додавши обʼєкт EndpointSlice вручну. Наприклад:
apiVersion:discovery.k8s.io/v1kind:EndpointSlicemetadata:name:my-service-1# за домовленістю використовуйте назву Service# як префікс для назви EndpointSlicelabels:# Ви повинні встановити мітку "kubernetes.io/service-name".# Встановіть її значення відповідно до назви Servicekubernetes.io/service-name:my-serviceaddressType:IPv4ports:- name:http# має збігатися з назвою порту Service, визначеного вищеappProtocol:httpprotocol:TCPport:9376endpoints:- addresses:- "10.4.5.6"- addresses:- "10.1.2.3"
Власні EndpointSlices
Коли ви створюєте обʼєкт EndpointSlice для Service, ви можете використовувати будь-яку назву для EndpointSlice. Кожен EndpointSlice у просторі імен повинен мати унікальну назву. Ви повʼязуєте EndpointSlice із Service, встановлюючи на цьому EndpointSlice міткуkubernetes.io/service-name.
Примітка:
IP-адреси точок доступу не повинні бути: loopback-адресами (127.0.0.0/8 для IPv4, ::1/128 для IPv6) або link-local-адресами (169.254.0.0/16 та 224.0.0.0/24 для IPv4, fe80::/64 для IPv6).
IP-адреси точок доступу не можуть бути кластерними IP-адресами інших Services Kubernetes, оскільки kube-proxy не підтримує віртуальні IP-адреси як призначення.
Для EndpointSlice, який ви створюєте самостійно або у власному коді, також слід вибрати значення для мітки endpointslice.kubernetes.io/managed-by. Якщо ви створюєте власний код контролера для керування EndpointSlices, розгляньте можливість використання значення на кшталт "my-domain.example/name-of-controller". Якщо ви використовуєте сторонній інструмент, використовуйте назву інструмента в нижньому регістрі, замінивши пробіли та інші знаки пунктуації дефісами (-). Якщо люди безпосередньо використовують інструмент, такий як kubectl, для керування EndpointSlices, використовуйте назву, яка описує це ручне керування, наприклад, "staff" або "cluster-admins". Уникайте використання зарезервованого значення "controller", яке позначає EndpointSlices, керовані власною панеллю управління Kubernetes.
Доступ до Service без селектора
Доступ до Service без селектора працює так само, як якби він мав селектор. У прикладі Service без селектора трафік спрямовується до однієї з двох точок доступу, визначених у маніфесті EndpointSlice: TCP-зʼєднання до 10.1.2.3 або 10.4.5.6 на порт 9376.
Примітка:
API-сервер Kubernetes не дозволяє проксіювання до точок доступу, не повʼязаних із Podʼами. Дії на кшталт kubectl port-forward service/<service-name> forwardedPort:servicePort, де Service не має селектора, завершаться збоєм через це обмеження. Це запобігає використанню API-сервера Kubernetes як проксі до точок доступу, до яких викликач може не мати дозволу на доступ.
Service ExternalName — це особливий випадок Service, який не має селекторів і натомість використовує DNS-імена. Докладнішу інформацію дивіться в розділі ExternalName.
EndpointSlices
СТАН ФУНКЦІОНАЛУ:GA since Kubernetes v1.21
EndpointSlices — це обʼєкти, які представляють підмножину (зріз) мережевих точок доступу, що стоять за Service.
Ваш кластер Kubernetes відстежує, скільки точок доступу представляє кожен EndpointSlice. Якщо для Service стільки точок доступу, що досягається поріг, Kubernetes додає ще один порожній EndpointSlice і зберігає там інформацію про нові точки доступу. Стандартно Kubernetes створює новий EndpointSlice, коли всі наявні EndpointSlices містять щонайменше 100 точок доступу. Kubernetes не створює новий EndpointSlice, доки не потрібно додати ще одну точку доступу.
Докладнішу інформацію про цей API дивіться в EndpointSlices.
Endpoints (застаріло)
СТАН ФУНКЦІОНАЛУ:Deprecated since Kubernetes v1.33
API EndpointSlice є розвитком старішого API Endpoints. Застарілий API Endpoints має кілька проблем порівняно з EndpointSlice:
Він не підтримує двостекові кластери.
Він не містить інформації, потрібної для підтримки новіших можливостей, таких як trafficDistribution.
Він обрізає список точок доступу, якщо той надто довгий, щоб уміститися в одному обʼєкті.
Через це рекомендується, щоб усі клієнти використовували API EndpointSlice, а не Endpoints.
Точки доступу понад місткість
Kubernetes обмежує кількість точок доступу, які можуть уміститися в одному обʼєкті Endpoints. Коли в Service понад 1000 точок доступу, Kubernetes обрізає дані в обʼєкті Endpoints. Оскільки Service можна повʼязати з кількома EndpointSlices, обмеження в 1000 точок доступу стосується лише застарілого API Endpoints.
У цьому випадку Kubernetes вибирає не більше 1000 можливих точок доступу бекенда для збереження в обʼєкті Endpoints і встановлює на Endpoints анотаціюendpoints.kubernetes.io/over-capacity: truncated. Панель управління також вилучає цю анотацію, якщо кількість бекенд-Podʼів падає нижче 1000.
Трафік і далі надсилається на бекенди, але будь-який механізм балансування навантаження, який покладається на застарілий API Endpoints, надсилає трафік щонайбільше до 1000 доступних точок доступу.
Те саме обмеження API означає, що ви не можете вручну оновити Endpoints так, щоб він мав понад 1000 точок доступу.
Протокол застосунку
СТАН ФУНКЦІОНАЛУ:GA since Kubernetes v1.20
Поле appProtocol дає змогу вказати протокол застосунку для кожного порту Service. Воно використовується як підказка для реалізацій, щоб вони могли запропонувати розширену поведінку для протоколів, які розуміють. Значення цього поля дзеркально відтворюється у відповідних обʼєктах Endpoints та EndpointSlice.
Це поле відповідає стандартному синтаксису міток Kubernetes. Дійсні значення — одне з:
Для деяких Services вам потрібно відкрити більше одного порту. Kubernetes дозволяє налаштувати кілька визначень портів в обʼєкті Service. Під час використання кількох портів для Service ви повинні надати назви всім портам, щоб вони були однозначними. Наприклад:
Як і назви в Kubernetes загалом, назви портів мають містити лише буквено-цифрові символи в нижньому регістрі та -. Назви портів також мають починатися й закінчуватися буквено-цифровим символом.
Наприклад, назви 123-abc та web є допустимими, а 123_abc та -web — ні.
Тип Service
Для деяких частин вашого застосунку (наприклад, фронтендів) вам може знадобитися відкрити доступ до Service на зовнішній IP-адресі, яка доступна поза вашим кластером.
Типи Service у Kubernetes дозволяють вказати, який саме Service вам потрібен.
Відкриває доступ до Service на внутрішній IP-адресі кластера. Вибір цього значення робить Service доступним лише зсередини кластера. Це стандартне значення, яке використовується, якщо ви явно не вказали type для Service. Ви можете відкрити доступ до Service із загальнодоступного інтернету за допомогою Ingress або Gateway.
Відкриває доступ до Service на IP-адресі кожного вузла на статичному порту (NodePort). Щоб зробити порт вузла доступним, Kubernetes налаштовує кластерну IP-адресу так само, як якби ви запросили Service з type: ClusterIP.
Відкриває зовнішній доступ до Service за допомогою зовнішнього балансувальника навантаження. Kubernetes не надає компонент балансування навантаження безпосередньо; ви повинні надати його самі або інтегрувати свій кластер Kubernetes із хмарним провайдером.
Зіставляє Service із вмістом поля externalName (наприклад, з іменем хоста api.foo.bar.example). Це зіставлення налаштовує DNS-сервер вашого кластера на повернення запису CNAME із цим зовнішнім іменем хоста. Жодне проксіювання не налаштовується.
Поле type в API Service розроблено як вкладену функціональність: кожен рівень доповнює попередній. Однак із цього вкладеного дизайну є виняток. Ви можете визначити Service LoadBalancer, вимкнувши виділення NodePort для балансувальника навантаження.
type: ClusterIP
Цей стандартний тип Service призначає IP-адресу з пулу IP-адрес, який ваш кластер зарезервував для цієї мети.
Кілька інших типів Service базуються на типі ClusterIP.
Якщо ви визначаєте Service, у якому .spec.clusterIP має значення "None", Kubernetes не призначає IP-адресу. Докладнішу інформацію дивіться в розділі headless Services.
Вибір власної IP-адреси
Ви можете вказати власну кластерну IP-адресу в запиті на створення Service. Для цього встановіть поле .spec.clusterIP. Наприклад, це корисно, якщо у вас уже є запис DNS, який ви хочете використовувати повторно, або застарілі системи, налаштовані на певну IP-адресу, які важко переналаштувати.
Вибрана вами IP-адреса має бути дійсною адресою IPv4 або IPv6 із діапазону CIDR service-cluster-ip-range, налаштованого для API-сервера. Якщо ви спробуєте створити Service з недійсним значенням clusterIP, API-сервер поверне код стану HTTP 422, щоб вказати на проблему.
Читайте уникнення конфліктів, щоб дізнатися, як Kubernetes допомагає зменшити ризик і наслідки спроб двох різних Services використовувати ту саму IP-адресу.
type: NodePort
Якщо ви встановлюєте поле type у NodePort, панель управління Kubernetes виділяє порт із діапазону, вказаного прапорцем --service-node-port-range (стандартно: 30000-32767). Кожен вузол проксіює цей порт (той самий номер порту на кожному вузлі) у ваш Service. Ваш Service повідомляє виділений порт у своєму полі .spec.ports[*].nodePort.
Використання NodePort дає вам свободу налаштувати власне рішення для балансування навантаження, конфігурувати середовища, які не повністю підтримуються Kubernetes, або навіть безпосередньо відкрити IP-адреси одного чи кількох вузлів.
Для Service з портом вузла Kubernetes додатково виділяє порт (TCP, UDP або SCTP відповідно до протоколу Service). Кожен вузол кластера налаштовується на прослуховування цього призначеного порту та пересилання трафіку до однієї з готових точок доступу, повʼязаних із цим Service. Ви зможете звернутися до Service type: NodePort ззовні кластера, підʼєднавшись до будь-якого вузла за відповідним протоколом (наприклад, TCP) та відповідним портом (призначеним цьому Service).
Вибір власного порту
Якщо вам потрібен певний номер порту, ви можете вказати значення в полі nodePort. Панель управління або виділить вам цей порт, або повідомить, що транзакція API не вдалася. Це означає, що вам потрібно самостійно подбати про можливі конфлікти портів. Ви також повинні використовувати дійсний номер порту, що входить до діапазону, налаштованого для використання NodePort.
Ось приклад маніфесту для Service з type: NodePort, який вказує значення NodePort (у цьому прикладі 30007):
apiVersion:v1kind:Servicemetadata:name:my-servicespec:type:NodePortselector:app.kubernetes.io/name:MyAppports:- port:80# Стандартно та для зручності `targetPort` встановлено# у те саме значення, що й поле `port`.targetPort:80# Необовʼязкове поле# Стандартно та для зручності панель управління Kubernetes# виділить порт із діапазону (стандартно: 30000-32767)nodePort:30007
Резервування діапазонів NodePort для уникнення конфліктів
Політика призначення портів Services NodePort застосовується як до автоматичного, так і до ручного призначення. Коли користувач хоче створити Service NodePort, який використовує певний порт, цей цільовий порт може конфліктувати з іншим, уже призначеним портом.
Щоб уникнути цієї проблеми, діапазон портів для Services NodePort поділено на дві смуги. Динамічне призначення портів стандартно використовує верхню смугу, а коли її вичерпано, може використовувати нижню. Користувачі можуть виділяти порти з нижньої смуги з меншим ризиком конфлікту портів.
Під час використання стандартного діапазону NodePort 30000-32767 смуги розподіляються так:
Під час використання kube-proxy у режимі iptables Services NodePort стандартно доступні на всіх IP-адресах вузла. Під час використання режиму nftables вони стандартно доступні лише на основній IP-адресі вузла (або основних IP-адресах у разі подвійного стека).
Ви можете змінити набір IP-адрес вузла, на яких доступні Services NodePort, за допомогою прапорця kube-proxy --nodeport-addresses або еквівалентного поля nodePortAddresses у файлі конфігурації kube-proxy. Він приймає розділений комами список IP-блоків (наприклад, 10.0.0.0/8, 192.0.2.0/25) або одне чи кілька з таких ключових слів:
primary — основна адреса IPv4 та/або IPv6 вузла згідно з обʼєктом Node. (Це стандартне значення для режиму nftables.)
all — усі адреси. (Це стандартне значення для режимів iptables та ipvs.)
Наприклад, якщо ви запускаєте kube-proxy з прапорцем --nodeport-addresses=192.168.0.0/24, kube-proxy спробує знайти локальну IP-адресу в цій підмережі на кожному вузлі та обслуговуватиме Services NodePort лише через цю IP-адресу.
Services type: NodePort через localhost
Механізми, які проксі сервісів використовують для реалізації Services NodePort, не завжди підтримують надання Services NodePort на localhost. Для kube-proxy:
Під час використання режиму iptables зі значенням --nodeport-addresses, яке містить 127.0.0.1, Services NodePort будуть доступні на 127.0.0.1. Однак це вимагає ввімкнення sysctl ядра (route_localnet), який у деяких кластерах може мати небезпечні побічні ефекти. NodePort на localhost для IPTables можна вимкнути, передавши kube-proxy --iptables-localhost-nodeports false або встановивши для --nodeport-addresses діапазон, який не містить 127.0.0.1.
Під час використання режиму ipvs або режиму iptables в одностекових кластерах IPv6 Services NodePort недоступні на localhost.
СТАН ФУНКЦІОНАЛУ:Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature
To use this feature, you (or a cluster administrator) will need to enable the KubeProxyNFTablesLocalhostNodePorts feature gate for all relevant components in your cluster.
Під час використання режиму nftables Services NodePort будуть доступні на localhost, коли ввімкнено функціональну можливість KubeProxyNFTablesLocalhostNodePorts, а --nodeport-addresses має значення, яке явно містить localhost. (Значення лише allне ввімкне Services NodePort на localhost.) Це реалізовано перенаправленням зʼєднань NodePort на localhost через проксі в просторі користувача, тому це не так ефективно, як звичайне проксіювання сервісів.
Сторонні мережеві втулки, які мають власні реалізації проксі сервісів, можуть підтримувати NodePort на localhost, а можуть і не підтримувати; зверніться до документації цих втулків.
type: LoadBalancer
У хмарних провайдерів, які підтримують зовнішні балансувальники навантаження, встановлення поля type у LoadBalancer створює балансувальник навантаження для вашого Service. Фактичне створення балансувальника навантаження відбувається асинхронно, а інформація про створений балансувальник публікується в полі .status.loadBalancer Service. Наприклад:
Трафік від зовнішнього балансувальника навантаження спрямовується на бекенд-Podʼи. Хмарний провайдер вирішує, як він балансується.
Щоб реалізувати Service з type: LoadBalancer, Kubernetes зазвичай починає зі змін, еквівалентних вашому запиту на Service з type: NodePort. Потім компонент cloud-controller-manager налаштовує зовнішній балансувальник навантаження на пересилання трафіку на цей призначений порт вузла.
Ви можете налаштувати Service із балансуванням навантаження так, щоб не призначати порт вузла, якщо реалізація хмарного провайдера це підтримує.
Деякі хмарні провайдери дозволяють вказати loadBalancerIP. У таких випадках балансувальник навантаження створюється із вказаною користувачем loadBalancerIP. Якщо поле loadBalancerIP не вказано, балансувальник навантаження налаштовується з ефемерною IP-адресою. Якщо ви вказали loadBalancerIP, але ваш хмарний провайдер не підтримує цю можливість, вказане вами поле loadbalancerIP ігнорується.
Примітка:
Поле .spec.loadBalancerIP для Service визнано застарілим у Kubernetes v1.24.
Це поле було недостатньо визначене, і його значення відрізняється в різних реалізаціях. Воно також не підтримує мережі з подвійним стеком. Це поле може бути вилучено в майбутній версії API.
Якщо ви інтегруєтеся з провайдером, який підтримує вказання IP-адрес балансувальника навантаження для Service через анотацію (специфічну для провайдера), вам слід перейти на цей спосіб.
Якщо ви пишете код для інтеграції балансувальника навантаження з Kubernetes, уникайте використання цього поля. Ви можете інтегруватися з Gateway замість Service або визначити власні анотації (специфічні для провайдера) на Service, які задають еквівалентні дані.
Вплив життєздатності вузла на трафік балансувальника навантаження
Перевірки справності балансувальника навантаження є критично важливими для сучасних застосунків. Вони використовуються для визначення того, на який сервер (віртуальну машину або IP-адресу) балансувальник навантаження має спрямовувати трафік. API Kubernetes не визначають, як мають бути реалізовані перевірки справності для балансувальників навантаження, керованих Kubernetes; поведінку визначають хмарні провайдери (і ті, хто пише код інтеграції). Перевірки справності балансувальника навантаження широко використовуються для підтримки поля externalTrafficPolicy у Services.
Балансувальники навантаження зі змішаними типами протоколів
This is a stable feature in Kubernetes, and has been since the 1.26 release. You can no longer toggle this feature (the associated feature gate has been removed).
Стандартно для Services типу LoadBalancer, коли визначено більше одного порту, усі порти повинні мати той самий протокол, і цей протокол має підтримуватися хмарним провайдером.
Функціональна можливість MixedProtocolLBService (стандартно ввімкнена для kube-apiserver починаючи з v1.24) дозволяє використовувати різні протоколи для Services типу LoadBalancer, коли визначено більше одного порту.
Примітка:
Набір протоколів, які можна використовувати для Services із балансуванням навантаження, визначає ваш хмарний провайдер; він може накладати обмеження понад ті, що застосовує API Kubernetes.
Вимкнення виділення NodePort для балансувальника навантаження
СТАН ФУНКЦІОНАЛУ:GA since Kubernetes v1.24
За бажанням ви можете вимкнути виділення портів вузла для Service з type: LoadBalancer, встановивши поле spec.allocateLoadBalancerNodePorts у false. Це слід використовувати лише для реалізацій балансувальників навантаження, які спрямовують трафік безпосередньо до Podʼів, а не через порти вузла. Стандартно spec.allocateLoadBalancerNodePorts має значення true, і Services типу LoadBalancer продовжуватимуть виділяти порти вузла. Якщо встановити spec.allocateLoadBalancerNodePorts у false для наявного Service з виділеними портами вузла, ці порти вузла не будуть звільнені автоматично. Щоб звільнити ці порти вузла, ви повинні явно вилучити запис nodePorts у кожному порту Service.
Вказання класу реалізації балансувальника навантаження
СТАН ФУНКЦІОНАЛУ:GA since Kubernetes v1.24
Для Service із type, встановленим у LoadBalancer, поле .spec.loadBalancerClass дозволяє використовувати реалізацію балансувальника навантаження, відмінну від стандартної реалізації хмарного провайдера.
Стандартно .spec.loadBalancerClass не встановлено, і Service типу LoadBalancer використовує стандартну реалізацію балансувальника навантаження хмарного провайдера, якщо кластер налаштовано з хмарним провайдером за допомогою прапорця компонента --cloud-provider.
Якщо ви вказуєте .spec.loadBalancerClass, вважається, що за Services стежить реалізація балансувальника навантаження, яка відповідає вказаному класу. Будь-яка стандартна реалізація балансувальника навантаження (наприклад, та, яку надає хмарний провайдер) ігноруватиме Services, у яких встановлено це поле. spec.loadBalancerClass можна встановити лише для Service типу LoadBalancer. Після встановлення його не можна змінити. Значення spec.loadBalancerClass має бути ідентифікатором у стилі мітки з необовʼязковим префіксом, наприклад, "internal-vip" або "example.com/internal-vip". Назви без префікса зарезервовані для кінцевих користувачів.
Режим IP-адреси балансувальника навантаження
Для Service з type: LoadBalancer контролер може встановити .status.loadBalancer.ingress.ipMode. .status.loadBalancer.ingress.ipMode вказує, як поводиться IP-адреса балансувальника навантаження. Його можна вказати лише тоді, коли вказано також поле .status.loadBalancer.ingress.ip.
Є два можливі значення для .status.loadBalancer.ingress.ipMode: "VIP" та "Proxy". Стандартне значення — "VIP", що означає, що трафік доставляється на вузол із призначенням, встановленим на IP-адресу та порт балансувальника навантаження. Є два випадки, коли встановлюється значення "Proxy", залежно від того, як балансувальник навантаження хмарного провайдера доставляє трафік:
Якщо трафік доставляється на вузол, а потім через DNAT до Podʼа, призначенням буде IP-адреса вузла та порт вузла;
Якщо трафік доставляється безпосередньо до Podʼа, призначенням буде IP-адреса та порт Podʼа.
Реалізації Service можуть використовувати цю інформацію для коригування маршрутизації трафіку.
Внутрішній балансувальник навантаження
У змішаному середовищі іноді необхідно маршрутизувати трафік від Services всередині того самого (віртуального) блоку мережевих адрес.
У середовищі DNS із розділеним горизонтом вам знадобляться два Services, щоб маршрутизувати і зовнішній, і внутрішній трафік до ваших точок доступу.
Щоб налаштувати внутрішній балансувальник навантаження, додайте до свого Service одну з наведених нижче анотацій залежно від хмарного провайдера, який ви використовуєте:
Services типу ExternalName зіставляють Service з DNS-іменем, а не зі звичайним селектором, таким як my-service або cassandra. Ви вказуєте такі Services за допомогою параметра spec.externalName.
Наприклад, це визначення Service зіставляє Service my-service у просторі імен prod з my.database.example.com:
Service з type: ExternalName приймає рядок з адресою IPv4, але трактує цей рядок як DNS-імʼя, що складається з цифр, а не як IP-адресу (однак інтернет не дозволяє таких імен у DNS). DNS-сервери не розвʼязують Services із зовнішніми іменами, схожими на адреси IPv4.
Якщо ви хочете зіставити Service безпосередньо з певною IP-адресою, розгляньте можливість використання headless Services.
Під час пошуку хоста my-service.prod.svc.cluster.local DNS Service кластера повертає запис CNAME зі значенням my.database.example.com. Доступ до my-service працює так само, як і для інших Services, але з важливою відмінністю: перенаправлення відбувається на рівні DNS, а не через проксіювання чи пересилання. Якщо пізніше ви вирішите перенести базу даних у кластер, ви зможете запустити її Podʼи, додати відповідні селектори чи точки доступу та змінити type цього Service.
Увага:
Під час використання ExternalName з деякими поширеними протоколами, зокрема HTTP та HTTPS, можуть виникати проблеми. Якщо ви використовуєте ExternalName, імʼя хоста, яке використовують клієнти всередині вашого кластера, відрізняється від імені, на яке посилається ExternalName.
Для протоколів, які використовують імена хостів, ця різниця може призвести до помилок або неочікуваних відповідей. HTTP-запити матимуть заголовок Host:, який вихідний сервер не розпізнає; сервери TLS не зможуть надати сертифікат, що відповідає імені хоста, до якого підʼєднався клієнт.
Headless Services
Іноді вам не потрібні балансування навантаження та одна IP-адреса Service. У цьому випадку ви можете створити так звані headless Services, явно вказавши "None" для кластерної IP-адреси (.spec.clusterIP).
Ви можете використовувати headless Service для взаємодії з іншими механізмами виявлення сервісів, не привʼязуючись до реалізації Kubernetes.
Для headless Services кластерна IP-адреса не виділяється, kube-proxy не обробляє ці Services, а платформа не виконує для них балансування навантаження чи проксіювання.
Headless Service дозволяє клієнту підʼєднуватися безпосередньо до будь-якого Podʼа, якому він віддає перевагу. Services, що є headless, не налаштовують маршрути та пересилання пакетів за допомогою віртуальних IP-адрес і проксі; натомість headless Services повідомляють IP-адреси точок доступу окремих Podʼів через внутрішні записи DNS, які обслуговує DNS-сервіс кластера. Щоб визначити headless Service, ви створюєте Service із .spec.type, встановленим у ClusterIP (що також є стандартним значенням type), і додатково встановлюєте .spec.clusterIP у None.
Рядкове значення None є особливим випадком і не тотожне тому, що поле .spec.clusterIP не встановлено.
Те, як автоматично налаштовується DNS, залежить від того, чи визначено для Service селектори:
З селекторами
Для headless Services, які визначають селектори, контролер точок доступу створює EndpointSlices в API Kubernetes і змінює конфігурацію DNS так, щоб повертати записи A або AAAA (адреси IPv4 або IPv6), які вказують безпосередньо на Podʼи, що стоять за Service.
Без селекторів
Для headless Services, які не визначають селектори, панель управління не створює обʼєкти EndpointSlice. Однак система DNS шукає та налаштовує одне з такого:
DNS-записи A / AAAA для всіх IP-адрес готових точок доступу Service, для всіх типів Service, крім ExternalName.
Для точок доступу IPv4 система DNS створює записи A.
Для точок доступу IPv6 система DNS створює записи AAAA.
Коли ви визначаєте headless Service без селектора, port має збігатися з targetPort.
Виявлення сервісів
Для клієнтів, що працюють всередині вашого кластера, Kubernetes підтримує два основні способи виявлення Service: змінні середовища та DNS.
Змінні середовища
Коли Pod запускається на вузлі, kubelet додає набір змінних середовища для кожного активного Service. Він додає змінні {SVCNAME}_SERVICE_HOST та {SVCNAME}_SERVICE_PORT, де назва Service записується у верхньому регістрі, а дефіси перетворюються на підкреслення.
Наприклад, Service redis-primary, який відкриває TCP-порт 6379 і якому виділено кластерну IP-адресу 10.0.0.11, створює такі змінні середовища:
Коли у вас є Pod, якому потрібен доступ до Service, і ви використовуєте метод змінних середовища для публікації порту та кластерного IP для клієнтських Podʼів, ви повинні створити Service до появи клієнтських Podʼів. Інакше змінні середовища цих клієнтських Podʼів не будуть заповнені.
Якщо ви використовуєте лише DNS для виявлення кластерного IP для Service, вам не потрібно турбуватися про цю проблему порядку.
Kubernetes також підтримує та надає змінні, сумісні з можливістю Docker Engine "legacy container links". Ви можете переглянути makeLinkVariables, щоб побачити, як це реалізовано в Kubernetes.
DNS
Ви можете (і майже завжди повинні) налаштувати DNS-сервіс для свого кластера Kubernetes за допомогою надбудови.
DNS-сервер, обізнаний із кластером, такий як CoreDNS, стежить за появою нових Services в API Kubernetes і створює набір записів DNS для кожного з них. Якщо DNS увімкнено в усьому кластері, всі Podʼи повинні автоматично мати змогу розвʼязувати Services за їхніми DNS-іменами.
Наприклад, якщо у вас є Service з назвою my-service у просторі імен Kubernetes my-ns, панель управління та DNS Service разом створюють запис DNS для my-service.my-ns. Podʼи у просторі імен my-ns повинні мати змогу знайти цей Service, виконавши пошук за іменем my-service (my-service.my-ns також працюватиме).
Podʼи в інших просторах імен повинні вказувати імʼя як my-service.my-ns. Ці імена розвʼязуватимуться в кластерний IP, призначений для Service.
Kubernetes також підтримує записи DNS SRV (Service) для іменованих портів. Якщо Service my-service.my-ns має порт з назвою http із протоколом TCP, ви можете виконати запит DNS SRV для _http._tcp.my-service.my-ns, щоб дізнатися номер порту для http, а також IP-адресу.
DNS-сервер Kubernetes — єдиний спосіб доступу до Services ExternalName. Докладніше про розвʼязання ExternalName читайте в DNS для Services та Podʼів.
Прочитайте Віртуальні IP та проксі для Service, де пояснено механізм, який Kubernetes надає, щоб відкрити доступ до Service на віртуальній IP-адресі.
Політики трафіку
Ви можете встановити поля .spec.internalTrafficPolicy та .spec.externalTrafficPolicy, щоб контролювати, як Kubernetes маршрутизує трафік до справних («готових») бекендів.
Поле .spec.trafficDistribution надає ще один спосіб впливати на маршрутизацію трафіку в межах Service Kubernetes. Якщо політики трафіку зосереджені на суворих семантичних гарантіях, то розподіл трафіку дозволяє виражати уподобання (наприклад, маршрутизацію до топологічно ближчих точок доступу). Це може допомогти оптимізувати продуктивність, вартість або надійність. У Kubernetes 1.37 підтримуються такі значення:
PreferSameZone
Вказує на перевагу маршрутизації трафіку до точок доступу, які перебувають у тій самій зоні, що й клієнт.
PreferSameNode
Вказує на перевагу маршрутизації трафіку до точок доступу, які перебувають на тому самому вузлі, що й клієнт.
PreferClose (застаріло)
Це старіший псевдонім для PreferSameZone, менш зрозумілий щодо семантики.
Якщо поле не встановлено, реалізація застосує свою стандартну стратегію маршрутизації.
Якщо ви хочете, щоб зʼєднання від певного клієнта щоразу передавалися до того самого Podʼа, ви можете налаштувати спорідненість сесії на основі IP-адреси клієнта. Докладніше читайте в розділі спорідненість сесії.
Зовнішні IP-адреси
СТАН ФУНКЦІОНАЛУ:Deprecated since Kubernetes v1.36
Усі користувачі мають розпочати перехід від externalIPs. Натомість розгляньте можливість використання контролера зовнішнього балансувальника навантаження або реалізації Gateway API.
Якщо є зовнішні IP-адреси, які маршрутизуються до одного чи кількох вузлів кластера, до Services Kubernetes можна відкрити доступ на цих externalIPs. Коли мережевий трафік надходить до кластера із зовнішньою IP-адресою (як IP-адресою призначення) та портом, що відповідають цьому Service, правила й маршрути, налаштовані Kubernetes, забезпечують маршрутизацію трафіку до однієї з точок доступу цього Service.
Під час визначення Service ви можете вказати externalIPs для будь-якого типу Service. У наведеному нижче прикладі клієнти можуть отримати доступ до Service з назвою "my-service" через TCP за адресою "198.51.100.32:80" (обчисленою з .spec.externalIPs[] та .spec.ports[].port).
Щоб Ingress працював у вашому кластері, у ньому має працювати контролер Ingress. Вам потрібно вибрати принаймні один контролер Ingress і переконатися, що його налаштовано у вашому кластері. На цій сторінці перелічено поширені контролери Ingress, які ви можете розгорнути.
Примітка:
Проєкт Kubernetes рекомендує використовувати Gateway замість Ingress. API Ingress заморожено.
Це означає, що:
API Ingress є загальнодоступним, і на нього поширюються гарантії стабільності для загальнодоступних API. Проєкт Kubernetes не планує вилучати Ingress із Kubernetes.
API Ingress більше не розробляється, і до нього не вноситимуть змін чи оновлень.
Контролери Ingress
Як проєкт, Kubernetes підтримує та супроводжує контролери Ingress AWS та GCE.
Контролери Ingress сторонніх розробників
Примітка: Цей розділ містить посилання на проєкти сторонніх розробників, які надають функціонал, необхідний для Kubernetes. Автори проєкту Kubernetes не несуть відповідальності за ці проєкти. Проєкти вказано в алфавітному порядку. Щоб додати проєкт до цього списку, ознайомтеся з посібником з контенту перед надсиланням змін. Докладніше.
ngrok-operator — це контролер для ngrok, який підтримує як Ingress, так і Gateway API для додавання безпечного публічного доступу до ваших Services K8s.
Контролер Ingress OCI Native — це контролер Ingress для Oracle Cloud Infrastructure, який дозволяє керувати OCI Load Balancer.
Контролер Ingress Pomerium — це контролер Ingress на основі Pomerium, який пропонує політику доступу з урахуванням контексту.
Skipper — HTTP-маршрутизатор і зворотний проксі для композиції сервісів, зокрема для таких випадків, як Kubernetes Ingress, спроєктований як бібліотека для створення власного проксі.
Tyk Operator розширює Ingress власними ресурсами, щоб додати до Ingress можливості керування API. Tyk Operator працює з Tyk Gateway з відкритим кодом і панеллю управління Tyk Cloud.
Контролер Ingress Wallarm — це контролер Ingress, який надає можливості WAAP (WAF) та захисту API.
Використання кількох контролерів Ingress
Ви можете розгортати будь-яку кількість контролерів Ingress, використовуючи клас Ingress у межах кластера. Зверніть увагу на значення .metadata.name вашого ресурсу класу Ingress. Під час створення Ingress ця назва знадобиться вам, щоб вказати поле ingressClassName в обʼєкті Ingress (див. довідник IngressSpec v1). ingressClassName є заміною застарілого методу анотації.
Якщо ви не вказуєте IngressClass для Ingress, а у вашому кластері рівно один IngressClass позначено як стандартний, Kubernetes застосовує до Ingress стандартний IngressClass кластера. Щоб позначити IngressClass як стандартний, встановіть для нього анотацію ingressclass.kubernetes.io/is-default-class зі строковим значенням "true".
В ідеалі всі контролери Ingress мають відповідати цій специфікації, але різні контролери Ingress працюють дещо по-різному.
Примітка:
Обовʼязково ознайомтеся з документацією вашого контролера Ingress, щоб зрозуміти особливості його вибору.
Gateway API — це сімейство видів API, які забезпечують динамічне надання інфраструктури та розширену маршрутизацію трафіку.
Зробіть мережеві сервіси доступними за допомогою розширюваного, орієнтованого на ролі механізму конфігурації з урахуванням протоколу. Gateway API — це надбудова, що містить види API, які забезпечують динамічне надання інфраструктури та розширену маршрутизацію трафіку.
Принципи дизайну
Наведені нижче принципи визначили дизайн та архітектуру Gateway API:
Орієнтований на ролі: Види Gateway API побудовано за організаційними ролями, відповідальними за керування мережевою взаємодією сервісів Kubernetes:
Провайдер інфраструктури: Керує інфраструктурою, яка дозволяє кільком ізольованим кластерам обслуговувати кількох орендарів, наприклад, хмарний провайдер.
Оператор кластера: Керує кластерами та зазвичай займається політиками, мережевим доступом, дозволами застосунків тощо.
Розробник застосунків: Керує застосунком, що працює в кластері, і зазвичай займається конфігурацією на рівні застосунку та композицією Service.
Переносний: Специфікації Gateway API визначено як власні ресурси, і їх підтримують багато реалізацій.
Виразний: Види Gateway API підтримують функціональність для поширених сценаріїв маршрутизації трафіку, як-от зіставлення за заголовками, розподіл трафіку за вагою та інші, які в Ingress були можливі лише за допомогою власних анотацій.
Розширюваний: Gateway дозволяє повʼязувати власні ресурси на різних рівнях API. Це робить можливим детальне налаштування у відповідних місцях структури API.
Модель ресурсів
Gateway API має чотири стабільні види API:
GatewayClass: Визначає набір шлюзів зі спільною конфігурацією, якими керує контролер, що реалізує цей клас.
Gateway: Визначає екземпляр інфраструктури обробки трафіку, наприклад, хмарний балансувальник навантаження.
HTTPRoute: Визначає специфічні для HTTP правила зіставлення трафіку від слухача (listener) Gateway із поданням мережевих точок доступу бекенду. Ці точки доступу часто подаються як Service.
GRPCRoute: Визначає специфічні для gRPC правила зіставлення трафіку від слухача (listener) Gateway із поданням мережевих точок доступу бекенду. Ці точки доступу часто подаються як Service.
Gateway API організовано у різні види API, повʼязані взаємозалежними відносинами, що відображає рольову природу організацій. Обʼєкт Gateway повʼязаний рівно з одним GatewayClass; GatewayClass описує контролер шлюзу, відповідальний за керування Gateways цього класу. Потім із Gateways повʼязуються один або кілька видів маршрутів, наприклад, HTTPRoute. Gateway може фільтрувати маршрути, які можна прикріпити до його listeners, утворюючи з маршрутами модель двосторонньої довіри.
Наведена нижче схема ілюструє звʼязки між трьома стабільними видами Gateway API:
graph LR;
subgraph cluster["Кластер"]
direction LR
HTTPRoute --> Gateway;
Gateway --> GatewayClass;
end
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
class HTTPRoute,Gateway,GatewayClass k8s;
class cluster cluster;
GatewayClass
Gateways можуть бути реалізовані різними контролерами, часто з різними конфігураціями. Gateway має посилатися на GatewayClass, який містить назву контролера, що реалізує цей клас.
У цьому прикладі контролер, який реалізує Gateway API, налаштовано на керування GatewayClasses із назвою контролера example.com/gateway-controller. Gateways цього класу керуватиме контролер реалізації.
Повне визначення цього виду API дивіться в довіднику GatewayClass.
Gateway
Gateway описує екземпляр інфраструктури обробки трафіку. Він визначає мережеву точку доступу, яку можна використовувати для обробки трафіку, тобто фільтрування, балансування, розділення тощо, для таких бекендів, як Service. Наприклад, Gateway може представляти хмарний балансувальник навантаження або проксі-сервер у кластері, налаштований на приймання HTTP-трафіку.
У цьому прикладі екземпляр інфраструктури обробки трафіку запрограмовано на прослуховування HTTP-трафіку на порту 80. Оскільки поле addresses не вказано, адресу або імʼя хоста для Gateway призначає контролер реалізації. Ця адреса використовується як мережева точка доступу для обробки трафіку мережевих точок доступу бекенду, визначених у маршрутах.
Повне визначення цього виду API дивіться в довіднику Gateway. Вказівки щодо налаштування слухачів HTTPS/TLS дивіться в посібнику Gateway API з TLS.
Примітка:
Стандартно Gateway приймає маршрути лише з того самого простору імен. Для маршрутів з інших просторів імен потрібно налаштувати allowedRoutes.
HTTPRoute
Вид HTTPRoute визначає поведінку маршрутизації HTTP-запитів від слухача Gateway до мережевих точок доступу бекенду. Для бекенду Service реалізація може подавати мережеву точку доступу бекенду як IP-адресу Service або як EndpointSlices, що стоять за цим Service. HTTPRoute подає конфігурацію, яка застосовується до базової реалізації Gateway. Наприклад, визначення нового HTTPRoute може призвести до налаштування додаткових маршрутів трафіку в хмарному балансувальнику навантаження або проксі-сервері в кластері.
У цьому прикладі HTTP-трафік від Gateway example-gateway із заголовком Host: зі значенням www.example.com і шляхом запиту /login буде спрямовано до Service example-svc на порт 8080.
Повне визначення цього виду API дивіться в довіднику HTTPRoute.
GRPCRoute
Вид GRPCRoute визначає поведінку маршрутизації запитів gRPC від слухача Gateway до мережевих точок доступу бекенду. Для бекенду Service реалізація може подавати мережеву точку доступу бекенду як IP-адресу Service або як EndpointSlices, що стоять за цим Service. GRPCRoute подає конфігурацію, яка застосовується до базової реалізації Gateway. Наприклад, визначення нового GRPCRoute може призвести до налаштування додаткових маршрутів трафіку в хмарному балансувальнику навантаження або проксі-сервері в кластері.
Gateways, що підтримують GRPCRoute, повинні підтримувати HTTP/2 без початкового оновлення з HTTP/1, тому трафік gRPC гарантовано проходить належним чином.
У цьому прикладі трафік gRPC від Gateway example-gateway із хостом svc.example.com буде спрямовано до Service example-svc на порт 50051 з того самого простору імен.
GRPCRoute дозволяє зіставляти конкретні сервіси gRPC, як показано в наведеному нижче прикладі:
У цьому випадку GRPCRoute зіставлятиме будь-який трафік для svc.example.com і застосовуватиме свої правила маршрутизації, щоб переспрямувати трафік до правильного бекенду. Оскільки вказано лише одне зіставлення, переспрямовуватимуться тільки запити до методу com.example.User.Login на svc.example.com. RPC будь-якого іншого методу цей маршрут не зіставлятиме.
Повне визначення цього виду API дивіться в довіднику GRPCRoute.
Потік запитів
Ось простий приклад маршрутизації HTTP-трафіку до Service за допомогою Gateway та HTTPRoute:
У цьому прикладі потік запиту для Gateway, реалізованого як зворотний проксі, такий:
Клієнт починає готувати HTTP-запит для URL http://www.example.com
DNS-резолвер клієнта запитує імʼя призначення та дізнається про його відповідність одній або кільком IP-адресам, повʼязаним із Gateway.
Клієнт надсилає запит на IP-адресу Gateway; зворотний проксі отримує HTTP-запит і використовує заголовок Host:, щоб зіставити його з конфігурацією, отриманою з Gateway і прикріпленого HTTPRoute.
За потреби зворотний проксі може виконати зіставлення заголовків запиту та/або шляху на основі правил зіставлення HTTPRoute.
За потреби зворотний проксі може змінити запит, наприклад, додати або вилучити заголовки, на основі правил фільтрації HTTPRoute.
Насамкінець зворотний проксі пересилає запит до одного або кількох бекендів.
Відповідність
Gateway API охоплює широкий набір можливостей і має багато реалізацій. Таке поєднання вимагає чітких визначень відповідності та тестів, щоб API забезпечував узгоджений досвід, де б він не використовувався.
Дивіться документацію щодо відповідності, щоб дізнатися про такі деталі, як канали випусків, рівні підтримки та запуск тестів на відповідність.
Міграція з Ingress
Gateway API є наступником API Ingress. Однак він не містить виду Ingress. Тому потрібне одноразове перетворення наявних ресурсів Ingress на ресурси Gateway API.
Ресурси Gateway API не реалізовані в Kubernetes нативно: специфікації визначено як власні ресурси, що підтримуються широким спектром реалізацій.
Встановіть CRD Gateway API або виконайте інструкції зі встановлення обраної реалізації. Після встановлення реалізації скористайтеся посібником Початок роботи, щоб швидко почати роботу з Gateway API.
Примітка:
Обовʼязково ознайомтеся з документацією обраної вами реалізації, щоб розуміти можливі застереження.
Додаткові відомості про всі види Gateway API дивіться в специфікації API.
4 - Мережеві політики
Якщо ви хочете контролювати потік трафіку на рівні IP-адреси чи порту (рівень 3 або 4 моделі OSI), NetworkPolicies дозволяють визначати правила потоку трафіку всередині вашого кластера, а також між Podʼами та зовнішнім світом. Ваш кластер повинен використовувати мережевий втулок, який підтримує застосування NetworkPolicy.
Якщо ви хочете контролювати потік трафіку на рівні IP-адреси чи порту для протоколів TCP, UDP та SCTP, вам варто розглянути використання NetworkPolicies Kubernetes для окремих застосунків у вашому кластері. NetworkPolicies — це конструкція, орієнтована на застосунки, яка дозволяє визначити, як Pod може взаємодіяти через мережу з різними мережевими «сутностями» (ми вживаємо тут слово «сутність», щоб не перевантажувати поширеніші терміни, як-от «точки доступу» та «Services», які мають у Kubernetes особливі значення). NetworkPolicies застосовуються до зʼєднання, на одному або обох кінцях якого є Pod, і не стосуються інших зʼєднань.
Сутності, з якими може взаємодіяти Pod, визначаються за допомогою комбінації таких трьох ідентифікаторів:
Інші дозволені Podʼи (виняток: Pod не може заблокувати доступ до самого себе)
Дозволені простори імен
IP-блоки (виняток: трафік до вузла і від вузла, де працює Pod, завжди дозволений, незалежно від IP-адреси Podʼа чи вузла)
Під час визначення NetworkPolicy на основі Podʼів або просторів імен ви використовуєте селектор, щоб вказати, який трафік дозволений до Podʼів і від Podʼів, що відповідають цьому селектору.
Натомість під час створення NetworkPolicies на основі IP ми визначаємо політики на основі IP-блоків (діапазонів CIDR).
Передумови
Мережеві політики реалізуються мережевим втулком. Щоб використовувати мережеві політики, вам потрібне мережеве рішення, яке підтримує NetworkPolicy. Створення ресурсу NetworkPolicy без контролера, який його реалізує, не матиме ефекту.
Два види ізоляції Podʼів
Існує два види ізоляції для Podʼа: ізоляція для вихідного трафіку (egress) та ізоляція для вхідного трафіку (ingress). Вони стосуються того, які зʼєднання можуть бути встановлені. «Ізоляція» тут не є абсолютною, а означає «застосовуються певні обмеження». Альтернатива, «неізольований для $direction», означає, що в зазначеному напрямку обмежень немає. Обидва види ізоляції (або її відсутності) оголошуються незалежно, і обидва мають значення для зʼєднання від одного Podʼа до іншого.
Стандартно Pod не є ізольованим для вихідного трафіку: усі вихідні зʼєднання дозволені. Pod є ізольованим для вихідного трафіку, якщо існує будь-яка NetworkPolicy, яка одночасно вибирає цей Pod і має "Egress" у своєму policyTypes; ми кажемо, що така політика застосовується до Podʼа для вихідного трафіку. Коли Pod ізольований для вихідного трафіку, єдині дозволені зʼєднання з Podʼа — це ті, що дозволені списком egress якоїсь NetworkPolicy, яка застосовується до Podʼа для вихідного трафіку. Трафік відповідей для цих дозволених зʼєднань також буде неявно дозволений. Дія цих списків egress обʼєднується адитивно.
Стандартно Pod не є ізольованим для вхідного трафіку: усі вхідні зʼєднання дозволені. Pod є ізольованим для вхідного трафіку, якщо існує будь-яка NetworkPolicy, яка одночасно вибирає цей Pod і має "Ingress" у своєму policyTypes; ми кажемо, що така політика застосовується до Podʼа для вхідного трафіку. Коли Pod ізольований для вхідного трафіку, єдині дозволені зʼєднання до Podʼа — це зʼєднання з вузла Podʼа та ті, що дозволені списком ingress якоїсь NetworkPolicy, яка застосовується до Podʼа для вхідного трафіку. Трафік відповідей для цих дозволених зʼєднань також буде неявно дозволений. Дія цих списків ingress обʼєднується адитивно.
Мережеві політики не конфліктують, вони адитивні. Якщо одна чи кілька політик застосовуються до певного Podʼа в певному напрямку, то дозволені в цьому напрямку зʼєднання цього Podʼа — це обʼєднання того, що дозволяють застосовні політики. Тому порядок обчислення не впливає на результат політики.
Щоб зʼєднання від Podʼа-джерела до Podʼа-призначення було дозволене, його мають дозволяти і політика вихідного трафіку на Podʼі-джерелі, і політика вхідного трафіку на Podʼі-призначенні. Якщо хоча б одна сторона не дозволяє зʼєднання, воно не відбудеться.
Ресурс NetworkPolicy
Повне визначення ресурсу дивіться в довіднику NetworkPolicy.
Надсилання цього маніфесту (POST) до API-сервера вашого кластера не матиме жодного ефекту, якщо обране вами мережеве рішення не підтримує мережеві політики.
spec: Специфікація NetworkPolicy містить усю інформацію, необхідну для визначення конкретної мережевої політики в заданому просторі імен.
podSelector: Кожна NetworkPolicy містить podSelector, який вибирає групу Podʼів, до яких застосовується політика. Політика з прикладу вибирає Podʼи з міткою "role=db". Порожній podSelector вибирає всі Podʼи в просторі імен.
policyTypes: Кожна NetworkPolicy містить список policyTypes, який може включати Ingress, Egress або обидва значення. Поле policyTypes вказує, чи застосовується ця політика до вхідного трафіку до вибраних Podʼів, до вихідного трафіку від вибраних Podʼів чи до обох. Якщо в NetworkPolicy не вказано жодного policyTypes, то стандартно завжди буде встановлено Ingress, а Egress буде встановлено, якщо NetworkPolicy має хоча б одне правило вихідного трафіку.
ingress: Кожна NetworkPolicy може містити список дозволених правил ingress. Кожне правило дозволяє трафік, який відповідає обом секціям: from і ports. Політика з прикладу містить одне правило, яке відповідає трафіку на одному порту від одного з трьох джерел: перше вказано через ipBlock, друге через namespaceSelector, а третє через podSelector.
egress: Кожна NetworkPolicy може містити список дозволених правил egress. Кожне правило дозволяє трафік, який відповідає обом секціям: to і ports. Політика з прикладу містить одне правило, яке відповідає трафіку на одному порту до будь-якого призначення в 10.0.0.0/24.
Отже, NetworkPolicy з прикладу:
ізолює Podʼи role=db у просторі імен default як для вхідного, так і для вихідного трафіку (якщо вони ще не були ізольовані)
(правила Ingress) дозволяє зʼєднання до всіх Podʼів у просторі імен default з міткою role=db на TCP-порт 6379 від:
будь-якого Podʼа в просторі імен default з міткою role=frontend
будь-якого Podʼа в просторі імен з міткою project=myproject
IP-адрес у діапазонах 172.17.0.0–172.17.0.255 та 172.17.2.0–172.17.255.255 (тобто всіх адрес 172.17.0.0/16, крім 172.17.1.0/24)
(правила Egress) дозволяє зʼєднання від будь-якого Podʼа в просторі імен default з міткою role=db до CIDR 10.0.0.0/24 на TCP-порт 5978
Існує чотири види селекторів, які можна вказати в секції from правила ingress або в секції to правила egress:
podSelector: Вибирає певні Podʼи в тому самому просторі імен, що й NetworkPolicy, які мають бути дозволені як джерела вхідного трафіку або призначення вихідного трафіку.
namespaceSelector: Вибирає певні простори імен, усі Podʼи яких мають бути дозволені як джерела вхідного трафіку або призначення вихідного трафіку.
namespaceSelectorтаpodSelector: Один запис to/from, який вказує і namespaceSelector, і podSelector, вибирає певні Podʼи в певних просторах імен. Будьте уважні й використовуйте правильний синтаксис YAML. Наприклад:
Ця політика містить один елемент from, який дозволяє зʼєднання від Podʼів з міткою role=client у просторах імен з міткою user=alice. Але наведена далі політика відрізняється:
Вона містить два елементи в масиві from і дозволяє зʼєднання від Podʼів у локальному просторі імен з міткою role=clientабо від будь-якого Podʼа в будь-якому просторі імен з міткою user=alice.
Якщо є сумніви, скористайтеся kubectl describe, щоб побачити, як Kubernetes інтерпретував політику.
ipBlock: Вибирає певні діапазони IP CIDR, дозволені як джерела вхідного трафіку або призначення вихідного трафіку. Це мають бути IP-адреси поза кластером, оскільки IP-адреси Podʼів є ефемерними та непередбачуваними.
Механізми вхідного та вихідного трафіку кластера часто вимагають переписування IP-адреси джерела або призначення пакетів. У таких випадках не визначено, чи відбувається це до обробки NetworkPolicy, чи після неї, і поведінка може відрізнятися для різних комбінацій мережевого втулка, хмарного провайдера, реалізації Service тощо.
Для вхідного трафіку це означає, що в одних випадках ви можете фільтрувати вхідні пакети за фактичною початковою IP-адресою джерела, а в інших «IP-адреса джерела», за якою працює NetworkPolicy, може бути IP-адресою LoadBalancer, вузла Podʼа тощо.
Для вихідного трафіку це означає, що на зʼєднання від Podʼів до IP-адрес Service, які переписуються на зовнішні для кластера IP-адреси, політики на основі ipBlock можуть поширюватися, а можуть і не поширюватися.
Стандартні політики
Стандартно, якщо в просторі імен немає жодної політики, весь вхідний і вихідний трафік до Podʼів і від Podʼів у цьому просторі імен дозволений. Наведені нижче приклади дозволяють змінити стандартну поведінку в цьому просторі імен.
Стандартна заборона всього вхідного трафіку
Ви можете створити «стандартну» політику ізоляції вхідного трафіку для простору імен, створивши NetworkPolicy, яка вибирає всі Podʼи, але не дозволяє жодного вхідного трафіку до цих Podʼів.
Це гарантує, що навіть Podʼи, не вибрані жодною іншою NetworkPolicy, залишатимуться ізольованими для вхідного трафіку. Ця політика не впливає на ізоляцію вихідного трафіку будь-якого Podʼа.
Дозвіл на весь вхідний трафік
Якщо ви хочете дозволити всі вхідні зʼєднання до всіх Podʼів у просторі імен, ви можете створити політику, яка явно це дозволяє.
За наявності цієї політики жодна додаткова політика чи політики не можуть призвести до відмови у вхідному зʼєднанні до цих Podʼів. Ця політика не впливає на ізоляцію вихідного трафіку будь-якого Podʼа.
Стандартна заборона всього вихідного трафіку
Ви можете створити «стандартну» політику ізоляції вихідного трафіку для простору імен, створивши NetworkPolicy, яка вибирає всі Podʼи, але не дозволяє жодного вихідного трафіку від цих Podʼів.
Це гарантує, що навіть Podʼам, не вибраним жодною іншою NetworkPolicy, не буде дозволено вихідний трафік. Ця політика не змінює поведінку ізоляції вхідного трафіку будь-якого Podʼа.
Увага:
Стандартна політика заборони всього вихідного трафіку також блокує DNS-трафік. Якщо вашим робочим навантаженням потрібне розвʼязання DNS-імен, ви повинні додати окрему NetworkPolicy, яка дозволяє вихідний трафік до DNS-сервісу вашого кластера.
Дозвіл на весь вихідний трафік
Якщо ви хочете дозволити всі зʼєднання від усіх Podʼів у просторі імен, ви можете створити політику, яка явно дозволяє всі вихідні зʼєднання від Podʼів у цьому просторі імен.
За наявності цієї політики жодна додаткова політика чи політики не можуть призвести до відмови у вихідному зʼєднанні від цих Podʼів. Ця політика не впливає на ізоляцію вхідного трафіку будь-якого Podʼа.
Стандартна заборона всього вхідного та всього вихідного трафіку
Ви можете створити «стандартну» політику для простору імен, яка забороняє весь вхідний І вихідний трафік, створивши в цьому просторі імен наведену нижче NetworkPolicy.
Це гарантує, що навіть Podʼам, не вибраним жодною іншою NetworkPolicy, не буде дозволено вхідний або вихідний трафік.
Фільтрація мережевого трафіку
NetworkPolicy визначена для зʼєднань рівня 4 (TCP, UDP та, за потреби, SCTP). Для всіх інших протоколів поведінка може відрізнятися залежно від мережевого втулка.
Примітка:
Ви повинні використовувати втулок CNI, який підтримує NetworkPolicies для протоколу SCTP.
Коли визначено мережеву політику deny all, гарантовано забороняються лише зʼєднання TCP, UDP та SCTP. Для інших протоколів, таких як ARP чи ICMP, поведінка не визначена. Те саме стосується дозвільних правил: коли певний Pod дозволений як джерело вхідного трафіку або призначення вихідного трафіку, не визначено, що відбувається (наприклад) з пакетами ICMP. Такі протоколи, як ICMP, можуть бути дозволені одними мережевими втулками та заборонені іншими.
Націлювання на діапазон портів
СТАН ФУНКЦІОНАЛУ:GA since Kubernetes v1.25
Під час написання NetworkPolicy ви можете націлитися на діапазон портів, а не на один порт.
Це можна зробити за допомогою поля endPort, як показано в наведеному нижче прикладі:
Наведене вище правило дозволяє будь-якому Podʼу з міткою role=db у просторі імен default взаємодіяти з будь-якою IP-адресою в діапазоні 10.0.0.0/24 через TCP за умови, що цільовий порт перебуває в діапазоні від 32000 до 32768.
Під час використання цього поля застосовуються такі обмеження:
Поле endPort має бути рівним полю port або більшим за нього.
endPort можна визначити, лише якщо також визначено port.
Обидва порти мають бути числовими.
Примітка:
Ваш кластер повинен використовувати втулок CNI, який підтримує поле endPort у специфікаціях NetworkPolicy. Якщо ваш мережевий втулок не підтримує поле endPort, а ви вкажете NetworkPolicy із цим полем, політика буде застосована лише для одного поля port.
Націлювання на кілька просторів імен за міткою
У цьому сценарії ваша NetworkPolicy типу Egress націлена на кілька просторів імен за назвами їхніх міток. Щоб це працювало, потрібно додати мітки до цільових просторів імен. Наприклад:
Неможливо безпосередньо вказати назви просторів імен у NetworkPolicy. Ви повинні використовувати namespaceSelector із matchLabels або matchExpressions, щоб вибрати простори імен за їхніми мітками.
Націлювання на простір імен за його назвою
Панель управління Kubernetes встановлює незмінну мітку kubernetes.io/metadata.name на всі простори імен, значенням мітки є назва простору імен.
Хоча NetworkPolicy не може націлитися на простір імен за його назвою через якесь поле обʼєкта, ви можете використати стандартизовану мітку, щоб націлитися на конкретний простір імен.
Життєвий цикл Podʼа
Примітка:
Наведене нижче стосується кластерів із сумісним мережевим втулком та сумісною реалізацією NetworkPolicy.
Коли створюється новий обʼєкт NetworkPolicy, мережевому втулку може знадобитися певний час, щоб обробити цей новий обʼєкт. Якщо Pod, на який впливає NetworkPolicy, створено до того, як мережевий втулок завершив обробку NetworkPolicy, цей Pod може бути запущений незахищеним, а правила ізоляції будуть застосовані, коли обробку NetworkPolicy буде завершено.
Щойно NetworkPolicy оброблено мережевим втулком,
Усі новостворені Podʼи, на які впливає певна NetworkPolicy, будуть ізольовані до їхнього запуску. Реалізації NetworkPolicy повинні гарантувати, що фільтрація діє протягом усього життєвого циклу Podʼа, починаючи з першої миті запуску будь-якого контейнера в цьому Podʼі. Оскільки NetworkPolicies застосовуються на рівні Podʼа, вони однаково застосовуються до init-контейнерів, sidecar-контейнерів і звичайних контейнерів.
Дозвільні правила будуть зрештою застосовані після правил ізоляції (або можуть бути застосовані одночасно з ними). У найгіршому випадку новостворений Pod може взагалі не мати мережевого звʼязку під час першого запуску, якщо правила ізоляції вже застосовані, а дозвільні правила ще ні.
Кожна створена NetworkPolicy рано чи пізно буде оброблена мережевим втулком, але через API Kubernetes неможливо дізнатися, коли саме це станеться.
Тому Podʼи мають бути стійкими до запуску з іншим мережевим звʼязком, ніж очікувалося. Якщо вам потрібно переконатися, що Pod може досягти певних призначень до запуску, ви можете використати init-контейнер, щоб дочекатися доступності цих призначень, перш ніж kubelet запустить контейнери застосунків.
Кожна NetworkPolicy рано чи пізно буде застосована до всіх вибраних Podʼів. Оскільки мережевий втулок може реалізовувати NetworkPolicy розподілено, Podʼи можуть бачити дещо неузгоджене подання мережевих політик під час першого створення Podʼа або коли змінюються Podʼи чи політики. Наприклад, новостворений Pod, який має мати доступ і до Podʼа A на вузлі 1, і до Podʼа B на вузлі 2, може виявити, що Pod A доступний йому одразу, а Pod B — лише через кілька секунд.
NetworkPolicy та Podʼи з hostNetwork
Поведінка NetworkPolicy для Podʼів із hostNetwork не визначена, але вона має обмежуватися двома можливостями:
Мережевий втулок може відрізняти трафік Podʼів із hostNetwork від усього іншого трафіку (зокрема, відрізняти трафік різних Podʼів із hostNetwork на тому самому вузлі) і застосовує NetworkPolicy до Podʼів із hostNetwork так само, як і до Podʼів у мережі Podʼів.
Мережевий втулок не може належним чином відрізнити трафік Podʼів із hostNetwork, тому він ігнорує такі Podʼи під час зіставлення podSelector та namespaceSelector. Трафік до Podʼів і від Podʼів із hostNetwork обробляється так само, як і весь інший трафік до IP-адреси вузла та від неї. (Це найпоширеніша реалізація.)
Це стосується випадків, коли
Pod із hostNetwork вибирається за допомогою spec.podSelector.
...spec:podSelector:matchLabels:role:client...
Pod із hostNetwork вибирається за допомогою podSelector чи namespaceSelector у правилі ingress чи egress.
Водночас, оскільки Podʼи з hostNetwork мають ті самі IP-адреси, що й вузли, на яких вони розміщені, їхні зʼєднання вважатимуться зʼєднаннями вузла. Наприклад, ви можете дозволити трафік від Podʼа з hostNetwork за допомогою правила ipBlock.
Що не можна зробити за допомогою мережевих політик (принаймні поки що)
У Kubernetes 1.37 наведена нижче функціональність відсутня в API NetworkPolicy, але ви можете реалізувати обхідні рішення за допомогою компонентів операційної системи (таких як SELinux, OpenVSwitch, IPTables тощо), технологій рівня 7 (контролери Ingress, реалізації Service Mesh) або контролерів допуску. Якщо ви лише починаєте знайомитися з мережевою безпекою в Kubernetes, варто зазначити, що наведені нижче сценарії користувачів поки що не можна реалізувати за допомогою API NetworkPolicy.
Примусове проходження внутрішньокластерного трафіку через спільний шлюз (для цього, ймовірно, найкраще підійде service mesh або інший проксі).
Будь-що, повʼязане з TLS (для цього використовуйте service mesh або контролер Ingress).
Політики для окремих вузлів (для цього можна використовувати нотацію CIDR, але не можна націлитися на вузли саме за їхніми ідентифікаторами в Kubernetes).
Націлювання на Services за назвою (проте ви можете націлюватися на Podʼи чи простори імен за їхніми мітками, що часто є прийнятним обхідним рішенням).
Створення запитів на політики («Policy requests»), які виконує третя сторона, або керування ними.
Стандартні політики, які застосовуються до всіх просторів імен чи Podʼів (деякі сторонні дистрибутиви Kubernetes і проєкти можуть це робити).
Розширені запити до політик та інструменти перевірки досяжності.
Можливість логування подій мережевої безпеки (наприклад, заблокованих чи прийнятих зʼєднань).
Можливість явно забороняти політиками (наразі модель NetworkPolicies — стандартна заборона з можливістю додавати лише дозвільні правила).
Можливість заборонити loopback-трафік або вхідний трафік від хоста (Podʼи наразі не можуть блокувати доступ через localhost, а також не можуть блокувати доступ від вузла, на якому вони розміщені).
Вплив NetworkPolicy на наявні зʼєднання
Коли змінюється набір NetworkPolicies, що застосовуються до наявного зʼєднання, — через зміну самих NetworkPolicies або через зміну відповідних міток просторів імен чи Podʼів, вибраних політикою (і субʼєкта, і його співрозмовників (peers)), посеред наявного зʼєднання, — те, чи вплине ця зміна на це наявне зʼєднання, визначається реалізацією. Приклад: створено політику, яка призводить до заборони раніше дозволеного зʼєднання; реалізація базового мережевого втулка відповідає за визначення того, чи закриє ця нова політика наявні зʼєднання. Рекомендується не змінювати політики, Podʼи чи простори імен у спосіб, який може вплинути на наявні зʼєднання.
Дивіться інші рецепти для поширених сценаріїв, які підтримує ресурс NetworkPolicy.
5 - DNS для Services та Podʼів
Ваше робоче навантаження може виявляти Services у вашому кластері за допомогою DNS; на цій сторінці пояснено, як це працює.
Kubernetes створює DNS-записи для Services та Podʼів. Ви можете звертатися до Services за стабільними DNS-іменами замість IP-адрес.
Kubernetes публікує інформацію про Podʼи та Services, яка використовується для програмування DNS. kubelet налаштовує DNS Podʼів так, щоб запущені контейнери могли знаходити Services за іменем, а не за IP.
Services, визначеним у кластері, призначаються DNS-імена. Стандартно список пошуку DNS клієнтського Podʼа містить власний простір імен Podʼа та стандартний домен кластера.
Простори імен Services
DNS-запит може повертати різні результати залежно від простору імен Podʼа, який його робить. DNS-запити, які не вказують простір імен, обмежуються простором імен Podʼа. Щоб отримати доступ до Services в інших просторах імен, вказуйте простір імен у DNS-запиті.
Наприклад, розгляньмо Pod у просторі імен test. Service data міститься в просторі імен prod.
Запит data не повертає результатів, оскільки використовує простір імен Podʼа test.
Запит data.prod повертає очікуваний результат, оскільки вказує простір імен.
DNS-запити можуть бути розширені за допомогою /etc/resolv.conf Podʼа. kubelet налаштовує цей файл для кожного Podʼа. Наприклад, запит лише data може бути розширено до data.test.svc.cluster.local. Для розширення запитів використовуються значення параметра search. Щоб дізнатися більше про DNS-запити, див. сторінку довідки resolv.conf.
Отже, Pod у просторі імен test може успішно розвʼязувати як data.prod, так і data.prod.svc.cluster.local.
DNS-записи
Для яких обʼєктів створюються DNS-записи?
Services
Podʼи
У розділах нижче докладно описано підтримувані типи DNS-записів та їхню структуру. Будь-яка інша структура, імена чи запити, які випадково працюють, вважаються деталями реалізації й можуть змінитися без попередження. Актуальнішу специфікацію див. у Kubernetes DNS-Based Service Discovery.
Services
Записи A/AAAA
«Звичайні» (не headless) Services отримують DNS-записи A та/або AAAA залежно від сімейства або сімейств IP цього Service, з іменем у вигляді my-svc.my-namespace.svc.cluster-domain.example. Це імʼя розвʼязується в кластерний IP Service.
Headless Services
(без кластерного IP) теж отримують DNS-записи A та/або AAAA, з іменем у вигляді my-svc.my-namespace.svc.cluster-domain.example. На відміну від звичайних Services, це імʼя розвʼязується в набір IP-адрес усіх Podʼів, вибраних Service. Очікується, що клієнти використовуватимуть увесь набір або стандартний вибір round-robin із нього.
Записи SRV
Записи SRV створюються для іменованих портів, які є частиною звичайних або headless Services.
Для кожного іменованого порту SRV-запис має вигляд _port-name._port-protocol.my-svc.my-namespace.svc.cluster-domain.example.
Для звичайного Service він розвʼязується в номер порту та доменне імʼя: my-svc.my-namespace.svc.cluster-domain.example.
Для headless Service він розвʼязується в кілька відповідей, по одній для кожного Podʼа, що обслуговує Service, і містить номер порту та доменне імʼя Podʼа у вигляді hostname.my-svc.my-namespace.svc.cluster-domain.example.
Podʼи
Записи A/AAAA
Версії Kube-DNS до впровадження специфікації DNS мали таке розвʼязання DNS:
Наприклад, якщо Pod у просторі імен cafe має IP-адресу 172.17.0.3, є точкою доступу Service з назвою barista, а доменне імʼя вашого кластера — cluster.local, то Pod матиме такий запис DNS A в межах Service.
172-17-0-3.barista.cafe.svc.cluster.local
Поля hostname та subdomain Podʼа
Наразі під час створення Podʼа його імʼя хоста (як його видно зсередини Podʼа) — це значення metadata.name Podʼа.
У специфікації Podʼа є необовʼязкове поле hostname, яке можна використовувати, щоб вказати інше імʼя хоста. Якщо його вказано, воно має пріоритет над назвою Podʼа й стає іменем хоста Podʼа (знову ж таки, як його видно зсередини Podʼа). Наприклад, Pod зі spec.hostname, встановленим у "my-host", матиме імʼя хоста "my-host".
У специфікації Podʼа також є необовʼязкове поле subdomain, яким можна вказати, що Pod є частиною підгрупи простору імен. Наприклад, Pod зі spec.hostname, встановленим у "foo", і spec.subdomain, встановленим у "bar", у просторі імен "my-namespace" матиме імʼя хоста "foo" та повне доменне імʼя (FQDN) "foo.bar.my-namespace.svc.cluster.local" (знову ж таки, як його видно зсередини Podʼа).
Якщо в тому самому просторі імен, що й Pod, існує headless Service із такою самою назвою, як піддомен, DNS-сервер кластера також повертає записи A та/або AAAA для повного імені хоста Podʼа.
Приклад:
apiVersion:v1kind:Servicemetadata:name:busybox-subdomainspec:selector:name:busyboxclusterIP:Noneports:- name:foo# name не є обовʼязковим для Services з одним портомport:1234---apiVersion:v1kind:Podmetadata:name:busybox1labels:name:busyboxspec:hostname:busybox-1subdomain:busybox-subdomaincontainers:- image:busybox:1.28command:- sleep- "3600"name:busybox---apiVersion:v1kind:Podmetadata:name:busybox2labels:name:busyboxspec:hostname:busybox-2subdomain:busybox-subdomaincontainers:- image:busybox:1.28command:- sleep- "3600"name:busybox
Для наведеного вище Service "busybox-subdomain" і Podʼів, які встановлюють spec.subdomain у "busybox-subdomain", перший Pod бачитиме своє FQDN як "busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example". DNS обслуговує за цим іменем записи A та/або AAAA, що вказують на IP-адресу Podʼа. Обидва Podʼи, "busybox1" та "busybox2", матимуть власні адресні записи.
EndpointSlice може вказувати DNS-імʼя хоста для будь-яких адрес точок доступу разом з їхнім IP.
Примітка:
Записи A та AAAA не створюються для назв Podʼів, оскільки для Podʼа відсутній hostname. Pod без hostname, але з subdomain створить запис A або AAAA лише для headless Service (busybox-subdomain.my-namespace.svc.cluster-domain.example), що вказує на IP-адреси Podʼів. Крім того, Pod має бути готовим, щоб мати запис, якщо для Service не встановлено publishNotReadyAddresses=True.
Поле setHostnameAsFQDN Podʼа
СТАН ФУНКЦІОНАЛУ:GA since Kubernetes v1.22
Коли Pod налаштовано так, що він має повне доменне імʼя (FQDN), його імʼя хоста — це коротке імʼя хоста. Наприклад, якщо у вас є Pod із повним доменним імʼям busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example, то стандартно команда hostname в цьому Podʼі повертає busybox-1, а команда hostname --fqdn повертає FQDN.
Коли ви встановлюєте setHostnameAsFQDN: true у специфікації Podʼа, kubelet записує FQDN Podʼа в імʼя хоста для простору імен цього Podʼа. У цьому випадку як hostname, так і hostname --fqdn повертають FQDN Podʼа.
Примітка:
У Linux поле hostname ядра (поле nodename структури struct utsname) обмежено 64 символами.
Якщо Pod вмикає цю можливість, а його FQDN довше за 64 символи, він не запуститься. Pod залишиться у статусі Pending (ContainerCreating, як показує kubectl), генеруючи події помилок, такі як Failed to construct FQDN from Pod hostname and cluster domain, FQDN long-FQDN is too long (64 characters is the max, 70 characters requested). Один зі способів покращити досвід користувача в цьому сценарії — створити контролер вебхука допуску, щоб контролювати розмір FQDN під час створення користувачами обʼєктів верхнього рівня, наприклад Deployment.
Політика DNS Podʼа
Політику DNS можна встановлювати для кожного Podʼа окремо. Наразі Kubernetes підтримує такі політики DNS для Podʼів. Ці політики вказуються в полі dnsPolicy специфікації Podʼа.
"Default": Pod успадковує конфігурацію розвʼязання імен від вузла, на якому він працює. Докладніше дивіться в повʼязаному обговоренні.
"ClusterFirst": Будь-який DNS-запит, який не відповідає налаштованому суфіксу домену кластера, наприклад "www.kubernetes.io", DNS-сервер пересилає до вищестоящого сервера імен. Адміністратори кластера можуть налаштувати додаткові stub-домени та вищестоящі DNS-сервери. Як у цих випадках обробляються DNS-запити, дивіться в повʼязаному обговоренні.
"ClusterFirstWithHostNet": Для Podʼів, що працюють із hostNetwork, слід явно встановити політику DNS "ClusterFirstWithHostNet". Інакше Podʼи, що працюють із hostNetwork і "ClusterFirst", повернуться до поведінки політики "Default".
Примітка:
Це не підтримується в Windows. Деталі дивіться нижче.
"None": Дозволяє Podʼу ігнорувати налаштування DNS із середовища Kubernetes. Усі налаштування DNS мають надаватися за допомогою поля dnsConfig у специфікації Podʼа. Див. підрозділ Конфігурація DNS Podʼа нижче.
Примітка:
"Default" — це не стандартна політика DNS. Якщо dnsPolicy не вказано явно, використовується "ClusterFirst".
У прикладі нижче показано Pod із політикою DNS "ClusterFirstWithHostNet", оскільки hostNetwork встановлено в true.
Конфігурація DNS Podʼа дає користувачам більше контролю над налаштуваннями DNS Podʼа.
Поле dnsConfig є необовʼязковим і може працювати з будь-якими налаштуваннями dnsPolicy. Однак коли dnsPolicy Podʼа встановлено в "None", поле dnsConfig потрібно вказати обовʼязково.
Нижче наведено властивості, які користувач може вказати в полі dnsConfig:
nameservers: список IP-адрес, які використовуватимуться як DNS-сервери для Podʼа. Можна вказати не більше 3 IP-адрес. Коли dnsPolicy Podʼа встановлено в "None", список повинен містити принаймні одну IP-адресу, інакше ця властивість є необовʼязковою. Указані сервери буде обʼєднано з базовими серверами імен, згенерованими із зазначеної політики DNS, а дубльовані адреси вилучено.
searches: список доменів пошуку DNS для пошуку імен хостів у Podʼі. Ця властивість є необовʼязковою. Якщо її вказано, цей список буде обʼєднано з базовими доменами пошуку, згенерованими з вибраної політики DNS. Дубльовані доменні імена вилучаються. Kubernetes дозволяє до 32 доменів пошуку.
options: необовʼязковий список обʼєктів, де кожний обʼєкт може мати властивість name (обовʼязкова) і властивість value (необовʼязкова). Вміст цієї властивості буде обʼєднано з параметрами, згенерованими із зазначеної політики DNS. Дубльовані записи вилучаються.
apiVersion:v1kind:Podmetadata:namespace:defaultname:dns-examplespec:containers:- name:testimage:nginxdnsPolicy:"None"dnsConfig:nameservers:- 192.0.2.1# this is an examplesearches:- ns1.svc.cluster-domain.example- my.dns.search.suffixoptions:- name:ndotsvalue:"2"- name:edns0
Коли наведений вище Pod створено, контейнер test отримує такий вміст у своєму файлі /etc/resolv.conf:
Kubernetes сам не обмежує конфігурацію DNS, доки довжина списку доменів пошуку не перевищить 32 або загальна довжина всіх доменів пошуку не перевищить 2048. Це обмеження стосується файлу конфігурації резолвера вузла, конфігурації DNS Podʼа та обʼєднаної конфігурації DNS відповідно.
Примітка:
Деякі середовища виконання контейнерів раніших версій можуть мати власні обмеження щодо кількості доменів пошуку DNS. Залежно від середовища виконання контейнерів,
Podʼи з великою кількістю доменів пошуку DNS можуть залишатися в стані очікування.
Відомо, що цю проблему мають containerd v1.5.5 або раніші та CRI-O v1.21 або раніші.
Розвʼязання DNS на вузлах Windows
ClusterFirstWithHostNet не підтримується для Podʼів, що працюють на вузлах Windows. Windows вважає всі імена з крапкою . повними доменними іменами (FQDN) і пропускає розвʼязання FQDN.
У Windows можна використовувати кілька резолверів DNS. Оскільки їхня поведінка дещо відрізняється, для розвʼязання імен рекомендовано використовувати командлет PowerShell Resolve-DNSName.
У Linux є список суфіксів DNS, який використовується після невдалого розвʼязання імені як повного. У Windows можна мати лише 1 суфікс DNS — суфікс, повʼязаний із простором імен цього Podʼа (наприклад, mydns.svc.cluster.local). Windows може розвʼязувати FQDN, Services або мережеві імена, які можна розвʼязати за допомогою цього єдиного суфікса. Наприклад, Pod, запущений у просторі імен default, матиме суфікс DNS default.svc.cluster.local. Усередині Podʼа Windows можна розвʼязувати і kubernetes.default.svc.cluster.local, і kubernetes, але не частково кваліфіковані імена (kubernetes.default або kubernetes.default.svc).
Kubernetes дозволяє налаштувати мережу з одним стеком IPv4, мережу з одним стеком IPv6 або мережу з подвійним стеком, де активні обидва мережеві сімейства. На цій сторінці пояснено, як це зробити.
СТАН ФУНКЦІОНАЛУ:GA since Kubernetes v1.23
Двостекова мережа IPv4/IPv6 дозволяє виділяти адреси IPv4 та IPv6 для Podʼів та Services.
Двостекова мережа IPv4/IPv6 стандартно увімкнена у вашому кластері Kubernetes починаючи з версії 1.21, що дозволяє одночасно призначати адреси IPv4 та IPv6.
Підтримувані можливості
Двостекова мережа IPv4/IPv6 у вашому кластері Kubernetes надає такі можливості:
Двостекова мережа Podʼів (одна адреса IPv4 та одна адреса IPv6 на Pod)
Services з підтримкою IPv4 та IPv6
Маршрутизація вихідного трафіку Podʼів за межі кластера (наприклад, в Інтернет) через інтерфейси IPv4 та IPv6
Передумови
Щоб використовувати двостекові кластери Kubernetes IPv4/IPv6, потрібно виконати такі передумови:
Kubernetes 1.20 або новіше
Інформацію про використання двостекових Services із попередніми версіями Kubernetes дивіться в документації відповідної версії Kubernetes.
Підтримка двостекової мережі провайдером (хмарний чи інший провайдер має надати вузлам Kubernetes маршрутизовані мережеві інтерфейси IPv4/IPv6)
--node-cidr-mask-size-ipv4|--node-cidr-mask-size-ipv6 стандартно /24 для IPv4 та /64 для IPv6
kube-proxy:
--cluster-cidr=<CIDR IPv4>,<CIDR IPv6>
kubelet:
--node-ip=<IP IPv4>,<IP IPv6>
Цей параметр є обовʼязковим для двостекових вузлів bare metal (вузлів, які не визначають хмарного провайдера прапорцем --cloud-provider). Якщо ви використовуєте хмарного провайдера й вирішили перевизначити IP-адреси вузлів, вибрані ним, встановіть параметр --node-ip.
(Застарілі вбудовані хмарні провайдери не підтримують двостековий --node-ip.)
Примітка:
Приклад CIDR IPv4: 10.244.0.0/16 (хоча ви вказуватимете власний діапазон адрес)
Приклад CIDR IPv6: fdXY:IJKL:MNOP:15::/64 (це показує формат, але не є дійсною адресою — дивіться RFC 4193)
Services
Ви можете створювати Services, які можуть використовувати IPv4, IPv6 або обидва.
Сімейство адрес Service стандартно відповідає сімейству адрес першого діапазону кластерних IP Services (налаштованого через прапорець --service-cluster-ip-range для kube-apiserver).
Під час визначення Service ви можете за бажанням налаштувати його як двостековий. Щоб вказати потрібну поведінку, встановіть у полі .spec.ipFamilyPolicy одне з таких значень:
SingleStack: одностековий Service. Панель управління виділяє кластерний IP для Service, використовуючи перший налаштований діапазон кластерних IP Services.
PreferDualStack: виділяє кластерні IP IPv4 та IPv6 для Service, коли подвійний стек увімкнено. Якщо подвійний стек не увімкнено або він не підтримується, застосовується одностекова поведінка.
RequireDualStack: виділяє .spec.clusterIPs Service з діапазонів адрес IPv4 та IPv6, коли подвійний стек увімкнено. Якщо подвійний стек не увімкнено або він не підтримується, створення обʼєкта API Service завершиться невдачею.
Вибирає .spec.clusterIP зі списку .spec.clusterIPs на основі сімейства адрес першого елемента у масиві .spec.ipFamilies.
Якщо ви хочете визначити, яке сімейство IP використовувати для одного стека, або задати порядок сімейств IP для подвійного стека, ви можете вибрати сімейства адрес, встановивши необовʼязкове поле .spec.ipFamilies у Service.
Примітка:
Поле .spec.ipFamilies умовно змінюване: ви можете додавати або видаляти вторинне
сімейство IP-адрес, але не можете змінювати основне сімейство IP-адрес наявного Service.
Ви можете встановити .spec.ipFamilies в будь-яке з таких значень масиву:
["IPv4"]
["IPv6"]
["IPv4","IPv6"] (подвійний стек)
["IPv6","IPv4"] (подвійний стек)
Перше вказане вами сімейство використовується для застарілого поля .spec.clusterIP.
Сценарії конфігурації двостекового Service
Ці приклади демонструють поведінку різних сценаріїв конфігурації двостекового Service.
Параметри подвійного стека в нових Services
Специфікація цього Service явно не визначає .spec.ipFamilyPolicy. Коли ви створюєте цей Service, Kubernetes призначає кластерний IP для Service з першого налаштованого service-cluster-ip-range і встановлює .spec.ipFamilyPolicy у SingleStack. (Services без селекторів та headless Services із селекторами поводитимуться так само.)
Специфікація цього Service явно визначає PreferDualStack в .spec.ipFamilyPolicy. Коли ви створюєте цей Service у двостековому кластері, Kubernetes призначає адреси IPv4 та IPv6 для Service. Панель управління оновлює .spec Service, щоб зафіксувати призначені IP-адреси. Поле .spec.clusterIPs є основним і містить обидві призначені IP-адреси; .spec.clusterIP є вторинним полем, значення якого обчислюється з .spec.clusterIPs.
Для поля .spec.clusterIP панель управління записує IP-адресу з того самого сімейства адрес, що й перший діапазон кластерних IP Services.
В одностековому кластері обидва поля .spec.clusterIPs та .spec.clusterIP містять лише одну адресу.
У кластері з увімкненим подвійним стеком вказання RequireDualStack в .spec.ipFamilyPolicy працює так само, як і PreferDualStack.
Специфікація цього Service явно визначає IPv6 та IPv4 в .spec.ipFamilies, а також PreferDualStack в .spec.ipFamilyPolicy. Коли Kubernetes призначає адреси IPv6 та IPv4 у .spec.clusterIPs, .spec.clusterIP встановлюється на адресу IPv6, оскільки це перший елемент масиву .spec.clusterIPs, що перевизначає стандартну поведінку.
Стандартні значення подвійного стека в наявних Services
Ці приклади демонструють стандартну поведінку, коли подвійний стек щойно увімкнено в кластері, де вже існують Services. (Оновлення наявного кластера до версії 1.21 або новішої вмикає подвійний стек.)
Коли в кластері увімкнено подвійний стек, панель управління налаштовує наявні Services (чи то IPv4, чи IPv6), встановлюючи .spec.ipFamilyPolicy у SingleStack, а .spec.ipFamilies — у сімейство адрес наявного Service. Кластерний IP наявного Service зберігається в .spec.clusterIPs.
Коли в кластері увімкнено подвійний стек, панель управління налаштовує наявні headless Services із селекторами, встановлюючи .spec.ipFamilyPolicy у SingleStack, а .spec.ipFamilies — у сімейство адрес першого діапазону кластерних IP Services (налаштованого через прапорець --service-cluster-ip-range для kube-apiserver), навіть якщо .spec.clusterIP встановлено в None.
Перемикання Services між одностековим та двостековим режимами
Services можна перемикати з одностекового режиму на двостековий і навпаки.
Щоб перемкнути Service з одностекового режиму на двостековий, змініть .spec.ipFamilyPolicy з SingleStack на PreferDualStack або RequireDualStack, залежно від потреби. Коли ви переводите цей Service з одностекового режиму на двостековий, Kubernetes призначає відсутнє сімейство адрес, тож Service тепер має адреси IPv4 та IPv6.
Відредагуйте специфікацію Service, оновивши .spec.ipFamilyPolicy з SingleStack на PreferDualStack.
До:
spec:ipFamilyPolicy:SingleStack
Після:
spec:ipFamilyPolicy:PreferDualStack
Щоб перемкнути Service з двостекового режиму на одностековий, змініть .spec.ipFamilyPolicy з PreferDualStack або RequireDualStack на SingleStack. Коли ви переводите цей Service з двостекового режиму на одностековий, Kubernetes залишає лише перший елемент масиву .spec.clusterIPs, встановлює .spec.clusterIP на цю IP-адресу, а .spec.ipFamilies — на сімейство адрес .spec.clusterIPs.
Headless Services без селектора
Для Headless Services без селекторів і без явно вказаного .spec.ipFamilyPolicy стандартним значенням поля .spec.ipFamilyPolicy є RequireDualStack.
Service типу LoadBalancer
Щоб створити двостековий балансувальник навантаження для вашого Service:
Встановіть значення поля .spec.type в LoadBalancer
Встановіть значення поля .spec.ipFamilyPolicy в PreferDualStack або RequireDualStack
Примітка:
Щоб використовувати двостековий Service типу LoadBalancer, ваш хмарний провайдер має підтримувати балансувальники навантаження IPv4 та IPv6.
Вихідний трафік
Якщо ви хочете увімкнути вихідний трафік, щоб досягати призначень за межами кластера (наприклад, публічного Інтернету) з Podʼа, який використовує адреси IPv6, що не маршрутизуються публічно, вам потрібно дати Podʼу змогу використовувати публічно маршрутизовану адресу IPv6 за допомогою такого механізму, як прозоре проксіювання або IP-маскування. Проєкт ip-masq-agent підтримує IP-маскування у двостекових кластерах.
Примітка:
Переконайтеся, що ваш провайдер CNI підтримує IPv6.
Підтримка Windows
Kubernetes у Windows не підтримує одностекову мережу «лише IPv6». Однак підтримується двостекова мережа IPv4/IPv6 для Podʼів і вузлів з одностековими Services.
Ви можете використовувати двостекову мережу IPv4/IPv6 з мережами l2bridge.
Примітка:
Оверлейні мережі (VXLAN) у Windows не підтримують двостекову мережу.
Докладніше про різні режими мережі у Windows читайте в розділі Мережа у Windows.
Маршрутизація з урахуванням топології надає механізм, який допомагає утримувати мережевий трафік у межах зони, з якої він надійшов. Надання переваги трафіку в межах однієї зони між Podʼами у вашому кластері може допомогти з надійністю, продуктивністю (затримкою мережі та пропускною здатністю) або вартістю.
Маршрутизація з урахуванням топології налаштовує поведінку маршрутизації так, щоб трафік по можливості залишався в зоні, з якої він надійшов. У деяких випадках це може допомогти зменшити витрати або покращити продуктивність мережі.
Мотивація
Кластери Kubernetes дедалі частіше розгортаються в багатозональних середовищах. Маршрутизація з урахуванням топології надає механізм, який допомагає утримувати трафік у межах зони, з якої він надійшов. Під час обчислення точок доступу для Service контролер EndpointSlice враховує топологію (регіон і зону) кожної точки доступу та заповнює поле hints, щоб призначити її зоні. Компоненти кластера, такі як kube-proxy, можуть використовувати ці підказки, щоб впливати на маршрутизацію трафіку (надаючи перевагу топологічно ближчим точкам доступу).
Увімкнення маршрутизації з урахуванням топології
Ви можете увімкнути маршрутизацію з урахуванням топології для Service, встановивши анотацію service.kubernetes.io/topology-mode у значення Auto. Коли в кожній зоні є достатньо точок доступу, в EndpointSlices заповнюються підказки топології (Topology Hints), що призначають окремі точки доступу конкретним зонам, і трафік маршрутизується ближче до місця, звідки він надійшов.
Коли це працює найкраще
Ця можливість працює найкраще, коли:
1. Вхідний трафік рівномірно розподілений
Якщо значна частина трафіку надходить з однієї зони, цей трафік може перевантажити підмножину точок доступу, призначених цій зоні. Цю можливість не рекомендується використовувати, коли очікується, що вхідний трафік надходитиме з однієї зони.
2. У Service є 3 чи більше точок доступу на зону
У кластері з трьома зонами це означає 9 чи більше точок доступу. Якщо точок доступу менше ніж 3 на зону, існує висока (≈50%) ймовірність, що контролер EndpointSlice не зможе рівномірно розподілити точки доступу й натомість повернеться до стандартного підходу до маршрутизації в межах кластера.
Як це працює
Евристика "Auto" намагається пропорційно розподілити кількість точок доступу між зонами. Зверніть увагу, що ця евристика працює найкраще для Services зі значною кількістю точок доступу.
Контролер EndpointSlice
Контролер EndpointSlice відповідає за встановлення підказок в EndpointSlices, коли цю евристику увімкнено. Контролер призначає кожній зоні пропорційну кількість точок доступу. Ця пропорція ґрунтується на доступних для розподілу ядрах CPU вузлів, що працюють у цій зоні. Наприклад, якщо в одній зоні є 2 ядра CPU, а в іншій лише 1 ядро CPU, контролер призначить удвічі більше точок доступу зоні з 2 ядрами CPU.
У цьому прикладі показано, як виглядає EndpointSlice із заповненими підказками:
Компонент kube-proxy фільтрує точки доступу, до яких він маршрутизує трафік, на основі підказок, встановлених контролером EndpointSlice. У більшості випадків це означає, що kube-proxy може маршрутизувати трафік до точок доступу в тій самій зоні. Іноді контролер призначає точки доступу з іншої зони, щоб забезпечити рівномірніший розподіл точок доступу між зонами. Через це частина трафіку маршрутизуватиметься до інших зон.
Запобіжники
Панель управління Kubernetes та kube-proxy на кожному вузлі застосовують деякі запобіжні правила перед використанням Topology Aware Hints. Якщо ці перевірки не проходять, kube-proxy вибирає точки доступу з будь-якої частини вашого кластера, незалежно від зони.
Недостатня кількість точок доступу: Якщо точок доступу менше, ніж зон у кластері, контролер не призначатиме жодних підказок.
Неможливо досягти збалансованого розподілу: У деяких випадках досягти збалансованого розподілу точок доступу між зонами неможливо. Наприклад, якщо zone-a удвічі більша за zone-b, але є лише 2 точки доступу, точка доступу, призначена zone-a, може отримувати вдвічі більше трафіку, ніж точка доступу zone-b. Контролер не призначає підказок, якщо не може знизити це значення «очікуваного перевантаження» нижче прийнятного порогу для кожної зони. Важливо, що це не ґрунтується на зворотному звʼязку в реальному часі. Окремі точки доступу все ще можуть бути перевантажені.
Один чи кілька вузлів мають недостатньо інформації: Якщо будь-який вузол не має мітки topology.kubernetes.io/zone або не повідомляє значення CPU, доступного для розподілу, панель управління не встановлює жодних топологічних підказок для точок доступу, тож kube-proxy не фільтрує точки доступу за зоною.
Одна чи кілька точок доступу не мають підказки щодо зони: У такому разі kube-proxy вважає, що відбувається перехід до Topology Aware Hints або від них. Фільтрувати точки доступу для Service в такому стані було б небезпечно, тому kube-proxy повертається до використання всіх точок доступу.
Зону не представлено в підказках: Якщо kube-proxy не може знайти принаймні одну точку доступу з підказкою для зони, в якій він працює, він повертається до використання точок доступу з усіх зон. Найімовірніше це трапиться, коли ви додаєте нову зону до наявного кластера.
Обмеження
Topology Aware Hints не використовуються, коли для Service internalTrafficPolicy встановлено в Local. Обидві можливості можна використовувати в одному кластері для різних Services, але не для одного Service.
Цей підхід погано працюватиме для Services, у яких значна частина трафіку надходить із підмножини зон. Він передбачає, що вхідний трафік буде приблизно пропорційним місткості вузлів у кожній зоні.
Контролер EndpointSlice ігнорує неготові вузли під час обчислення пропорцій для кожної зони. Це може мати небажані наслідки, якщо значна частина вузлів неготова.
Контролер EndpointSlice ігнорує вузли з мітками node-role.kubernetes.io/control-plane або node-role.kubernetes.io/master. Це може бути проблемою, якщо на цих вузлах також працюють робочі навантаження.
Контролер EndpointSlice не враховує tolerations під час розгортання або обчислення пропорцій для кожної зони. Якщо Podʼи, що обслуговують Service, обмежені підмножиною вузлів кластера, це не враховуватиметься.
Це може погано працювати з автомасштабуванням. Наприклад, якщо багато трафіку надходить з однієї зони, цей трафік оброблятимуть лише точки доступу, призначені цій зоні. Через це Horizontal Pod Autoscaler може або не помітити цю подію, або нові Podʼи запускатимуться в іншій зоні.
Власні евристики
Kubernetes розгортається багатьма різними способами, і немає єдиної евристики розподілу точок доступу між зонами, яка підходила б для кожного випадку. Ключова мета цієї можливості — дозволити розробку власних евристик, якщо вбудована евристика не підходить для вашого випадку. Перші кроки для увімкнення власних евристик увійшли до випуску 1.27. Це обмежена реалізація, яка може ще не охоплювати деякі актуальні та ймовірні ситуації.
Дізнайтесь про поле trafficDistribution, що тісно повʼязане з анотацією service.kubernetes.io/topology-mode і надає гнучкі варіанти маршрутизації трафіку в Kubernetes.
8 - Мережа у Windows
Kubernetes підтримує роботу вузлів як на Linux, так і на Windows. Ви можете поєднувати обидва види вузлів в одному кластері. На цій сторінці наведено огляд мережевих аспектів, специфічних для операційної системи Windows.
Мережа контейнерів у Windows
Мережа для контейнерів Windows надається через втулки CNI. Контейнери Windows працюють подібно до віртуальних машин з погляду мережі. Кожен контейнер має віртуальний мережевий адаптер (vNIC), підключений до віртуального комутатора Hyper-V (vSwitch). Host Networking Service (HNS) та Host Compute Service (HCS) спільно створюють контейнери й підключають vNIC контейнерів до мереж. HCS відповідає за керування контейнерами, а HNS — за керування мережевими ресурсами, такими як:
Віртуальні мережі (зокрема створення vSwitches)
Точки доступу / vNIC
Namespaces
Політики, зокрема інкапсуляція пакетів, правила балансування навантаження, ACL та правила NAT.
HNS та vSwitch у Windows реалізують простори імен і можуть за потреби створювати віртуальні NIC для Podʼа чи контейнера. Однак багато конфігурацій, таких як DNS, маршрути та метрики, зберігаються в базі даних реєстру Windows, а не у файлах в /etc, як у Linux. Реєстр Windows контейнера відокремлений від реєстру хоста, тому такі прийоми, як зіставлення /etc/resolv.conf з хоста в контейнер, не дають того ефекту, що в Linux. Це потрібно налаштовувати за допомогою API Windows, що виконуються в контексті цього контейнера. Тому реалізації CNI повинні викликати HNS, а не покладатися на зіставлення файлів, щоб передавати мережеві дані в Pod чи контейнер.
Режими мережі
Windows підтримує пʼять різних мережевих драйверів/режимів: L2bridge, L2tunnel, Overlay (Beta), Transparent та NAT. У гетерогенному кластері з робочими вузлами Windows і Linux потрібно вибрати мережеве рішення, сумісне і з Windows, і з Linux. У таблиці нижче наведено зовнішні (out-of-tree) втулки, які підтримуються у Windows, з рекомендаціями щодо використання кожного CNI:
Мережевий драйвер
Опис
Зміни пакетів контейнерів
Мережеві втулки
Характеристики мережевих втулків
L2bridge
Контейнери підключені до зовнішнього vSwitch. Контейнери підключені до базової мережі (underlay), хоча фізичній мережі не потрібно знати MAC-адреси контейнерів, оскільки вони переписуються на вході та виході.
MAC переписується на MAC хоста, IP може бути переписаний на IP хоста за допомогою політики HNS OutboundNAT.
win-bridge використовує режим мережі L2bridge, підключає контейнери до базової мережі хостів і забезпечує найкращу продуктивність. Потребує маршрутів, визначених користувачем (UDR), для звʼязку між вузлами.
L2Tunnel
Це особливий випадок l2bridge, який використовується лише в Azure. Усі пакети надсилаються на хост віртуалізації, де застосовується політика SDN.
Azure-CNI дозволяє інтегрувати контейнери з Azure vNET і дає їм змогу використовувати набір можливостей, які надає Azure Virtual Network. Наприклад, безпечно підключатися до сервісів Azure або використовувати NSG Azure. Див. azure-cni, де є кілька прикладів
Overlay
Контейнерам надається vNIC, підключений до зовнішнього vSwitch. Кожна оверлейна мережа отримує власну IP-підмережу, визначену власним IP-префіксом. Драйвер оверлейної мережі використовує інкапсуляцію VXLAN.
win-overlay слід використовувати, коли віртуальні мережі контейнерів потрібно ізолювати від базової мережі хостів (наприклад, з міркувань безпеки). Дозволяє повторно використовувати IP-адреси для різних оверлейних мереж (які мають різні теґи VNID), якщо у вашому центрі обробки даних обмаль IP-адрес. Цей варіант потребує KB4489899 у Windows Server 2019.
Потребує зовнішнього vSwitch. Контейнери підключені до зовнішнього vSwitch, що забезпечує взаємодію всередині Podʼа через логічні мережі (логічні комутатори та маршрутизатори).
Пакет інкапсулюється через тунелювання GENEVE або STT, щоб досягти Podʼів, які не перебувають на тому самому хості. Пакети пересилаються або відкидаються на основі метаданих тунелю, які надає мережевий контролер ovn. NAT виконується для трафіку північ-південь.
Розгортається за допомогою ansible. Розподілені ACL можна застосовувати за допомогою політик Kubernetes. Підтримка IPAM. Балансування навантаження можливе без kube-proxy. NAT виконується без використання iptables/netsh.
NAT (не використовується в Kubernetes)
Контейнерам надається vNIC, підключений до внутрішнього vSwitch. DNS/DHCP надається внутрішнім компонентом, який називається WinNAT
Цей втулок підтримує делегування одному з еталонних втулків CNI (win-overlay, win-bridge) для спільної роботи з демоном Flannel у Windows (Flanneld), щоб автоматично призначати оренду підмережі вузла та створювати мережу HNS. Цей втулок читає власний файл конфігурації (cni.conf) і обʼєднує його зі змінними середовища з файлу subnet.env, згенерованого FlannelD. Потім він делегує налаштування мережі одному з еталонних втулків CNI й надсилає правильну конфігурацію з призначеною вузлу підмережею до втулка IPAM (наприклад, host-local).
Для обʼєктів Node, Pod та Service підтримуються такі мережеві потоки для трафіку TCP/UDP:
This is a stable feature in Kubernetes, and has been since version v1.34. It was first available in the v1.14 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate WinDSR, Kubernetes ignores it but does not report any error.
Режим балансування навантаження, у якому виправлення IP-адрес і LBNAT відбуваються безпосередньо на порту vSwitch контейнера; трафік сервісу надходить з IP-адресою джерела, що дорівнює IP-адресі вихідного Podʼа. Це оптимізує продуктивність, дозволяючи зворотному трафіку, що маршрутизується через балансувальники навантаження, оминати балансувальник і відповідати безпосередньо клієнту; це зменшує навантаження на балансувальник і загальну затримку. Докладніше читайте в Direct Server Return (DSR) in a nutshell.
Балансування навантаження та Services
Service Kubernetes — це абстракція, яка визначає логічний набір Podʼів і спосіб доступу до них мережею. У кластері з вузлами Windows можна використовувати такі типи Service:
Встановіть такий аргумент командного рядка (для версії 1.37): --enable-dsr=true
Preserve-Destination
Пропускає DNAT трафіку сервісу, зберігаючи віртуальну IP-адресу цільового сервісу в пакетах, що досягають Podʼа-бекенда. Також вимикає пересилання між вузлами.
Windows Server, версія 1903
Встановіть "preserve-destination": "true" в анотаціях сервісу та увімкніть DSR у kube-proxy.
Двостекова мережа IPv4/IPv6
Нативний звʼязок IPv4-IPv4 паралельно зі звʼязком IPv6-IPv6 до кластера, з нього та всередині нього
Гарантує збереження IP-адреси джерела вхідного трафіку. Також вимикає пересилання між вузлами.
Windows Server 2019
Встановіть service.spec.externalTrafficPolicy у "Local" та увімкніть DSR у kube-proxy
Обмеження
Така мережева функціональність не підтримується на вузлах Windows:
Режим мережі хоста
Локальний доступ до NodePort із самого вузла (працює для інших вузлів або зовнішніх клієнтів)
Понад 64 Podʼи-бекенди (або унікальні адреси призначення) для одного Service
Звʼязок IPv6 між Podʼами Windows, підключеними до оверлейних мереж
Local Traffic Policy в режимі без DSR
Вихідний звʼязок за протоколом ICMP через win-overlay, win-bridge або за допомогою втулка Azure-CNI. Зокрема, площина даних Windows (VFP) не підтримує транспозицію пакетів ICMP, і це означає:
Пакети ICMP, спрямовані до призначень у тій самій мережі (наприклад, звʼязок між Podʼами через ping), працюють як очікується;
TCP/UDP-пакети працюють, як очікується;
Пакети ICMP, спрямовані через віддалену мережу (наприклад, звʼязок Podʼа із зовнішнім інтернетом через ping), не можуть бути транспоновані, тому не маршрутизуються назад до свого джерела;
Оскільки TCP/UDP-пакети все ще можуть бути транспоновані, під час налагодження звʼязку із зовнішнім світом ви можете замінити ping <destination> на curl <destination>.
Інші обмеження:
Еталонні мережеві втулки Windows win-bridge та win-overlay не реалізують специфікацію CNI v0.4.0 через відсутність реалізації CHECK.
Втулок CNI Flannel VXLAN має такі обмеження у Windows:
Звʼязок між вузлом і Podʼом можливий лише для локальних Podʼів із Flannel v0.12.0 (або новішим).
Flannel обмежений використанням VNI 4096 та UDP-порту 4789. Докладніше про ці параметри див. в офіційній документації бекенда Flannel VXLAN.
9 - Виділення ClusterIP для Service
У Kubernetes Services — це абстрактний спосіб надати доступ до застосунку, що працює на наборі Podʼів. Services можуть мати віртуальну IP-адресу в межах кластера (за допомогою Service з type: ClusterIP). Клієнти можуть підключатися за цією віртуальною IP-адресою, а Kubernetes балансує трафік до цього Service між різними Podʼами, що його обслуговують.
Як виділяються ClusterIP для Services?
Коли Kubernetes потрібно призначити віртуальну IP-адресу для Service, це відбувається одним із двох способів:
динамічно
панель управління кластера автоматично вибирає вільну IP-адресу з налаштованого діапазону IP для Services із type: ClusterIP.
статично
ви вказуєте IP-адресу на свій вибір із налаштованого діапазону IP для Services.
У всьому вашому кластері ClusterIP кожного Service має бути унікальним. Спроба створити Service із конкретним ClusterIP, який уже виділено, поверне помилку.
Навіщо резервувати Cluster IP для Services?
Іноді вам може знадобитися, щоб Services працювали на добре відомих IP-адресах, аби інші компоненти та користувачі в кластері могли ними користуватися.
Найкращий приклад — DNS Service для кластера. За неформальною домовленістю деякі інсталятори Kubernetes призначають DNS Service 10-ту IP-адресу з діапазону IP для Services. Припустимо, ви налаштували кластер із діапазоном IP для Services 10.96.0.0/16 і хочете, щоб IP-адресою вашого DNS Service була 10.96.0.10; тоді вам доведеться створити такий Service:
Але, як уже пояснювалося, IP-адресу 10.96.0.10 не зарезервовано. Якщо інші Services буде створено раніше або паралельно з динамічним виділенням, є ймовірність, що їм буде виділено цю IP-адресу. Тоді ви не зможете створити DNS Service, оскільки це завершиться помилкою конфлікту.
Як уникнути конфліктів ClusterIP для Services?
Стратегія виділення ClusterIP для Services, реалізована в Kubernetes, зменшує ризик колізій.
Діапазон ClusterIP поділено на основі формули min(max(16, cidrSize / 16), 256), яку можна описати так: ніколи не менше ніж 16 і не більше ніж 256, з поступовим кроком між ними.
Динамічне призначення IP стандартно використовує верхню смугу, а коли її вичерпано, використовує нижній діапазон. Це дає користувачам змогу робити статичні виділення в нижній смузі з низьким ризиком колізій.
Приклади
Приклад 1
У цьому прикладі використовується діапазон IP-адрес: 10.96.0.0/24 (нотація CIDR) для IP-адрес Services.
Розмір діапазону: 28 - 2 = 254
Зсув смуги: min(max(16, 256/16), 256) = min(16, 256) = 16
Початок статичної смуги: 10.96.0.1
Кінець статичної смуги: 10.96.0.16
Кінець діапазону: 10.96.0.254
pie showData
title 10.96.0.0/24
"Статичний" : 16
"Динамічний" : 238
Приклад 2
У цьому прикладі використовується діапазон IP-адрес: 10.96.0.0/20 (нотація CIDR) для IP-адрес Services.
Розмір діапазону: 212 - 2 = 4094
Зсув смуги: min(max(16, 4096/16), 256) = min(256, 256) = 256
Початок статичної смуги: 10.96.0.1
Кінець статичної смуги: 10.96.1.0
Кінець діапазону: 10.96.15.254
pie showData
title 10.96.0.0/20
"Статичний" : 256
"Динамічний" : 3838
Приклад 3
У цьому прикладі використовується діапазон IP-адрес: 10.96.0.0/16 (нотація CIDR) для IP-адрес Services.
Розмір діапазону: 216 - 2 = 65534
Зсув смуги: min(max(16, 65536/16), 256) = min(4096, 256) = 256
Початок статичної смуги: 10.96.0.1
Кінець статичної смуги: 10.96.1.0
Кінець діапазону: 10.96.255.254
pie showData
title 10.96.0.0/16
"Статичний" : 256
"Динамічний" : 65278
Якщо два Podʼи у вашому кластері хочуть взаємодіяти, і обидва Podʼи фактично працюють на одному вузлі, використовуйте політику внутрішнього трафіку Service, щоб утримувати мережевий трафік у межах цього вузла. Якщо уникнути проходження трафіку туди й назад через мережу кластера, це може допомогти з надійністю, продуктивністю (затримкою мережі та пропускною здатністю) або вартістю.
СТАН ФУНКЦІОНАЛУ:GA since Kubernetes v1.26
Політика внутрішнього трафіку Service дозволяє обмежити внутрішній трафік, маршрутизуючи його лише до точок доступу в межах вузла, з якого надійшов трафік. Тут «внутрішній» трафік означає трафік, який надходить від Podʼів у поточному кластері. Це може допомогти зменшити витрати та покращити продуктивність.
Використання політики внутрішнього трафіку Service
Ви можете увімкнути політику лише для внутрішнього трафіку для Service, встановивши його .spec.internalTrafficPolicy у Local. Це вказує kube-proxy використовувати для внутрішнього трафіку кластера лише локальні для вузла точки доступу.
Примітка:
Для Podʼів на вузлах без точок доступу для певного Service цей Service поводиться так, ніби в нього немає точок доступу (для Podʼів на цьому вузлі), навіть якщо він має точки доступу на інших вузлах.
У цьому прикладі показано, як виглядає Service, коли ви встановлюєте .spec.internalTrafficPolicy у Local:
kube-proxy фільтрує точки доступу, до яких він маршрутизує трафік, на основі параметра spec.internalTrafficPolicy. Коли встановлено Local, враховуються лише локальні для вузла точки доступу. Коли встановлено Cluster (стандартно) або параметр не встановлено, Kubernetes враховує всі точки доступу.