Це багатосторінковий друкований вигляд цього розділу. Натисність щоб друкувати.

Повернутися до звичайного перегляду сторінки.

Service, балансування навантаження та мережа

Концепції та ресурси, що лежать в основі роботи в мережі в Kubernetes.

Мережева модель Kubernetes

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

Kubernetes накладає наступні фундаментальні вимоги до будь-якої реалізації мережі (з урахуванням будь-якої цілеспрямованої політики сегментації мережі):

  • Podʼи можуть спілкуватися з усіма іншими Podʼами на будь-якому іншому вузлі без NAT
  • Агенти на вузлі (наприклад, системні служби, kubelet) можуть спілкуватися з усіма Podʼами на цьому вузлі

Примітка: Для тих платформ, які підтримують Podʼи, що працюють в мережі вузла (наприклад, Linux), коли Podʼи приєднуються до мережі вузла вони все ще можуть спілкуватися з усіма Podʼами на всіх вузлах без NAT.

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

IP-адреси Kubernetes існують на рівні Pod — контейнери всередині Pod спільно використовують свої мережеві простори імен, включаючи їх IP-адреси та MAC-адреси. Це означає, що контейнери всередині Pod можуть мати доступ до портів один одного через localhost. Це також означає, що контейнери всередині Pod повинні координувати використання портів, але це не відрізняється від процесів у віртуальній машині. Ця модель називається "IP-на-кожен-Pod".

Те, як це реалізовано, залежить від середовища виконання контейнерів в кожному конкретному випадку.

Можна запросити порти на самому вузлі (Node), які переспрямувати до вашого Podʼу. Це називається "портами на вузлі", але досить нішева операція. Те як це реалізовано, залежить від середовища виконання контейнерів в кожному конкретному випадку. Pod сам по собі не бачить існування чи відсутності портів хосту.

Мережа Kubernetes розвʼязує чотири проблеми:

Посібник Поєднання застосунків за допомогою служб пояснює, як використовувати Service для забезпечення взаємодії між застосунками в Kubernetes.

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

1 - Service

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

В Kubernetes, Service — це метод надання доступу ззовні до мережевого застосунку, який працює як один чи кілька Podʼів у вашому кластері.

Ключова мета Service в Kubernetes — це те, що вам не потрібно модифікувати ваш поточний застосунок для використання незнайомого механізму виявлення Service. Ви можете виконувати код в Podʼах, чи це буде код, призначений для світу, орієнтованого на хмари, або старий застосунок, який ви контейнеризували. Ви використовуєте Service, щоб зробити цей набір Podʼіів доступним в мережі, так щоб клієнти могли взаємодіяти з ним.

Якщо ви використовуєте Deployment для запуску вашого застосунку, цей Deployment може динамічно створювати та знищувати Podʼи. З одного моменту і до наступного, ви не знаєте, скільки з цих Podʼів працюють і є справними; ви навіть не можете знати, як називаються ці справні Podʼи. Podʼи Kubernetes створюються та знищуються для відповідності бажаному стану вашого кластера. Podʼи є ефемерними ресурсами (ви не повинні очікувати, що індивідуальний Pod є надійним та довговічним).

Кожен Pod отримує свою власну IP-адресу (Kubernetes очікує, що мережеві втулки гарантують це). Для даного Deployment у вашому кластері набір Podʼів, який працює в один момент часу, може відрізнятися від набору Pod, який працює для цього застосунку наступний момент часу.

Це призводить до проблеми: якщо певний набір Podʼів (назвемо їх "backend") надає функціонал іншим Podʼам (назвемо їх "frontend") всередині вашого кластера, як фронтенд дізнається та відстежує, яку IP-адресу підключати, щоб він міг використовувати частину робочого навантаження?

Познайомтесь з Service.

Service в Kubernetes

API Service, що є частиною Kubernetes, є абстракцією, яка допомагає вам давати групі Podʼів доступ в мережі. Кожен об'єкт Service визначає логічний набір endpoint (зазвичай endpoint — Pod) разом із політикою того, як робити ці Podʼи доступними.

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

Абстракція Service дозволяє таке відокремлення.

Набір Podʼів, яким призначається Service, зазвичай визначається селектором, який ви визначаєте. Щоб дізнатися про інші способи визначення endpointʼів сервісу, дивіться Сервіси без селекторів.

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

API Gateway для Kubernetes надає додаткові можливості, які виходять за межі Ingress і Service. Ви можете додати Gateway до вашого кластера — це родина розширених API, реалізованих за допомогою CustomResourceDefinitions — і потім використовувати їх для налаштування доступу до мережевих сервісів, що працюють у вашому кластері.

Хмарно-нативне виявлення сервісів

Якщо ви можете використовувати API Kubernetes для виявлення сервісів у вашому застосунку, ви можете звертатись до сервера API по відповідні EndpointSlices. Kubernetes оновлює EndpointSlices для сервісу кожного разу, коли набір Podʼів у сервісі змінюється.

Для не-нативних застосунків Kubernetes пропонує способи розміщення мережевого порту чи балансувальника між вашим застосунком та Podʼами бекенду.

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

Визначення Сервісу

Service — це обʼєкт (так само як Pod чи ConfigMap є обʼєктами). Ви можете створювати, переглядати або змінювати визначення Service, використовуючи API Kubernetes. Зазвичай для цього ви використовуєте інструмент, такий як kubectl, який звертається до API.

Наприклад, припустимо, у вас є набір Podʼів, які слухають TCP-порт 9376 і мають мітку app.kubernetes.io/name=MyApp. Ви можете визначити Сервіс, щоб опублікувати цього TCP-слухача:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

Застосування цього маніфесту створює новий Сервіс з назвою "my-service" зі стандартним типом служби ClusterIP. Сервіс обслуговує TCP-порт 9376 на будь-якому Podʼі з міткою app.kubernetes.io/name: MyApp.

Kubernetes призначає цьому Сервісу IP-адресу (так званий кластерний IP), що використовується механізмом віртуалізації IP-адрес. Для отримання докладнішої інформації про цей механізм, читайте Віртуальні IP та Проксі-сервіси.

Контролер для цього Сервісу постійно сканує Podʼи, які відповідають його селектору, а потім вносить будь-які необхідні оновлення до набору EndpointSlices для Сервісу.

Назва обʼєкта Сервісу повинна бути дійсним іменем мітки за стандартом RFC 1035.

Визначення портів

Визначення портів в Podʼах мають назви, і ви можете посилатися на ці назви в атрибуті targetPort Сервісу. Наприклад, ми можемо привʼязати targetPort Сервісу до порту Podʼа таким чином:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app.kubernetes.io/name: proxy
spec:
  containers:
  - name: nginx
    image: nginx:stable
    ports:
      - containerPort: 80
        name: http-web-svc

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app.kubernetes.io/name: proxy
  ports:
  - name: name-of-service-port
    protocol: TCP
    port: 80
    targetPort: http-web-svc

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

Станадртним протоколом для Service є TCP; ви також можете використовувати будь-який інший підтримуваний протокол.

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

Сервіси без селекторів

Сервіси найчастіше абстрагують доступ до Podʼів Kubernetes завдяки селектору, але коли вони використовуються разом із відповідним набором EndpointSlices обʼєктів та без селектора, Сервіс може абстрагувати інші типи бекендів, включаючи ті, які працюють поза кластером.

Наприклад:

  • Ви хочете мати зовнішній кластер баз даних у вашому експлуатаційному оточенні, але у своєму тестовому середовищі ви використовуєте свої власні бази даних.
  • Ви хочете спрямувати ваш Сервіс на Сервіс в іншому Namespace чи в іншому кластері.
  • Ви мігруєте робоче навантаження в Kubernetes. Під час оцінки цього підходу, ви запускаєте лише частину своїх бекендів в Kubernetes.

У будь-якому з цих сценаріїв ви можете визначити Сервіс без вказівки селектора для відповідності Podʼам. Наприклад:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376

Оскільки у цього Сервісу немає селектора, відповідні обʼєкти EndpointSlice (та застарілі Endpoints) не створюються автоматично. Ви можете повʼязувати Сервіс з мережевою адресою та портом, де він працює, додавши обʼєкт EndpointSlice вручну. Наприклад:

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: my-service-1 # за звичай, використовуйте назву Сервісу
                     # як префікс для назви EndpointSlice
  labels:
    # Ви повинні встановити мітку "kubernetes.io/service-name".
    # Встановіть її значення, щоб відповідати назві Сервісу
    kubernetes.io/service-name: my-service
addressType: IPv4
ports:
  - name: http # Має збігатись з іменем порту у визначенні Service 
               # визначеному вище
    appProtocol: http
    protocol: TCP
    port: 9376
endpoints:
  - addresses:
      - "10.4.5.6"
  - addresses:
      - "10.1.2.3"

Власні EndpointSlices

Коли ви створюєте обʼєкт EndpointSlice для Сервісу, ви можете використовувати будь-яку назву для EndpointSlice. Кожен EndpointSlice в просторі імен повинен мати унікальну назву. Ви поєднуєте EndpointSlice із Сервісом, встановлюючи label kubernetes.io/service-name на цьому EndpointSlice.

Для EndpointSlice, який ви створюєте самостійно або у своєму власному коді, вам також слід вибрати значення для мітки endpointslice.kubernetes.io/managed-by. Якщо ви створюєте свій власний код контролера для управління EndpointSlice, розгляньте можливість використання значення, схожого на "my-domain.example/name-of-controller". Якщо ви використовуєте інструмент від стороннього постачальника, використовуйте назву інструменту в нижньому регістрі та замініть пробіли та інші знаки пунктуації на дефіси (-). Якщо ви безпосередньо використовуєте інструмент, такий як kubectl, для управління EndpointSlice, використовуйте назву, яка описує це ручне управління, таку як "staff" або "cluster-admins". Ви повинні уникати використання захищеного значення "controller", яке ідентифікує EndpointSlices, які керуються власною панеллю управління Kubernetes.

Доступ до Сервісу без селектора

Доступ до Сервісу без селектора працює так само, якби він мав селектор. У прикладі Сервісу без селектора, трафік маршрутизується до одного з двох endpoint, визначених у маніфесті EndpointSlice: TCP-зʼєднання до 10.1.2.3 або 10.4.5.6, на порт 9376.

ExternalName Сервіс — це особливий випадок Сервісу, який не має селекторів і використовує DNS-імена замість них. Для отримання доклдадної інформації, див. розділ ExternalName.

EndpointSlices

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

EndpointSlices — це обʼєкти, які представляють підмножину (зріз) мережевих endpoint, які підтримують Сервіс.

Ваш кластер Kubernetes відстежує кількість endpointʼів, які представляє кожен EndpointSlice. Якщо для Сервісу є настільки багато endpointʼів, що досягається порогове значення, тоді Kubernetes додає ще один порожній EndpointSlice і зберігає там нову інформацію про endpoint. Типово Kubernetes створює новий EndpointSlice, як тільки наявні EndpointSlice всі містять принаймні 100 endpoint. Kubernetes не створює новий EndpointSlice, поки не буде потрібно додати додатковий endpoint.

Див. EndpointSlices для отримання додаткової інформації про цей API.

Endpoint

В API Kubernetes, Endpoints (тип ресурсу у множині) визначають список мережевих endpointʼів, зазвичай використовується Сервісом для визначення того, до яких Podʼів можна направляти трафік.

API EndpointSlice — це рекомендована заміна для Endpoints.

Endpoints з перевищеним обсягом

Kubernetes обмежує кількість endpointʼів, які можуть поміститися в один обʼєкт Endpoints. Коли є понад 1000 endpointʼів, які підтримують Сервіс, Kubernetes розмішує дані в обʼєкті Endpoints. Оскільки Сервіс може бути повʼязаним з більше ніж одним EndpointSlice, обмеження в 1000 endpointʼів впливає лише на застарілий API Endpoints.

У цьому випадку Kubernetes вибирає не більше 1000 можливих endpointʼів, які слід зберегти в обʼєкті Endpoints, і встановлює анотацію на Endpoints: endpoints.kubernetes.io/over-capacity: truncated. Панель управління також видаляє цю анотацію, якщо кількість бекенд-Podʼів впадає нижче 1000.

Трафік все ще відсилається на бекенди, але будь-який механізм балансування навантаження, який покладається на застарілий API Endpoints, відсилає трафік не більше, ніж до 1000 доступних бекенд-endpointʼів.

Той самий ліміт API означає, що ви не можете вручну оновлювати Endpoints так, щоб у них було понад 1000 endpointʼів.

Протокол застосунку

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

Поле appProtocol надає можливість вказати протокол застосунку для кожного порту Сервісу. Це використовується як підказка для реалізацій для надання розширеної поведінки для протоколів, які вони розуміють. Значення цього поля відображається відповідними обʼєктами Endpoints та EndpointSlice.

Це поле відповідає стандартному синтаксису міток Kubernetes. Дійсні значення — це одне з:

  • стандартні назви служб IANA.

  • Імплементаційно-визначені префіксовані імена, такі як mycompany.com/my-custom-protocol.

  • Імена з префіксом, визначені Kubernetes:

ПротоколОпис
kubernetes.io/h2cHTTP/2 поверх чіткого тексту, як описано в RFC 7540
kubernetes.io/wsWebSocket через текст, як описано у RFC 6455
kubernetes.io/wssWebSocket через TLS, як описано у RFC 6455

Сервіси з кількома портами

Для деяких Сервісів вам може знадобитися використовувати більше одного порту. Kubernetes дозволяє конфігурувати кілька визначень портів в обʼєкті Service. При використанні кількох портів для Сервісу, вам слід надавати всім портам імена, щоб вони були однозначними. Наприклад:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9377

Тип Сервісу

Для деяких частин вашого застосунку (наприклад, фронтенду) ви можете знадобитись звʼязати Сервіс з зовнішньою IP-адресою, доступну з-поза вашого кластера.

Типи Сервісів Kubernetes дозволяють вам вказати, який тип Сервісу ви потрібен.

Доступні значення type та їхні поведінки:

ClusterIP
Повʼязує Сервіс з внутрішньою IP-адресою кластера. Вибір цього значення робить Сервіс доступним лише зсередини кластера. Це значення використовується стандартно, якщо ви не вказали явно type для Сервісу. Ви можете дати Сервісу доступ в Інтернет за допомогою Ingress або Gateway.
NodePort
Повʼязує Сервіс на кожному IP-адресі вузла зі статичним портом (NodePort). Щоб зробити порт вузла доступним, Kubernetes налаштовує IP-адресу кластера, так само якби ви запросили Сервіс з type: ClusterIP.
LoadBalancer
Повʼязує Сервіс із зовнішніми споживачами за допомогою зовнішнього балансувальника навантаження. Kubernetes не надає безпосередньо компонент балансування навантаження; вам слід надати його, або ви можете інтегрувати свій кластер Kubernetes з постачальником хмарних послуг.
ExternalName
Повʼязує Сервіс зі змістом поля externalName (наприклад, на імʼя хоста api.foo.bar.example). Це конфігурує сервер DNS вашого кластера повертати запис CNAME з вказаною зовнішньою назвою хосту. Ніякого проксінгу не налаштовується.

Поле type в API Сервісу розроблене як вкладена функціональність — кожен рівень додається до попереднього. Однак існує виняток з цього вкладеного дизайну. Ви можете визначити Сервіс LoadBalancer, відключивши використання порту вузла для балансування навантаження.

type: ClusterIP

Цей тип Сервісу типово призначає IP-адресу з пулу IP-адрес, який ваш кластер зарезервував для цієї мети.

Кілька інших типів Сервісу базуються на типі ClusterIP.

Якщо ви визначаєте Сервіс, у якому .spec.clusterIP встановлено в "None", тоді Kubernetes не призначає IP-адресу. Див. сервіси headless для отримання додаткової інформації.

Вибір власної IP-адреси

Ви можете вказати власну IP-адресу кластера як частину запиту на створення Service. Для цього встановіть поле .spec.clusterIP. Наприклад, якщо у вас вже є наявний запис DNS, який ви хочете повторно використовувати, або старі системи, які налаштовані на певну IP-адресу і важко переналаштовуються.

IP-адреса, яку ви вибираєте, повинна бути дійсною IPv4 або IPv6 адресою з діапазону CIDR, який налаштований для сервера API за допомогою service-cluster-ip-range. Якщо ви намагаєтеся створити Сервіс із недійсною IP-адресою clusterIP, сервер API поверне HTTP-відповідь зі статус-кодом 422 для позначення проблеми.

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

type: NodePort

Якщо ви встановлюєте поле type в NodePort, панель управління Kubernetes виділяє порт з діапазону, вказаного прапорцем --service-node-port-range (типово: 30000-32767). Кожен вузол проксіює цей порт (той самий номер порту на кожному вузлі) у ваш Сервіс. Ваш Сервіс повідомляє виділений порт у полі .spec.ports[*].nodePort.

Використання NodePort дає вам свободу налаштувати власне рішення з балансування навантаження, конфігурувати середовища, які не повністю підтримуються Kubernetes, або навіть експонувати один або кілька IP-адрес вузлів безпосередньо.

Для Сервісу з портом вузла Kubernetes додатково виділяє порт (TCP, UDP або SCTP для відповідності протоколу Сервісу). Кожен вузол у кластері конфігурується на прослуховування цього призначеного порту і пересилання трафіку на одну з готових точок доступу, повʼязаних із цим Сервісом. Ви зможете звертатися до Сервісу з type: NodePort, ззовні кластера, підключаючись до будь-якого вузла за відповідним протоколом (наприклад: TCP) та відповідним портом (який призначено цьому Сервісу).

Вибір власного порту

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

Ось приклад маніфесту для Сервісу з type: NodePort, який вказує значення NodePort (30007 у цьому прикладі):

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - port: 80
      # Стандартно та для зручності, `targetPort` встановлено
      # в те ж значення, що й поле `port`.
      targetPort: 80
      # Необовʼязкове поле
      # Стандартно та для зручності, панель управління Kubernetes
      # виділить порт з діапазону (станадртно: 30000-32767)
      nodePort: 30007

Резервування діапазонів NodePort для уникнення конфліктів

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

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

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

Налаштування власної IP-адреси для Сервісів type: NodePort

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

Якщо ви хочете вказати певні IP-адреси для проксі-порта, ви можете встановити прапорець --nodeport-addresses для kube-proxy або еквівалентне поле nodePortAddresses у файлі конфігурації kube-proxy на конкретні блоки IP.

Цей прапорець приймає список IP-блоків через кому (наприклад, 10.0.0.0/8, 192.0.2.0/25) для вказівки діапазонів IP-адрес, які kube-proxy повинен вважати локальними для цього вузла.

Наприклад, якщо ви запускаєте kube-proxy з прапорцем --nodeport-addresses=127.0.0.0/8, kube-proxy вибирає лише інтерфейс loopback для NodePort-сервісів. Типово для --nodeport-addresses є порожній список. Це означає, що kube-proxy повинен вважати всі доступні мережеві інтерфейси локальними для NodePort. (Це також сумісно з раніше випущеними версіями Kubernetes.)

type: LoadBalancer

У хмарних постачальників, які підтримують зовнішні балансувальники навантаження, встановлення поле type в LoadBalancer надає балансувальник навантаження для вашого Сервісу. Створення балансувальника навантаження відбувається асинхронно, і інформація про створений балансувальник публікується у поле .status.loadBalancer Сервісу. Наприклад:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 192.0.2.127

Трафік від зовнішнього балансувальника навантаження направляється на бекенд-Podʼи. Хмарний постачальник вирішує, як він балансує навантаження.

Для реалізації Сервісу з type: LoadBalancer, Kubernetes зазвичай починає з того, що вносить зміни, які еквівалентні вашим запитам на Сервіс type: NodePort. Компонент cloud-controller-manager потім налаштовує зовнішній балансувальник для пересилання трафіку на цей призначений порт вузла.

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

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

Вплив життєздатності вузла на трафік балансувальника навантаження

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

Балансувальники з мішаними типами протоколів

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

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

Feature gate MixedProtocolLBService (стандартно увімкнено для kube-apiserver з версії v1.24) дозволяє використовувати різні протоколи для Сервісів типу LoadBalancer, коли визначено більше одного порту.

Вимкнення виділення порту вузла для балансувальника навантаження

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

Ви можете вимкнути виділення порту вузла для Сервісу з type: LoadBalancer, встановивши поле spec.allocateLoadBalancerNodePorts в false. Це слід використовувати тільки для реалізацій балансувальників, які маршрутизують трафік безпосередньо до Podʼів, а не використовують порти вузла. Стандартно spec.allocateLoadBalancerNodePorts дорівнює true, і Сервіси типу LoadBalancer будуть продовжувати виділяти порти вузла. Якщо spec.allocateLoadBalancerNodePorts встановлено в false для існуючого Сервісу з виділеними портами вузла, ці порти вузла не будуть автоматично видалятися. Вам слід явно видалити запис nodePorts в кожному порту Сервісу для деалокації цих портів вузла.

Вказання класу реалізації балансувальника

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

Для Сервісу з type встановленим на LoadBalancer, поле .spec.loadBalancerClass дозволяє вам використовувати реалізацію балансувальника, відмінну від тієї, яку типово встановлено постачальником хмари.

Типово .spec.loadBalancerClass не встановлено, і Сервіс з LoadBalancer використовує реалізацію балансувальника що постачається в хмарі, якщо кластер налаштовано постачальником хмари за допомогою прапорця компоненту --cloud-provider. Якщо ви вказуєте .spec.loadBalancerClass, вважається, що реалізація балансувальника, яка відповідає вказаному класу, відстежує Сервіси. Будь-яка стандартн реалізація балансувальника (наприклад, та, яку надає постачальник хмари), ігнорує Сервіси, у яких встановлено це поле. spec.loadBalancerClass може бути встановлено тільки для Сервісу типу LoadBalancer. Після встановлення його не можна змінити. Значення spec.loadBalancerClass повинно бути ідентифікатором у формі мітки, з необовʼязковим префіксом, таким як "internal-vip" або "example.com/internal-vip". Безпрефіксні імена зарезервовані для кінцевих користувачів.

Вказання IPMode для стану балансувальника

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

Як бета-функція в Kubernetes 1.30, feature gate з іменем LoadBalancerIPMode дозволяє встановлювати значення .status.loadBalancer.ingress.ipMode для Сервісу з type встановленим у LoadBalancer. .status.loadBalancer.ingress.ipMode вказує, як веде себе IP-адреса балансувальника. Воно може бути вказано лише тоді, коли вказано поле .status.loadBalancer.ingress.ip.

Є два можливі значення для .status.loadBalancer.ingress.ipMode: "VIP" та "Proxy".Типово встановлене значення "VIP", що означає, що трафік подається на вузол з призначенням, встановленим на IP та порт балансувальника. Є два випадки, коли встановлено значення "Proxy", залежно від того, як постачальник хмари балансує трафік:

  • Якщо трафік подається на вузол, а потім перенаправляється до Podʼа, призначення буде встановлено на IP та порт вузла;
  • Якщо трафік подається безпосередньо до Podʼа, призначення буде встановлено на IP та порт Podʼа.

Реалізації Сервісів можуть використовувати цю інформацію для налаштування маршрутизації трафіку.

Внутрішній балансувальник

У змішаному середовищі іноді необхідно направляти трафік від Сервісів всередині того ж (віртуального) мережевого блоку.

У середовищі DNS із подвійним горизонтом вам може знадобитися два Сервіси для маршрутизації зовнішнього і внутрішнього трафіку до ваших ендпоінтів.

Щоб встановити внутрішній балансувальник, додайте одну з наступних анотацій до Сервісу в залежності від постачальника хмари, який ви використовуєте:

Виберіть одну з вкладок.

metadata:
  name: my-service
  annotations:
      networking.gke.io/load-balancer-type: "Internal"

metadata:
    name: my-service
    annotations:
        service.beta.kubernetes.io/aws-load-balancer-internal: "true"

metadata:
  name: my-service
  annotations:
      service.beta.kubernetes.io/azure-load-balancer-internal: "true"

metadata:
  name: my-service
  annotations:
      service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: "private"

metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/openstack-internal-load-balancer: "true"

metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/cce-load-balancer-internal-vpc: "true"

metadata:
  annotations:
    service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxx

metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet"

metadata:
  name: my-service
  annotations:
      service.beta.kubernetes.io/oci-load-balancer-internal: true

type: ExternalName

Сервіси типу ExternalName звʼязують Сервіс з DNS-іменем, а не на типовим селектором, таким як my-service або cassandra. Ви вказуєте ці Сервіси параметром spec.externalName.

Наприклад, це визначення Сервісу звʼязує Сервіс my-service в просторі імен prod з my.database.example.com:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

При пошуку хоста my-service.prod.svc.cluster.local, DNS-сервіс кластера повертає запис CNAME із значенням my.database.example.com. Доступ до my-service працює так само, як і для інших Сервісів, але з важливою різницею в тому, що перенаправлення відбувається на рівні DNS, а не через проксі або переадресацію. Якщо ви пізніше вирішите перемістити свою базу даних в кластер, ви можете запустити його Podʼи, додати відповідні селектори чи endpointʼи та змінити тип Сервісу.

Headless Services

Іноді вам не потрібен балансувальник навантаження та одна IP-адреса Сервісу. У цьому випадку ви можете створити так звані headless Services, якщо явно вказати "None" для IP-адреси кластера (.spec.clusterIP).

Ви можете використовувати headless Сервіс для взаємодії з іншими механізмами виявлення служб, не будучи привʼязаним до реалізації Kubernetes.

Для headless Сервісів кластерна IP-адреса не видається, kube-proxy не обслуговує ці Сервіси, і для них платформа не виконує балансування навантаження чи проксіюваня.

Headless Сервіси дозволяють клієнту приєднуватись до будь-якого Pod безпосередньо. Ці Сервіси не встановлюють маршрути та перенаправлення пакетів з використанням віртуальних IP-адрес та проксі; натомість вони повідомляють про IP-адреси точок доступу окремих Podʼів через внутрішні записи DNS, які обслуговуються службою DNS кластера. Для визначення headless Сервіса вам потрібно створити Service з .spec.type встановленим на ClusterIP (що також є типовим значенням) та .spec.clusterIP встановленим у None.

Рядкове значення None є спеціальним випадком та не є тотожноми тому, якщо поле .spec.clusterIP не вказане.

Те, як автоматично налаштовано DNS, залежить від того, чи визначені селектори Сервісу:

З селекторами

Для headless Сервісів, які визначають селектори, контролер endpointʼів створює обʼєкти EndpointSlice в Kubernetes API та змінює конфігурацію DNS так, щоб повертати записи A або AAAA (IPv4 або IPv6 адреси), які напрямую вказують на Podʼи, які підтримують Сервіс.

Без селекторів

Для headless Сервісів, які не визначають селектори, панель управління не створює обʼєкти EndpointSlice. Проте система DNS шукає та налаштовує або:

  • DNS-записи CNAME для Сервісів з type: ExternalName.
  • DNS-записи A / AAAA для всіх IP-адрес Сервісу з готовими endpointʼами, для всіх типів Сервісів, крім ExternalName.
    • Для IPv4 endpointʼів система DNS створює A-записи.
    • Для IPv6 endpointʼів система DNS створює AAAA-записи.

Коли ви визначаєте headless Сервіс без селектора, поле port повинно відповідати полю targetPort.

Виявлення сервісів

Для клієнтів, що працюють всередині вашого кластера, Kubernetes підтримує два основних способи виявлення Сервісу: змінні середовища та DNS.

Змінні середовища

Коли Pod запускається на вузлі, kubelet додає набір змінних середовища для кожного активного Сервісу. Додаються змінні середовища {SVCNAME}_SERVICE_HOST та {SVCNAME}_SERVICE_PORT, де імʼя Сервісу перетворюється у верхній регістр, а тире конвертуються у підкреслення.

Наприклад, Сервіс redis-primary, який використовує TCP-порт 6379 та має присвоєну IP-адресу кластера 10.0.0.11, створює наступні змінні середовища:

REDIS_PRIMARY_SERVICE_HOST=10.0.0.11
REDIS_PRIMARY_SERVICE_PORT=6379
REDIS_PRIMARY_PORT=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP_PROTO=tcp
REDIS_PRIMARY_PORT_6379_TCP_PORT=6379
REDIS_PRIMARY_PORT_6379_TCP_ADDR=10.0.0.11

Kubernetes також підтримує та надає змінні, які сумісні з "legacy container links" Docker Engine. Ви можете переглянути makeLinkVariables щоб побачити, як це реалізовано в Kubernetes.

DNS

Ви можете (і майже завжди повинні) налаштувати службу DNS для вашого кластера Kubernetes, використовуючи надбудову.

Сервер DNS, знається на кластерах, такий як CoreDNS, стежить за Kubernetes API для виявлення нових Сервісів і створює набір DNS-записів для кожного з них. Якщо DNS увімкнено в усьому кластері, то всі Podʼи повинні автоматично мати можливість знаходити Сервіси за їхнім DNS-імʼям.

Наприклад, якщо у вас є Сервіс з назвою my-service в просторі імен Kubernetes my-ns, то разом панель управління та служба DNS створюють DNS-запис для my-service.my-ns. Podʼи в просторі імен my-ns повинні мати можливість знаходити Сервіс, роблячи запит за іменем my-service (my-service.my-ns також працюватиме).

Podʼи в інших просторах імен повинні вказати імʼя як my-service.my-ns. Ці імена будуть розповсюджуватись на призначений кластером IP для Сервісу.

Kubernetes також підтримує DNS SRV (Service) записи для іменованих портів. Якщо Сервіс my-service.my-ns має порт з іменем http і протоколом, встановленим в TCP, ви можете виконати DNS SRV-запит для _http._tcp.my-service.my-ns, щоб дізнатися номер порту для http, а також IP-адресу.

Сервер DNS Kubernetes — єдиний спосіб доступу до Сервісів ExternalName. Ви можете знайти більше інформації про вирішення ExternalName в DNS для Сервісів та Podʼів.

Механізм віртуальних IP-адрес

Прочитайте Віртуальні IP-адреси та сервісні проксі, що пояснює механізм, який Kubernetes надає для експозиції Сервісу з віртуальною IP-адресою.

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

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

Дивіться Політики трафіку для отримання докладнішої інформації.

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

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

Поле .spec.trafficDistribution надає ще один спосіб впливу на маршрутизацію трафіку в межах Сервісу Kubernetes. Хоча політика трафіку зосереджується на строгих семантичних гарантіях, розподіл трафіку дозволяє виражати уподобання (наприклад, маршрутизацію до топологічно ближчих точок доступу). Це може допомогти оптимізувати продуктивність, вартість або надійність. Це необовʼязкове поле можна використовувати, якщо ви ввімкнули feature gate ServiceTrafficDistribution для вашого кластера та всіх його вузлів. У Kubernetes 1.30, підтримується таке значення поля:

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

Якщо поле не встановлено, реалізація застосує свою стандартну стратегію маршрутизації.

Дивіться Розподіл трафіку для отримання додаткової інформації.

Збереження сесії

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

Зовнішні IP

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

При визначенні Сервісу ви можете вказати externalIPs для будь-якого типу сервісу. У наведеному нижче прикладі Сервіс з іменем "my-service" може отримати доступ від клієнтів за допомогою TCP за адресою "198.51.100.32:80" (розраховано із .spec.externalIPs[] та .spec.ports[].port).

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 49152
  externalIPs:
    - 198.51.100.32

API Обʼєкт

Сервіс — це ресурс верхнього рівня в Kubernetes REST API. Ви можете знайти більше деталей про обʼєкт API Service.

Що далі

Дізнайтеся більше про Сервіси та те, як вони вписуються в Kubernetes:

  • Дізнайтесь про Підключення застосунків за допомогою Service уроку.
  • Прочитайте про Ingress, який експонує маршрути HTTP та HTTPS ззовні кластера до Сервісів всередині вашого кластера.
  • Прочитайте про Gateway, розширення для Kubernetes, яке надає більше гнучкості, ніж Ingress.

Для отримання додаткового контексту прочитайте наступне:

2 - Ingress

Робить вашу мережеву службу HTTP (або HTTPS) доступною за допомогою конфігурації, яка розуміє протокол та враховує вебконцепції, такі як URI, імена хостів, шляхи та інше. Концепція Ingress дозволяє вам направляти трафік на різні бекенди на основі правил, які ви визначаєте через API Kubernetes.

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

Обʼєкт API, який управляє зовнішнім доступом до служб в кластері, зазвичай HTTP.

Ingress може надавати балансування навантаження, розшифровування SSL-трафіку та віртуальний хостинг на основі імен.

Термінологія

Для ясності цей посібник визначає наступні терміни:

  • Вузол: Робоча машина в Kubernetes, що є частиною кластера.
  • Кластер: Набір вузлів, на яких виконуються контейнеризовані застосунки, керовані Kubernetes. У прикладі та в більшості типових розгортань Kubernetes вузли кластера не є частиною відкритої мережі Інтернет.
  • Edge маршрутизатор: Маршрутизатор, який застосовує політику брандмауера для вашого кластера. Це може бути шлюз, керований хмарним постачальником, або фізичний пристрій.
  • Кластерна мережа: Набір зʼєднань, логічних або фізичних, які сприяють комунікації в межах кластера згідно з мережевою моделлю Kubernetes.
  • Service: Service Kubernetes, що ідентифікує набір Podʼів за допомогою селекторів label. Якщо не вказано інше, припускається, що служби мають віртуальні IP-адреси, які можна маршрутизувати лише в межах кластерної мережі.

Що таке Ingress?

Ingress відкриває маршрути HTTP та HTTPS із зовні кластера до Services всередині кластера. Маршрутизацію трафіку контролюють правила, визначені в ресурсі Ingress.

Ось простий приклад, де Ingress спрямовує весь свій трафік на один Service:

graph LR; client([клієнт])-. Балансувальник навантаження
яким керує Ingress .->ingress[Ingress]; ingress-->|правила
маршрутизації|service[Service]; subgraph cluster["Кластер"] ingress; service-->pod1[Pod]; service-->pod2[Pod]; 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 ingress,service,pod1,pod2 k8s; class client plain; class cluster cluster;
Схема. Ingress

Ingress може бути налаштований таким чином, щоб надавати Service зовнішньодоступні URL, балансувати трафік, термінувати SSL/TLS та пропонувати іменований віртуальний хостинг. Контролер Ingress відповідає за виконання Ingress, зазвичай з допомогою балансувальника навантаження, хоча він також може конфігурувати ваш edge маршрутизатор або додаткові фронтенди для допомоги в обробці трафіку.

Ingress не відкриває довільні порти або протоколи. Для експозиції служб, відмінних від HTTP та HTTPS, в Інтернет зазвичай використовується служба типу Service.Type=NodePort або Service.Type=LoadBalancer.

Передумови

Вам потрібно мати контролер Ingress, щоб виконувати Ingress. Лише створення ресурсу Ingress не має ефекту.

Можливо, вам доведеться розгорнути контролер Ingress, такий як ingress-nginx. Ви можете вибрати з-поміж контролерів Ingress.

В ідеалі, всі контролери Ingress повинні відповідати вказаній специфікації. На практиці різні контролери Ingress працюють трошки по-різному.

Ресурс Ingress

Мінімальний приклад ресурсу Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80

Для Ingress необхідні поля apiVersion, kind, metadata та spec. Назва обʼєкта Ingress повинна бути дійсним DNS-піддоменом. Для загальної інформації щодо роботи з файлами конфігурації дивіться розгортання застосунків, налаштування контейнерів, управління ресурсами. Ingress часто використовує анотації для налаштування деяких параметрів залежно від контролера Ingress, прикладом чого є анотація для перезапису. Різні контролери Ingress підтримують різні анотації. Ознайомтеся з документацією контролера Ingress, який ви вибрали, щоб дізнатися, які анотації підтримуються.

У специфікації Ingress міститься вся інформація, необхідна для налаштування балансувальника навантаження чи проксі-сервера. Важливою є наявність списку правил, які порівнюються з усіма вхідними запитами. Ресурс Ingress підтримує правила тільки для направлення трафіку HTTP(S).

Якщо ingressClassName відсутній, має бути визначений типовий клас Ingress.

Є контролери Ingress, які працюють без визначення типового IngressClass. Наприклад, контролер Ingress-NGINX може бути налаштований за допомогою прапора --watch-ingress-without-class. З усім тим, рекомендується вказати типовий IngressClass, як показано нижче.

Правила Ingress

Кожне правило HTTP містить наступну інформацію:

  • Необовʼязковий хост. У цьому прикладі хост не вказаний, тому правило застосовується до всього вхідного HTTP-трафіку через вказану IP-адресу. Якщо вказано хост (наприклад, foo.bar.com), правила застосовуються до цього хосту.
  • Список шляхів (наприклад, /testpath), кожен з яких має повʼязаний бекенд, визначений ім'ям service.name та service.port.name або service.port.number. Як хост, так і шлях повинні відповідати вмісту вхідного запиту, перш ніж балансувальник навантаження направить трафік до зазначеного Service.
  • Бекенд — це комбінація імені Service та порту, як описано в документації Service або ресурсом бекенду користувача за допомогою CRD. HTTP (та HTTPS) запити до Ingress, які відповідають хосту та шляху правила, надсилаються до вказаного бекенду.

Зазвичай в Ingress контролері налаштований defaultBackend, який обслуговує будь-які запити, які не відповідають шляху в специфікації.

DefaultBackend

Ingress без правил спрямовує весь трафік до єдиного стандартного бекенду, і .spec.defaultBackend — це бекенд, який повинен обробляти запити в цьому випадку. Зазвичай defaultBackend — це опція конфігурації контролера Ingress і не вказується в ресурсах вашого Ingress. Якщо не вказано .spec.rules, то повинен бути вказаний .spec.defaultBackend. Якщо defaultBackend не встановлено, обробка запитів, які не відповідають жодному з правил, буде покладена на контролер ingress (звертайтеся до документації свого контролера Ingress, щоб дізнатися, як він обробляє цей випадок).

Якщо жоден із хостів або шляхів не відповідає HTTP-запиту в обʼєктах Ingress, трафік направляється до вашого стандартного бекенду.

Бекенд Resource

Бекенд Resource — це ObjectRef на інший ресурс Kubernetes всередині того ж простору імен, що й обʼєкт Ingress. Resource — є несумісним з Service, перевірка налаштувань виявить помилку, якщо вказані обидва. Звичайне використання для бекенду Resource — це направлення даних в обʼєкт зберігання зі статичними ресурсами.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-resource-backend
spec:
  defaultBackend:
    resource:
      apiGroup: k8s.example.com
      kind: StorageBucket
      name: static-assets
  rules:
    - http:
        paths:
          - path: /icons
            pathType: ImplementationSpecific
            backend:
              resource:
                apiGroup: k8s.example.com
                kind: StorageBucket
                name: icon-assets

Після створення Ingress вище, ви можете переглянути його за допомогою наступної команди:

kubectl describe ingress ingress-resource-backend
Name:             ingress-resource-backend
Namespace:        default
Address:
Default backend:  APIGroup: k8s.example.com, Kind: StorageBucket, Name: static-assets
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /icons   APIGroup: k8s.example.com, Kind: StorageBucket, Name: icon-assets
Annotations:  <none>
Events:       <none>

Типи шляхів

Для кожного шляху в Ingress обовʼязково повинен бути відповідний тип шляху. Шляхи, які не включають явний pathType, не пройдуть валідацію. Існує три типи шляхів, що підтримуються:

  • ImplementationSpecific: З цим типом шляху визначення відповідності залежить від IngressClass. Реалізації можуть розглядати це як окремий pathType або обробляти його так само як типи шляхів Prefix або Exact.

  • Exact: Відповідає URL-шляху точно і з урахуванням регістрів.

  • Prefix: Відповідає на основі префіксу URL-шляху, розділеному /. Відповідність визначається з урахуванням регістру і виконується поелементно за кожним елементом шляху. Елемент шляху вказує на список міток у шляху, розділених роздільником /. Запит відповідає шляху p, якщо кожен p є префіксом елемента p запиту.

Приклади

ТипШлях(и)Шлях запитуВідповідає?
Префікс/(всі шляхи)Так
Точний/foo/fooТак
Точний/foo/barНі
Точний/foo/foo/Ні
Точний/foo//fooНі
Префікс/foo/foo, /foo/Так
Префікс/foo//foo, /foo/Так
Префікс/aaa/bb/aaa/bbbНі
Префікс/aaa/bbb/aaa/bbbТак
Префікс/aaa/bbb//aaa/bbbТак, ігнорує кінцевий слеш
Префікс/aaa/bbb/aaa/bbb/Так, співпадає з кінцевим слешем
Префікс/aaa/bbb/aaa/bbb/cccТак, співпадає з підшляхом
Префікс/aaa/bbb/aaa/bbbxyzНі, не співпадає з префіксом рядка
Префікс/, /aaa/aaa/cccТак, співпадає з префіксом /aaa
Префікс/, /aaa, /aaa/bbb/aaa/bbbТак, співпадає з префіксом /aaa/bbb
Префікс/, /aaa, /aaa/bbb/cccТак, співпадає з префіксом /
Префікс/aaa/cccНі, використовується типовий backend
Змішаний/foo (Префікс), /foo (Точний)/fooТак, віддає перевагу Точному

Декілька збігів

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

Шаблони імен хостів

Хости можуть бути точними збігами (наприклад, "foo.bar.com") або містити шаблони (наприклад, "*.foo.com"). Точні збіги вимагають, щоб заголовок HTTP host відповідав полю host. Шаблони вимагають, щоб заголовок HTTP host був рівним суфіксу правила з символами підстановки.

ХостЗаголовок хостаЗбіг?
*.foo.combar.foo.comЗбіг на основі спільного суфіксу
*.foo.combaz.bar.foo.comНемає збігу, символ підстановки охоплює лише одну DNS-мітку
*.foo.comfoo.comНемає збігу, символ підстановки охоплює лише одну DNS-мітку
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
              number: 80

Клас Ingress

Ingressʼи можуть бути реалізовані різними контролерами, часто з різною конфігурацією. Кожен Ingress повинен вказати клас — посилання на ресурс IngressClass, який містить додаткову конфігурацію, включаючи імʼя контролера, який повинен реалізувати цей клас.

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb
spec:
  controller: example.com/ingress-controller
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: external-lb

Поле .spec.parameters класу IngressClass дозволяє посилатися на інший ресурс, який надає конфігурацію, повʼязану з цим класом IngressClass.

Конкретний тип параметрів для використання залежить від контролера Ingress, який ви вказуєте в полі .spec.controller IngressClass.

Область застосування IngressClass

Залежно від вашого контролера Ingress, ви можете використовувати параметри, які ви встановлюєте на рівні кластера, або лише для одного простору імен.

Стандартна область застосування параметрів IngressClass — це весь кластер.

Якщо ви встановлюєте поле .spec.parameters і не встановлюєте .spec.parameters.scope, або ви встановлюєте .spec.parameters.scope на Cluster, тоді IngressClass посилається на ресурс, який є на рівні кластера. kind (в поєднанні з apiGroup) параметрів вказує на API на рівні кластера (можливо, власний ресурс), і name параметрів ідентифікує конкретний ресурс на рівні кластера для цього API.

Наприклад:

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-1
spec:
  controller: example.com/ingress-controller
  parameters:
    # Параметри для цього IngressClass вказані в ClusterIngressParameter
    # (API group k8s.example.net) імені "external-config-1".
    # Це визначення вказує Kubernetes шукати ресурс параметрів на рівні кластера.
    scope: Cluster
    apiGroup: k8s.example.net
    kind: ClusterIngressParameter
    name: external-config-1

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

Якщо ви встановлюєте поле .spec.parameters і встановлюєте .spec.parameters.scope на Namespace, тоді IngressClass посилається на ресурс на рівні простору імен. Ви також повинні встановити поле namespace в межах .spec.parameters на простір імен, який містить параметри, які ви хочете використовувати.

kind (в поєднанні з apiGroup) параметрів вказує на API на рівні простору імен (наприклад: ConfigMap), і name параметрів ідентифікує конкретний ресурс у просторі імен, який ви вказали в namespace.

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

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

Сам API IngressClass завжди має область застосування на рівні кластера.

Ось приклад IngressClass, який посилається на параметри на рівні простору імен:

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-2
spec:
  controller: example.com/ingress-controller
  parameters:
    # Параметри для цього IngressClass вказані в IngressParameter
    # (API group k8s.example.com) імені "external-config",
    # що знаходиться в просторі імен "external-configuration".
    scope: Namespace
    apiGroup: k8s.example.com
    kind: IngressParameter
    namespace: external-configuration
    name: external-config

Застарілі анотації

Перед тим, як в Kubernetes 1.18 були додані ресурс IngressClass та поле ingressClassName, класи Ingress вказувалися за допомогою анотації kubernetes.io/ingress.class в Ingress. Ця анотація ніколи не була формально визначена, але отримала широку підтримку контролерами Ingress.

Нове поле ingressClassName в Ingress — це заміна для цієї анотації, але не є прямим еквівалентом. Хоча анотація, як правило, використовувалася для посилання на імʼя контролера Ingress, який повинен реалізувати Ingress, поле є посиланням на ресурс IngressClass, який містить додаткову конфігурацію Ingress, включаючи імʼя контролера Ingress.

Стандартний IngressClass

Ви можете визначити певний IngressClass як стандартний для вашого кластера. Встановлення анотації ingressclass.kubernetes.io/is-default-class зі значенням true на ресурсі IngressClass забезпечить те, що новим Ingress буде призначений цей типовий IngressClass, якщо в них не вказано поле ingressClassName.

Є контролери Ingress, які працюють без визначення типового IngressClass. Наприклад, контролер Ingress-NGINX може бути налаштований з прапорцем --watch-ingress-without-class. Однак рекомендується визначати типовий IngressClass явно:

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  labels:
    app.kubernetes.io/component: controller
  name: nginx-example
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
spec:
  controller: k8s.io/ingress-nginx

Типи Ingress

Ingress з підтримкою одного Service

Існують концепції в Kubernetes, що дозволяють вам використовувати один Service (див. альтернативи). Ви також можете зробити це за допомогою Ingress, вказавши стандартний бекенд без правил.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  defaultBackend:
    service:
      name: test
      port:
        number: 80

Якщо ви створите його за допомогою kubectl apply -f, ви повинні мати можливість переглядати стан доданого Ingress:

kubectl get ingress test-ingress
NAME           CLASS         HOSTS   ADDRESS         PORTS   AGE
test-ingress   external-lb   *       203.0.113.123   80      59s

Де 203.0.113.123 — це IP-адреса, яку надав контролер Ingress для виконання цього Ingress.

Простий розподіл

Конфігурація розподілу дозволяє маршрутизувати трафік з одної IP-адреси до більше ніж одного сервісу, виходячи з HTTP URI, що запитується. Ingress дозволяє зберігати кількість балансувальників на мінімальному рівні. Наприклад, налаштування як:

graph LR; client([клієнт])-. Балансувальник навантаження
яким керує Ingress .->ingress[Ingress, 178.91.123.132]; ingress-->|/foo|service1[Service service1:4200]; ingress-->|/bar|service2[Service service2:8080]; subgraph cluster["Кластер"] ingress; service1-->pod1[Pod]; service1-->pod2[Pod]; service2-->pod3[Pod]; service2-->pod4[Pod]; 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 ingress,service1,service2,pod1,pod2,pod3,pod4 k8s; class client plain; class cluster cluster;
Схема. Ingress Fan Out

Для цього потрібно мати Ingress, наприклад:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 4200
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 8080

Коли ви створюєте Ingress за допомогою kubectl apply -f:

kubectl describe ingress simple-fanout-example
Name:             simple-fanout-example
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:4200 (10.8.0.90:4200)
               /bar   service2:8080 (10.8.0.91:8080)
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     22s                loadbalancer-controller  default/test

Контролер Ingress надає реалізаційно-специфічний балансувальник що влаштовує Ingress, за умови, що існують сервіси (service1, service2). Коли це сталося, ви можете побачити адресу балансувальника в полі Address.

Віртуальний хостинг на основі імен

Віртуальні хости на основі імен підтримують маршрутизацію HTTP-трафіку до кількох імен хостів за однією IP-адресою.

graph LR; client([клієнт])-. Балансувальник навантаження
яким керує Ingress .->ingress[Ingress, 178.91.123.132]; ingress-->|Host: foo.bar.com|service1[Service service1:80]; ingress-->|Host: bar.foo.com|service2[Service service2:80]; subgraph cluster["Кластер"] ingress; service1-->pod1[Pod]; service1-->pod2[Pod]; service2-->pod3[Pod]; service2-->pod4[Pod]; 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 ingress,service1,service2,pod1,pod2,pod3,pod4 k8s; class client plain; class cluster cluster;
Схема. Ingress віртуального хостингу на основі імен

Наступний Ingress вказує балансувальнику направляти запити на основі заголовка Host.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: bar.foo.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

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

Наприклад, наступний Ingress маршрутизує трафік спрямований для first.bar.com до service1, second.bar.com до service2, і будь-який трафік, який має заголовок запиту хоста, який не відповідає first.bar.com і second.bar.com до service3.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress-no-third-host
spec:
  rules:
  - host: first.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: second.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80
  - http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service3
            port:
              number: 80

TLS

Ви можете захистити Ingress, вказавши Secret, що містить приватний ключ TLS та сертифікат. Ресурс Ingress підтримує лише один TLS-порт, 443, та передбачає термінування TLS на точці входу (трафік до Service та його Podʼів передається у вигляді звичайного тексту). Якщо розділ конфігурації TLS в Ingress вказує різні хости, вони мультиплексуються на одному порту відповідно до імені хоста, вказаного через розширення TLS з SNI (за умови, що контролер Ingress підтримує SNI). TLS-секрет повинен містити ключі з іменами tls.crt та tls.key, які містять сертифікат та приватний ключ для використання TLS. Наприклад:

apiVersion: v1
kind: Secret
metadata:
  name: testsecret-tls
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: kubernetes.io/tls

Посилання на цей секрет в Ingress дозволяє контролеру Ingress захистити канал, що йде від клієнта до балансувальника навантаження за допомогою TLS. Вам потрібно переконатися, що TLS-секрет, який ви створили, містить сертифікат, який містить Common Name (CN), також Fully Qualified Domain Name (FQDN) для https-example.foo.com.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example-ingress
spec:
  tls:
  - hosts:
      - https-example.foo.com
    secretName: testsecret-tls
  rules:
  - host: https-example.foo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80

Балансування навантаження

Контролер Ingress створюється з певними параметрами політики балансування навантаження, які він застосовує до всіх Ingress, таких як алгоритм балансування навантаження, схема коефіцієнтів ваги бекенду та інші. Більш розширені концепції балансування навантаження (наприклад, постійні сесії, динамічні коефіцієнти ваги) наразі не експонуються через Ingress. Замість цього ви можете отримати ці функції через балансувальник, що використовується для Service.

Також варто зазначити, що навіть якщо перевірки стану не експоновані безпосередньо через Ingress, існують паралельні концепції в Kubernetes, такі як перевірки готовності, що дозволяють досягти того ж самого результату. Будь ласка, ознайомтеся з документацією конкретного контролера, щоб переглянути, як вони обробляють перевірки стану (наприклад: nginx або GCE).

Оновлення Ingress

Щоб оновити існуючий Ingress і додати новий хост, ви можете відредагувати ресурс таким чином:

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     35s                loadbalancer-controller  default/test
kubectl edit ingress test

Це відкриє редактор з поточною конфігурацією у форматі YAML. Змініть її, щоб додати новий хост:

spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          service:
            name: service1
            port:
              number: 80
        path: /foo
        pathType: Prefix
  - host: bar.baz.com
    http:
      paths:
      - backend:
          service:
            name: service2
            port:
              number: 80
        path: /foo
        pathType: Prefix
..

Після збереження змін, kubectl оновлює ресурс у API-сервері, що повідомляє Ingress-контролеру переконфігурувати балансувальник.

Перевірте це:

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
  bar.baz.com
               /foo   service2:80 (10.8.0.91:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     45s                loadbalancer-controller  default/test

Ви можете досягти того самого результату, викликавши kubectl replace -f із зміненим файлом YAML для Ingress.

Збій у різних зонах доступності

Методи розподілу трафіку між доменами відмови відрізняються між хмарними провайдерами. Будь ласка, перевірте документацію відповідного контролера Ingress для отримання деталей.

Альтернативи

Ви можете використовувати різні способи надання доступу до Service, які безпосередньо не стосуються ресурсу Ingress:

Що далі

3 - Контролери Ingress

Для того, щоб ресурс Ingress працював у вашому кластері, повинен бути запущений контролер Ingress. Вам потрібно вибрати принаймні один контролер Ingress та переконатися, що він налаштований у вашому кластері. На цій сторінці перелічені поширені контролери Ingress, які ви можете встановити.

Для того, щоб ресурс Ingress працював, у кластері повинен бути запущений контролер Ingress.

На відміну від інших типів контролерів, які працюють як частина бінарного файлу kube-controller-manager, контролери Ingress не запускаються автоматично разом з кластером. Використовуйте цю сторінку, щоб вибрати реалізацію контролера Ingress, яка найкраще підходить для вашого кластера.

Проєкт Kubernetes підтримує контролери Ingress для AWS, GCE та nginx.

Додаткові контролери

  • AKS Application Gateway Ingress Controller — це контролер Ingress, який налаштовує Azure Application Gateway.
  • Alibaba Cloud MSE Ingress — це контролер Ingress, який налаштовує Alibaba Cloud Native Gateway, який також є комерційною версією Higress.
  • Apache APISIX Ingress Controller — це контролер Ingress, заснований на Apache APISIX.
  • Avi Kubernetes Operator забезпечує балансування навантаження рівня 4-7, використовуючи VMware NSX Advanced Load Balancer.
  • BFE Ingress Controller — це контролер Ingress, заснований на BFE.
  • Cilium Ingress Controller — це контролер Ingress, який працює на основі Cilium.
  • Контролер Ingress Citrix співпрацює з контролером доставки програм Citrix.
  • Contour — це контролер Ingress на основі Envoy.
  • Emissary-Ingress API Gateway — це контролер Ingress на основі Envoy.
  • EnRoute — це шлюз API на основі Envoy, який може працювати як контролер Ingress.
  • Easegress IngressController — це шлюз API на основі Easegress, який може працювати як контролер Ingress.
  • F5 BIG-IP Container Ingress Services for Kubernetes дозволяє використовувати Ingress для конфігурації віртуальних серверів F5 BIG-IP.
  • FortiADC Ingress Controller підтримує ресурси Kubernetes Ingress та дозволяє керувати обʼєктами FortiADC з Kubernetes
  • Gloo — це відкритий контролер Ingress на основі Envoy, який пропонує функціональність воріт API.
  • HAProxy Ingress — це контролер Ingress для HAProxy.
  • Higress — це шлюз API на основі Envoy, який може працювати як контролер Ingress.
  • Контролер Ingress HAProxy для Kubernetes також є контролером Ingress для HAProxy.
  • Istio Ingress — це контролер Ingress на основі Istio.
  • Контролер Ingress Kong для Kubernetes — це контролер Ingress, який керує Kong Gateway.
  • Kusk Gateway — це контролер Ingress, орієнтований на OpenAPI, на основі Envoy.
  • Контролер Ingress NGINX для Kubernetes працює з вебсервером NGINX (як проксі).
  • ngrok Kubernetes Ingress Controller — це контролер Ingress з відкритим кодом для надання безпечного публічного доступу до ваших служб K8s за допомогою платформи ngrok.
  • Контролер Ingress OCI Native — це контролер Ingress для Oracle Cloud Infrastructure, який дозволяє керувати OCI Load Balancer.
  • OpenNJet Ingress Controller є ingress-контролером на основі OpenNJet.
  • Контролер Ingress Pomerium — це контролер Ingress на основі Pomerium, який пропонує політику доступу з урахуванням контексту.
  • Skipper — це HTTP-маршрутизатор та зворотний проксі для композиції служб, включаючи випадки використання, такі як Kubernetes Ingress, розроблений як бібліотека для побудови вашого власного проксі.
  • Контролер Ingress Traefik Kubernetes provider — це контролер Ingress для проксі Traefik.
  • Tyk Operator розширює Ingress за допомогою власних ресурсів для надання можливостей управління API Ingress. Tyk Operator працює з відкритими шлюзами Tyk та хмарною системою управління Tyk.
  • Voyager — це контролер Ingress для HAProxy.
  • Контролер Ingress Wallarm — це контролер Ingress, який надає можливості WAAP (WAF) та захисту API.

Використання кількох контролерів Ingress

Ви можете розгортати будь-яку кількість контролерів Ingress за допомогою класу Ingress у межах кластера. Зверніть увагу на значення .metadata.name вашого ресурсу класу Ingress. При створенні Ingress вам слід вказати це ім'я для визначення поля ingressClassName в обʼєкті Ingress (див. специфікацію IngressSpec v1). ingressClassName є заміною застарілого методу анотації.

Якщо ви не вказуєте IngressClass для Ingress, і у вашому кластері рівно один IngressClass відзначений як типовий, тоді Kubernetes застосовує типовий IngressClass кластера до Ingress. Ви вказуєте IngressClass як типовий, встановлюючи анотацію ingressclass.kubernetes.io/is-default-class для цього IngressClass, зі значенням "true".

В ідеалі, всі контролери Ingress повинні відповідати цій специфікації, але різні контролери Ingress працюють трошки по-різному.

Що далі

4 - Gateway API

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, для передачі трафіку з Gateway listener на мережеві точки доступу бекенду. Ці точки доступу часто представлені як Service.

Gateway API організовано за різними видами API, які мають взаємозалежні відносини для підтримки організаційно орієнтованої природи організацій. Обʼєкт Gateway повʼязаний із саме одним GatewayClass; GatewayClass описує контролер шлюзу, відповідального за керування шлюзами цього класу. Один чи кілька видів маршрутів, таких як HTTPRoute, потім повʼязуються з Gateways. Gateway може фільтрувати маршрути, які можуть бути прикріплені до його слухачів, утворюючи двоспрямовану довірчу модель з маршрутами.

Наступна схема ілюструє звʼязок між трьома стабільними видами 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

Шлюзи можуть бути реалізовані різними контролерами, часто з різними конфігураціями. Шлюз має посилатися на GatewayClass, який містить імʼя контролера, що реалізує цей клас.

Мінімальний приклад GatewayClass:

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: example-class
spec:
  controllerName: example.com/gateway-controller

У цьому прикладі контролер, який реалізував Gateway API, налаштований для управління GatewayClasses з іменем контролера example.com/gateway-controller. Шлюзи цього класу будуть керуватися контролером реалізації.

Дивіться специфікацію GatewayClass для повного визначення цього виду API.

Gateway

Gateway описує екземпляр інфраструктури обробки трафіку. Він визначає мережеву точку доступу з використанням якої можна обробляти трафік, тобто фільтрувати, балансувати, розділяти тощо для таких бекендів як Service. Наприклад, шлюз може представляти хмарний балансувальник навантаження або внутрішній проксі-сервер, налаштований для отримання HTTP-трафіку.

Мінімальний приклад ресурсу Gateway:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: example-gateway
spec:
  gatewayClassName: example-class
  listeners:
  - name: http
    protocol: HTTP
    port: 80

У цьому прикладі екземпляр інфраструктури обробки трафіку програмується на прослуховування HTTP-трафіку на порту 80. Оскільки поле addresses не вказано, адреса чи імʼя хосту надається Gateway контролером реалізації. Ця адреса використовується як мережева точка доступу для обробки трафіку бекенду, визначеного в маршрутах.

Дивіться специфікацію Gateway для повного визначення цього виду API.

HTTPRoute

Вид HTTPRoute визначає поведінку маршрутизації HTTP-запитів від слухача Gateway до бекенду мережевих точок доступу. Для бекенду Service реалізація може представляти мережеву точку доступу як IP-адресу Service чи поточні Endpointʼи Service. HTTPRoute представляє конфігурацію, яка застосовується до внутрішньої реалізації Gateway. Наприклад, визначення нового HTTPRoute може призвести до налаштування додаткових маршрутів трафіку в хмарному балансувальнику або внутрішньому проксі-сервері.

Мінімальний приклад HTTPRoute:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example-httproute
spec:
  parentRefs:
  - name: example-gateway
  hostnames:
  - "www.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /login
    backendRefs:
    - name: example-svc
      port: 8080

У цьому прикладі HTTP-трафік від Gateway example-gateway із заголовком Host: www.example.com та вказаним шляхом запиту /login буде направлений до Service example-svc на порт 8080.

Дивіться специфікацію HTTPRoute для повного визначення цього виду API.

Потік запитів

Ось простий приклад маршрутизації HTTP-трафіку до Service за допомогою Gateway та HTTPRoute:

graph LR; client([клієнт])-. HTTP
запит .->Gateway; Gateway-->HTTPRoute; HTTPRoute-->|Правила
маршрутизації|Service; Service-->pod1[Pod]; Service-->pod2[Pod]; 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 Gateway,HTTPRoute,Service,pod1,pod2 k8s; class client plain; class cluster cluster;

У цьому прикладі потік запиту для Gateway, реалізованого як зворотний проксі, є таким:

  1. Клієнт починає готувати HTTP-запит для URL http://www.example.com
  2. DNS-resolver клієнта запитує імʼя призначення та дізнається про звʼязок між однією чи кількома IP-адресами, повʼязаними з Gateway.
  3. Клієнт надсилає запит на IP-адресу Gateway; зворотній проксі отримує HTTP запит і використовує заголовок Host: заголовок має збігатись з налаштуваннями, які були отримані від Gateway та прикріпленого HTTPRoute. Опційно зворотній проксі може виконати порівняння заголовків або шляху запиту на основі правил відповідності HTTPRoute.
  4. Опційно зворотній проксі може змінювати запит; наприклад, додавати чи видаляти заголовки, відповідно до правил фільтрації HTTPRoute.
  5. Наприкінці зворотній проксі пересилає запит на один чи кілька бекендів.

Відповідність

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

Дивіться документацію щодо відповідності для розуміння деталей, таких як канали випусків, рівні підтримки та виконання тестів відповідності.

Міграція з Ingress

Gateway API є наступником Ingress API. Однак він не включає вид Ingress. Внаслідок цього необхідно провести одноразове перетворення з наявних ресурсів Ingress на ресурси Gateway API.

Дивіться посібник з міграції з Ingress для отримання деталей щодо міграції ресурсів Ingress на ресурси Gateway API.

Що далі

Замість того, щоб ресурси Gateway API були реалізовані нативно в Kubernetes, специфікації визначаються як Власні ресурси та підтримуються широким спектром реалізацій. Встановіть CRD Gateway API або виконайте інструкції щодо встановлення обраної реалізації. Після встановлення реалізації скористайтесь розділом Початок роботи для швидкого початку роботи з Gateway API.

Дивіться специфікацію API для отримання додаткових деталей про всі види API Gateway API.

5 - EndpointSlices

API EndpointSlice — це механізм, який Kubernetes використовує, щоб ваш Service масштабувався для обробки великої кількості бекендів і дозволяє кластеру ефективно оновлювати свій список справних бекендів.
СТАН ФУНКЦІОНАЛУ: Kubernetes v1.21 [stable]

EndpointSlice API Kubernetes надає можливість відстежувати мережеві точки доступу в межах кластера Kubernetes. EndpointSlices пропонують більш масштабований та розширюваний альтернативний варіант Endpoints.

EndpointSlice API

У Kubernetes, EndpointSlice містить посилання на набір мережевих точок доступу. Панель управління автоматично створює EndpointSlices для будь-якої служби Kubernetes, яка має вказаний селектор. Ці EndpointSlices містять посилання на всі Podʼи, які відповідають селектору Service. EndpointSlices групують мережеві точки доступу за унікальними комбінаціями протоколу, номеру порту та імені Service. Імʼя обʼєкта EndpointSlice повинно бути дійсним імʼям піддомену DNS.

Наприклад, ось приклад обʼєкта EndpointSlice, яким володіє Service Kubernetes з імʼям example.

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: example-abc
  labels:
    kubernetes.io/service-name: example
addressType: IPv4
ports:
  - name: http
    protocol: TCP
    port: 80
endpoints:
  - addresses:
      - "10.1.2.3"
    conditions:
      ready: true
    hostname: pod-1
    nodeName: node-1
    zone: us-west2-a

Типово, панель управління створює та керує EndpointSlices так, щоб в кожному з них було не більше 100 мережевих точок доступу. Це можна налаштувати за допомогою прапорця --max-endpoints-per-slice kube-controller-manager, до максимуму 1000.

EndpointSlices можуть виступати джерелом правди для kube-proxy щодо того, як маршрутизувати внутрішній трафік.

Типи адрес

EndpointSlices підтримують три типи адрес:

  • IPv4
  • IPv6
  • FQDN (Fully Qualified Domain Name — Повністю Кваліфіковане Доменне Імʼя)

Кожен обʼєкт EndpointSlice представляє конкретний тип IP-адреси. Якщо у вас є Service, який доступний через IPv4 та IPv6, буде принаймні два обʼєкти EndpointSlice (один для IPv4 та один для IPv6).

Стани

API EndpointSlice зберігає стани точок доступу, які можуть бути корисні для споживачів. Три стани: ready, serving та terminating.

Ready

ready — це стан, який відповідає стану Ready Pod. Запущений Pod зі станом Ready встановленим в True повинен мати стан ready також встановлений в true. З міркувань сумісності, ready НІКОЛИ не буває true, коли Pod видаляється. Споживачі повинні звертатися до стану serving, щоб перевірити готовність Podʼів, які видаляються. Єдиний виняток є для Services з spec.publishNotReadyAddresses, встановленим в true. Podʼи для цих служб завжди матимуть стан ready, встановлений в true.

Serving

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

Стан serving майже ідентичний стану ready. Різниця полягає в тому, що споживачі API EndpointSlice повинні перевіряти стан serving, якщо їм важливо перевірити готовність Podʼів в той час, коли Pod також примусово припиняє свою роботу.

Terminating

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

Terminating — це стан, що вказує, чи Pod видаляється. Для Podʼів це буде будь-який Pod з встановленою часовою міткою видалення.

Інформація про топологію

Кожна точка доступу в межах EndpointSlice може містити відповідну інформацію про топологію. Інформація про топологію включає місцезнаходження точки доступу та інформацію про відповідний вузол та зону. Ця інформація доступна в наступних полях на кожній кінцевій точці в EndpointSlices:

  • nodeName — Назва вузла, на якому знаходиться ця точка доступу.
  • zone — Зона, в якій знаходиться ця точка доступу.

Управління

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

Щоб забезпечити можливість кількох сутностей керувати EndpointSlices без взаємодії одна з одною, Kubernetes визначає label endpointslice.kubernetes.io/managed-by, яка вказує сутність, яка керує EndpointSlice. Контролер встановлює значення endpointslice-controller.k8s.io для цієї мітки на всіх точках доступу, якими він керує. Інші сутності, які керують EndpointSlices, також повинні встановити унікальне значення для цієї мітки.

Власність

У більшості випадків EndpointSlices належать Service, за яким обʼєкт EndpointSlices стежить для виявлення точок доступу. Право власності вказується власником посиланням на кожен EndpointSlice, а також міткою kubernetes.io/service-name для простого пошуку всіх EndpointSlices, які належать Service.

Віддзеркалення EndpointSlice

У деяких випадках застосунки створюють власні ресурси Endpoints. Щоб забезпечити що ці застосунки не повинні одночасно записувати як в ресурси Endpoints, так і в ресурси EndpointSlice, панель управління кластера віддзеркалює більшість ресурсів Endpoints на відповідні ресурси EndpointSlices.

Панель управління віддзеркалює ресурси Endpoints, якщо:

  • ресурс Endpoints має мітку endpointslice.kubernetes.io/skip-mirror встановлену в true.
  • ресурс Endpoints має анотацію control-plane.alpha.kubernetes.io/leader.
  • відповідний ресурс Service не існує.
  • відповідний ресурс Service має ненульовий селектор.

Окремі ресурси Endpoints можуть транслюватись в кілька ресурсів EndpointSlices. Це може відбуватись, якщо ресурс Endpoints має кілька підмножин або включає точки доступу з кількома сімействами IP (IPv4 та IPv6). Максимально 1000 адрес на підмножину буде віддзеркалено на EndpointSlices.

Розподіл EndpointSlices

Кожен EndpointSlice має набір портів, які застосовуються до всіх точок доступу ресурсу. При використанні іменованих портів для Service, Podʼи можуть мати різні номери цільового порту для того самого іменованого порту, що вимагає різних EndpointSlices. Це схоже на логіку того, як підмножини групуються з Endpoints.

Панель управління намагається заповнити EndpointSlices так повно, як це можливо, але не активно перерозподіляє їх. Логіка досить проста:

  1. Пройдіться по наявних EndpointSlices, вилучіть точки доступу, які вже не потрібні, і оновіть відповідні точки, які змінилися.
  2. Пройдіться по EndpointSlices, які були змінені на першому етапі, і заповніть їх будь-якими новими точками доступу, які потрібно додати.
  3. Якщо ще залишилися нові точки доступу для додавання, спробуйте додати їх в раніше не змінений EndpointSlice та/або створіть новий.

Важливо, що третій крок надає пріоритет обмеженню оновлень EndpointSlice над ідеально повним розподілом EndpointSlices. Наприклад, якщо є 10 нових точок доступу для додавання та 2 EndpointSlices з простором для ще 5 точок доступу кожна, цей підхід створить новий EndpointSlice замість заповнення 2 наявних EndpointSlices. Іншими словами, одне створення EndpointSlice краще, ніж кілька оновлень EndpointSlice.

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

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

Дублікати endpoints

Через характер змін EndpointSlice точки доступу можуть бути представлені в більш ніж одному EndpointSlice одночасно. Це, природно, відбувається, оскільки зміни до різних обʼєктів EndpointSlice можуть надходити до клієнта Kubernetes watch / cache в різний час.

Порівняння з Endpoints

Оригінальний API Endpoints надавав простий і зрозумілий спосіб відстеження мережевих точок доступу в Kubernetes. Однак з ростом кластерів Kubernetes та Serviceʼів, які обробляють більше трафіку і надсилають трафік до більшої кількості підзадач, обмеження оригінального API стали більш помітними. Зокрема, до них входили проблеми масштабування до більшої кількості мережевих точок доступу.

Оскільки всі мережеві точки доступу для Service зберігалися в одному ресурсі Endpoints, ці обʼєкти Endpoints могли бути досить великими. Для служб, які залишалися стабільними (тобто тим самим набором точок доступу протягом тривалого періоду часу), вплив був менше помітний; навіть тоді деякі випадки використання Kubernetes працювали не дуже добре.

Коли у Service було багато точок доступу бекенду, а робочі навантаження або часто масштабуються, або до них часто вносилися нові зміни, кожне оновлення єдиного обʼєкта Endpoints для цього Service означало багато трафіку між компонентами кластера Kubernetes (в межах панелі управління, а також між вузлами та сервером API). Цей додатковий трафік також мав вартість у термінах використання ЦП.

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

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

Що далі

6 - Мережеві політики

Якщо ви хочете контролювати потік трафіку на рівні IP-адреси чи порту (рівень OSI 3 або 4), мережеві політики Kubernetes дозволяють вам визначати правила потоку трафіку всередині вашого кластера, а також між Podʼами та зовнішнім світом. Ваш кластер повинен використовувати мережевий втулок, який підтримує NetworkPolicy.

Якщо ви хочете контролювати потік трафіку на рівні IP-адреси чи порту для протоколів TCP, UDP та SCTP, то вам, можливо, варто розглянути використання NetworkPolicies Kubernetes для конкретних застосунків у вашому кластері. NetworkPolicies — це конструкт, орієнтований на застосунок, який дозволяє вам визначати, як Pod може взаємодіяти з різними мережевими "сутностями" (ми використовуємо тут слово "сутність", щоб уникнути перевантаження більш загальноприйнятими термінами, такими як "Endpoints" та "Services", які мають конкретні конотації Kubernetes) мережею. NetworkPolicies – застосовується до зʼєднання з Pod на одному або обох кінцях і не має відношення до інших зʼєднань.

Сутності, з якими може взаємодіяти Pod, ідентифікуються за допомогою комбінації наступних трьох ідентифікаторів:

  1. Інші дозволені Podʼи (виняток: Pod не може блокувати доступ до себе самого)
  2. Дозволені простори імен
  3. IP-блоки (виняток: трафік до та від вузла, де працює Pod, завжди дозволений, незалежно від IP-адреси Podʼа чи вузла)

При визначенні мережевої політики на основі Podʼа чи простору імен ви використовуєте селектор для визначення, який трафік дозволений до та від Podʼа(ів), які відповідають селектору.

Тим часом при створенні мережевих політик на основі IP ми визначаємо політику на основі IP-блоків (діапазони CIDR).

Передумови

Мережеві політики впроваджуються мережевим втулком. Для використання мережевих політик вам слід використовувати рішення з підтримкою NetworkPolicy. Створення ресурсу NetworkPolicy без контролера, який його реалізує, не матиме ефекту.

Два види ізоляції для Podʼів

Існують два види ізоляції для Podʼа: ізоляція для вихідного трафіку (egress) та ізоляція для вхідного трафіку (ingress). Це стосується того, які зʼєднання можуть бути встановлені. Тут "ізоляція" не є абсолютною, але означає "діють деякі обмеження". Альтернатива, "non-isolated for $direction", означає, що в зазначеному напрямку обмеження відсутні. Два види ізоляції (або ні) декларуються незалежно та є важливими для підключення від одного Podʼа до іншого.

Типово Pod не є ізольованим для вихідного трафіку (egress); всі вихідні зʼєднання дозволені. Pod ізольований для вихідного трафіку, якщо є будь-яка мережева політика, яка одночасно вибирає Pod і має "Egress" у своєму policyTypes; ми кажемо, що така політика застосовується до Podʼа для вихідного трафіку. Коли Pod ізольований для вихідного трафіку, єдині дозволені зʼєднання з Podʼу — ті, які дозволені списком egress деякої мережевої політики, яка застосовується до Podʼа для вихідного трафіку. Також буде неявно дозволений вихідний трафік для цих дозволених зʼєднань. Ефекти цих списків egress обʼєднуються адитивно.

Типово Pod не є ізольованим для вхідного трафіку (ingress); всі вхідні зʼєднання дозволені. Pod ізольований для вхідного трафіку, якщо є будь-яка мережева політика, яка одночасно вибирає Pod і має "Ingress" у своєму policyTypes; ми кажемо, що така політика застосовується до Podʼа для вхідного трафіку. Коли Pod ізольований для вхідного трафіку, єдині дозволені зʼєднання до Podʼу - ті, що з вузла Podʼу та ті, які дозволені списком ingress деякої мережевої політики, яка застосовується до Podʼа для вхідного трафіку. Також буде неявно дозволений вхідний трафік для цих дозволених зʼєднань. Ефекти цих списків ingress об'єднуються адитивно.

Мережеві політики не конфліктують; вони є адитивними. Якщо будь-яка політика чи політики застосовуються до певного Podʼа для певного напрямку, то зʼєднання, які дозволяються в цьому напрямку від цього Podʼа, — це обʼєднання того, що дозволяють відповідні політики. Таким чином, порядок оцінки не впливає на результат політики.

Для того, щоб зʼєднання від джерела до призначення було дозволено, обидві політики, вихідна на джерелі та вхідна на призначенні, повинні дозволяти зʼєднання. Якщо хоча б одна сторона не дозволяє зʼєднання, воно не відбудеться.

Ресурс NetworkPolicy

Для повного визначення ресурсу дивіться посилання на NetworkPolicy.

Приклад NetworkPolicy може виглядати наступним чином:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Обовʼязкові поля: Як і з усіма іншими конфігураціями Kubernetes, для NetworkPolicy потрібні поля apiVersion, kind та metadata. Для загальної інформації щодо роботи з конфігураційними файлами дивіться Налаштування Pod для використання ConfigMap та Управління обʼєктами.

spec: Специфікація мережевої політики spec містить всю інформацію, необхідну для визначення конкретної мережевої політики в заданому просторі імен.

podSelector: Кожна NetworkPolicy включає podSelector, який вибирає групу Podʼів, до яких застосовується політика. У прикладі політики вибираються Podʼи з міткою "role=db". Порожній podSelector вибирає всі Podʼи в просторі імен.

policyTypes: Кожна NetworkPolicy включає список policyTypes, який може містити або Ingress, або Egress, або обидва. Поле policyTypes вказує, чи політика застосовується, чи ні до трафіку ingress до вибраних Podʼів, трафіку egress від вибраних Podʼів чи обох. Якщо на NetworkPolicy не вказано жодних policyTypes, то станадартно буде завжди встановлено Ingress, а Egress буде встановлено, якщо у NetworkPolicy є хоча б одне правило egress.

ingress: Кожна NetworkPolicy може включати список дозволених правил ingress. Кожне правило дозволяє трафіку, який відповідає як from, так і секції ports. У прикладі політики є одне правило, яке відповідає трафіку на одному порту від одного з трьох джерел: перше вказано через ipBlock, друге через namespaceSelector, а третє через podSelector.

egress: Кожна NetworkPolicy може включати список дозволених правил egress. Кожне правило дозволяє трафіку, який відповідає як секції to, так і ports. У прикладі політики є одне правило, яке відповідає трафіку на одному порту до будь-якого призначення в 10.0.0.0/24.

Отже, приклад NetworkPolicy:

  1. ізолює Podʼи role=db в просторі імен default для трафіку як ingress, так і egress (якщо вони ще не були ізольовані)

  2. (Правила Ingress) дозволяє підключення до всіх Podʼів в просторі імен default з міткою role=db на TCP-порт 6379 від:

    • будь-якого Pod в просторі імен default з міткою role=frontend
    • будь-якого Pod в просторі імені з міткою project=myproject
    • IP-адреси в діапазонах 172.17.0.0172.17.0.255 nf 172.17.2.0172.17.255.255 (тобто, усе 172.17.0.0/16, за винятком 172.17.1.0/24)
  3. (Правила Egress) дозволяє підключення з будь-якого Pod в просторі імен default з міткою role=db до CIDR 10.0.0.0/24 на TCP-порт 5978

Дивіться Оголошення мережевої політики для ознайомлення з додатковими прикладами.

Поведінка селекторів to та from

Існує чотири види селекторів, які можна вказати в розділі from для ingress або to для egress:

podSelector: Вибирає певні Podʼи в тому ж просторі імен, що і NetworkPolicy, які мають бути допущені як джерела ingress або призначення egress.

namespaceSelector: Вибирає певні простори імен, для яких всі Podʼи повинні бути допущені як джерела ingress або призначення egress.

namespaceSelector та podSelector: Один елемент to/from, який вказує як namespaceSelector, так і podSelector, вибирає певні Podʼи в певних просторах імен. Будьте уважні при використанні правильного синтаксису YAML. Наприклад:

  ...
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          user: alice
      podSelector:
        matchLabels:
          role: client
  ...

Ця політика містить один елемент from, який дозволяє підключення від Podʼів з міткою role=client в просторах імен з міткою user=alice. Але наступна політика відрізняється:

  ...
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          user: alice
    - podSelector:
        matchLabels:
          role: client
  ...

Вона містить два елементи у масиві from та дозволяє підключення від Podʼів у локальному просторі імен з міткою role=client, або від будь-якого Podʼа в будь-якому просторі імен з міткою user=alice.

У випадку невизначеності використовуйте kubectl describe, щоб переглянути, як Kubernetes інтерпретував політику.

ipBlock: Вибирає певні діапазони IP CIDR для дозволу їх як джерел ingress або призначення egress. Це повинні бути зовнішні для кластера IP, оскільки IP Podʼів є ефемерними та непередбачуваними.

Механізми ingress та egress кластера часто вимагають переписування IP джерела або IP призначення пакетів. У випадках, коли це відбувається, не визначено, чи це відбувається до, чи після обробки NetworkPolicy, і поведінка може бути різною для різних комбінацій мережевого втулка, постачальника хмарних послуг, реалізації Service тощо.

У випадку ingress це означає, що у деяких випадках ви можете фільтрувати вхідні пакети на основі фактичної вихідної IP, тоді як в інших випадках "вихідна IP-адреса", на яку діє NetworkPolicy, може бути IP LoadBalancer або вузла Podʼа тощо.

Щодо egress це означає, що підключення з Podʼів до IP Service, які переписуються на зовнішні IP кластера, можуть або не можуть підпадати під політику на основі ipBlock.

Стандартні політики

Типово, якщо в просторі імен відсутні будь-які політики, то трафік ingress та egress дозволено до та від Podʼів в цьому просторі імен. Наступні приклади дозволяють змінити стандартну поведінку в цьому просторі імені.

Стандартна заборона всього вхідного трафіку

Ви можете створити політику стандартної ізоляції вхідного трафіку для простору імен, створивши NetworkPolicy, яка вибирає всі Podʼи, але не дозволяє будь-який вхідний трафік для цих Podʼів.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Це забезпечить ізоляцію вхідного трафіку навіть для Podʼів, які не вибрані жодною іншою NetworkPolicy. Ця політика не впливає на ізоляцію egress трафіку з будь-якого Podʼа.

Дозвіл на весь вхідний трафік

Якщо ви хочете дозволити всі вхідні підключення до всіх Podʼів в просторі імен, ви можете створити політику, яка явно це дозволяє.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
spec:
  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress

З цією політикою ніяка додаткова політика або політики не можуть призвести до відмови у ingress підключенні до цих Podʼів. Ця політика не впливає на ізоляцію вихідного трафіку з будь-якого Podʼа.

Стандартна заборона всього вихідного трафіку

Ви можете створити стандартну політику ізоляції вихідного трафіку для простору імен, створивши NetworkPolicy, яка вибирає всі Podʼи, але не дозволяє будь-який egress трафік від цих Podʼів.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
spec:
  podSelector: {}
  policyTypes:
  - Egress

Це забезпечить те, що навіть Podʼи, які не вибрані жодною іншою NetworkPolicy, не матимуть дозволу на вихідний трафік. Ця політика не змінює ізоляційну поведінку egress трафіку з будь-якого Podʼа.

Дозвіл на весь вихідний трафік

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

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-egress
spec:
  podSelector: {}
  egress:
  - {}
  policyTypes:
  - Egress

З цією політикою ніяка додаткова політика або політики не можуть призвести до відмови у вихідному підключенні з цих Podʼів. Ця політика не впливає на ізоляцію ingress трафіку до будь-якого Podʼа.

Стандартна заборона всього вхідного та всього вихідного трафіку

Ви можете створити "стандартну" політику для простору імен, яка забороняє весь ingress та egress трафік, створивши наступний NetworkPolicy в цьому просторі імені.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Це забезпечить те, що навіть Podʼи, які не вибрані жодною іншою NetworkPolicy, не матимуть дозволу на трафік ingress та egress напрямку.

Фільтрація мережевого трафіку

NetworkPolicy визначений для зʼєднань layer 4 (TCP, UDP та за необхідності SCTP). Для всіх інших протоколів поведінка може варіюватися залежно від мережевих втулків.

Коли визначена мережева політика deny all, гарантується тільки відмова в TCP, UDP та SCTP зʼєднаннях. Для інших протоколів, таких як ARP чи ICMP, поведінка невизначена. Те ж саме стосується правил дозволу (allow): коли певний Pod дозволений як джерело ingress або призначення egress, не визначено, що відбувається з (наприклад) пакетами ICMP. Такі протоколи, як ICMP, можуть бути дозволені одними мережевими втулками та відхилені іншими.

Спрямування трафіку на діапазон портів

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

При написанні NetworkPolicy ви можете спрямовувати трафік на діапазон портів, а не на один окремий порт.

Це можливо завдяки використанню поля endPort, як показано в наступному прикладі:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: multi-port-egress
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/24
      ports:
        - protocol: TCP
          port: 32000
          endPort: 32768

Вищевказане правило дозволяє будь-якому Podʼу з міткою role=db в просторі імен default спілкуватися з будь-яким IP в діапазоні 10.0.0.0/24 по протоколу TCP, при умові, що цільовий порт знаходиться в діапазоні від 32000 до 32768.

Застосовуються наступні обмеження при використанні цього поля:

  • Поле endPort повинно бути рівним або більшим за поле port.
  • endPort може бути визначено тільки в тому випадку, якщо також визначено port.
  • Обидва порти повинні бути числовими значеннями.

Спрямування трафіку на кілька просторів імен за допомогою міток

У цім сценарії ця ваша Egress NetworkPolicy спрямована на більше ніж один простір імен, використовуючи їх мітки. Для цього необхідно додати мітки до цільових просторів імен. Наприклад:

kubectl label namespace frontend namespace=frontend
kubectl label namespace backend namespace=backend

Додайте мітки до namespaceSelector в вашому документі NetworkPolicy. Наприклад:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-namespaces
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchExpressions:
        - key: namespace
          operator: In
          values: ["frontend", "backend"]

Спрямування трафіку на простір імен за його іменем

Керівництво Kubernetes встановлює незмінювану мітку kubernetes.io/metadata.name на всі простори імен, значення мітки — це імʼя простору імен.

Хоча NetworkPolicy не може спрямовуватися на простір імен за його іменем з допомогою поля обʼєкта, ви можете використовувати стандартизовану мітку для спрямування на конкретний простір імен.

Життєвий цикл Podʼу

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

Щойно NetworkPolicy оброблено мережевим втулком,

  1. Усі нові Podʼи, які стосуються даної NetworkPolicy, будуть ізольовані перед тим, як їх запустять. Реалізації NetworkPolicy повинні забезпечити, що фільтрація є ефективною впродовж усього життєвого циклу Podʼа, навіть з моменту першого запуску будь-якого контейнера у цьому Podʼі. Оскільки вони застосовуються на рівні Podʼа, NetworkPolicies однаково застосовуються до init-контейнерів, контейнерів-супутників та звичайних контейнерів.

  2. Правила дозволів будуть застосовані, остаточно після правил ізоляції (або можуть бути застосовані одночасно). У найгіршому випадку новий Pod може не мати жодного мережевого зʼєднання взагалі при першому запуску, якщо правила ізоляції вже були застосовані, але правила дозволів ще не були застосовані.

Кожна створена NetworkPolicy буде врешті-решт застосована мережевим втулком, але немає способу визначити з API Kubernetes, коли саме це станеться.

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

Кожна NetworkPolicy буде застосована до всіх вибраних Podʼів врешті-решт. Оскільки мережевий втулок може реалізовувати NetworkPolicy розподіленим чином, можливо, що Podʼи можуть бачити трохи неузгоджений вид мережевих політик при першому створенні Podʼа або при зміні Podʼів або політик. Наприклад, новий створений Pod, який повинен бути в змозі досягти як Podʼа на вузлі 1, так і Podʼа на вузлі 2, може знайти, що він може досягати Podʼа А негайно, але не може досягати Podʼа B впродовж кількох секунд.

NetworkPolicy та Podʼи з hostNetwork

Поведінка NetworkPolicy для Podʼів із hostNetwork є невизначеною, але вона повинна обмежуватися двома можливостями:

  • Мережевий втулок може відрізняти трафік Podʼів з hostNetwork від усього іншого трафіку (включаючи можливість відрізняти трафік від різних Podʼів з hostNetwork на тому ж вузлі) та застосовувати NetworkPolicy до Podʼів із hostNetwork, , так само як і до Podʼів мережі Podʼа.
  • Мережевий втулок не може належним чином відрізняти трафік Podʼів із hostNetwork, тому він ігнорує Podʼи з hostNetwork при відповідності podSelector та namespaceSelector. Трафік до/від Podʼів із hostNetwork обробляється так само як і весь інший трафік до/від IP-адреси вузла. (Це найбільш поширена реалізація.)

Це стосується випадків, коли

  1. Pod із hostNetwork вибирається за допомогою spec.podSelector.

      ...
      spec:
        podSelector:
          matchLabels:
            role: client
      ...
    
  2. Pod із hostNetwork вибирається за допомогою podSelector чи namespaceSelector в правилі ingress чи egress.

      ...
      ingress:
        - from:
          - podSelector:
              matchLabels:
                role: client
      ...
    

В той самий час, оскільки Podʼи з hostNetwork мають ті ж IP-адреси, що й вузли, на яких вони розташовані, їх зʼєднання буде вважатися зʼєднанням до вузла. Наприклад, ви можете дозволити трафік з Podʼу із hostNetwork за допомогою правила ipBlock.

Що ви не можете зробити за допомогою мережевих політик (принаймні, зараз) {#what-you-can't-do-with-network-policies-at-least-not-yet}

В Kubernetes 1.30, наступна функціональність відсутня в API NetworkPolicy, але, можливо, ви зможете реалізувати обходні шляхи, використовуючи компоненти операційної системи (такі як SELinux, OpenVSwitch, IPTables та інші) або технології Layer 7 (контролери Ingress, реалізації Service Mesh) чи контролери допуску. У випадку, якщо ви новачок в мережевому захисті в Kubernetes, варто відзначити, що наступні випадки не можна (ще) реалізувати за допомогою API NetworkPolicy.

  • Примусова маршрутизація внутрішньокластерного трафіку через загальний шлюз (це, можливо, найкраще реалізувати за допомогою сервіс-мешу чи іншого проксі).
  • Будь-яка функціональність, повʼязана з TLS (для цього можна використовувати сервіс-меш чи контролер ingress).
  • Політики, специфічні для вузла (ви можете використовувати нотацію CIDR для цього, але ви не можете визначати вузли за їхніми ідентифікаторами Kubernetes).
  • Спрямування трафіку на service за іменем (проте ви можете спрямовувати трафік на Podʼи чи простори імен за їх мітками, що часто є прийнятним обхідним варіантом).
  • Створення або управління "Policy request", які виконуються третьою стороною.
  • Типові політики, які застосовуються до всіх просторів імен чи Podʼів (є деякі дистрибутиви Kubernetes від сторонніх постачальників та проєкти, які можуть це робити).
  • Розширені засоби надсилання запитів та інструменти перевірки досяжності політики.
  • Можливість ведення логу подій з мережевої безпеки (наприклад, заблоковані чи прийняті зʼєднання).
  • Можливість явно відмовляти в політиках (наразі модель для NetworkPolicy — це типова відмова, з можливістю додавання тільки правил дозволу).
  • Можливість уникнення loopback чи вхідного трафіку від хоста (Podʼи наразі не можуть блокувати доступ до localhost, і вони не мають можливості блокувати доступ від їхнього вузла-резидента).

Вплив мережевих політик на існуючі з'єднання

Коли набір мережевих політик, які застосовуються до існуючого з'єднання, змінюється - це може трапитися через зміну мережевих політик або якщо відповідні мітки обраних просторів імен/подів, обраних політикою (як суб'єкт і пірси), змінюються під час існуючого з'єднання - не визначено в реалізації, чи буде врахована зміна для цього існуючого з'єднання чи ні. Наприклад: створено політику, яка призводить до відмови в раніше дозволеному з'єднанні, реалізація базового мережевого плагіна відповідальна за визначення того, чи буде ця нова політика закривати існуючі з'єднання чи ні. Рекомендується утримуватися від змін політик/подів/просторів імен таким чином, що може вплинути на існуючі з'єднання.

Що далі

7 - DNS для Service та Podʼів

Ваше робоче навантаження може виявляти Serviceʼи всередині вашого кластеру за допомогою DNS; ця сторінка пояснює, як це працює.

Kubernetes створює DNS-записи для Service та Podʼів. Ви можете звертатися до Service за допомогою стійких імен DNS замість IP-адрес.

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

Service, визначеним у кластері, призначаються імена DNS. Типово список пошуку DNS клієнта Pod включає власний простір імен Pod та стандартний домен кластера.

Простори імен Serviceʼів

DNS-запит може повертати різні результати залежно від простору імен Podʼа, який його створив. DNS-запити, які не вказують простір імен, обмежені простором імен Podʼа. Для доступу до Service в інших просторах імен, вказуйте його в 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.

nameserver 10.32.0.10
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Отже, узагальнюючи, Pod у просторі імен test може успішно знаходити як data.prod, так і data.prod.svc.cluster.local.

DNS-записи

Для яких обʼєктів створюються DNS-записи?

  1. Serviceʼи
  2. Podʼи

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

Serviceʼи

Записи A/AAAA

"Звичайні" (не headless) Serviceʼи отримують 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. На відміну від звичайних Serviceʼів, це розгортається в набір IP-адрес всіх Podʼів, вибраних Serviceʼом. Очікується, що клієнти будуть використовувати цей набір або використовувати стандартний round-robin вибір із набору.

Записи SRV

Записи SRV створюються для іменованих портів, які є частиною звичайних або headless сервісів. Для кожного іменованого порту запис 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-ipv4-address.my-namespace.pod.cluster-domain.example.

Наприклад, якщо Pod в просторі імен default має IP-адресу 172.17.0.3, а доменне імʼя вашого кластера — cluster.local, то у Podʼа буде DNS-імʼя:

172-17-0-3.default.pod.cluster.local.

Будь-які Podʼи, на які поширюється Service, мають наступний доступ через DNS:

pod-ipv4-address.service-name.my-namespace.svc.cluster-domain.example.

Поля hostname та subdomain Podʼа

Наразі, при створенні Podʼа, його імʼя (як його видно зсередини Podʼа) визначається як значення metadata.name Podʼа.

У специфікації Podʼа є необовʼязкове поле hostname, яке можна використовувати для вказівки відмінного від імʼя Podʼа імені хосту. Коли вказано, воно має пріоритет над іменем Podʼа та стає імʼям хосту Podʼа (знову ж таки, в спостереженнях зсередини Podʼа). Наприклад, якщо у Podʼа вказано spec.hostname зі значенням "my-host", то у Podʼа буде імʼя хосту "my-host".

Специфікація Podʼа також має необовʼязкове поле subdomain, яке може використовуватися для вказівки того, що Pod є частиною підгрупи простору імен. Наприклад, Pod з spec.hostname встановленим на "foo", та spec.subdomain встановленим на "bar", у просторі імен "my-namespace", матиме імʼя хосту "foo" та повністю визначене доменне імʼя (FQDN) "foo.bar.my-namespace.svc.cluster.local" (знову ж таки, в спостереженнях зсередини Podʼа).

Якщо існує headless Service в тому ж просторі імен, що і Pod, із тим самим імʼям, що і піддомен, DNS-сервер кластера також поверне записи A та/або AAAA для повної доменної назви Podʼа.

Приклад:

apiVersion: v1
kind: Service
metadata:
  name: busybox-subdomain
spec:
  selector:
    name: busybox
  clusterIP: None
  ports:
  - name: foo # імʼя не є обовʼязковим для Serviceʼів з одним портом
    port: 1234
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox1
  labels:
    name: busybox
spec:
  hostname: busybox-1
  subdomain: busybox-subdomain
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    name: busybox
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox2
  labels:
    name: busybox
spec:
  hostname: busybox-2
  subdomain: busybox-subdomain
  containers:
  - image: busybox:1.28
    command:
      - 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-hostname для будь-якої адреси endpoint, разом з його IP.

Поле setHostnameAsFQDN Podʼа

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

Коли 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ʼа.

Політика DNS Podʼа

Політику DNS можна встановлювати для кожного Podʼа окремо. Наразі Kubernetes підтримує наступні політики DNS, вказані у полі dnsPolicy в специфікації Podʼа:

  • "Default": Pod успадковує конфігурацію розпізнавання імені від вузла, на якому працюють Podʼи. Деталі можна переглянути у відповідній дискусії.
  • "ClusterFirst": Будь-який DNS-запит, який не відповідає налаштованому суфіксу домену кластера, такому як "www.kubernetes.io", пересилається на вихідний DNS-сервер DNS-сервером. Адміністратори кластера можуть мати додаткові налаштовані піддомени та вихідні DNS-сервери. Деталі щодо обробки DNS-запитів у цих випадках можна знайти відповідній дискусії.
  • "ClusterFirstWithHostNet": Для Podʼів, які працюють із hostNetwork, ви повинні явно встановити для них політику DNS "ClusterFirstWithHostNet". В іншому випадку Podʼи, що працюють із hostNetwork та "ClusterFirst", будуть використовувати поведінку політики "Default".
    • Примітка: Це не підтримується в Windows. Деталі дивіться нижче.
  • "None": Це дозволяє Podʼу ігнорувати налаштування DNS з оточення Kubernetes. Всі налаштування DNS повинні надаватися за допомогою поля dnsConfig у специфікації Podʼа. Деталі дивіться у підрозділі DNS-конфігурація Podʼа нижче.

Наведений нижче приклад показує Pod із встановленою політикою DNS "ClusterFirstWithHostNet", оскільки у нього встановлено hostNetwork в true.

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
    name: busybox
  restartPolicy: Always
  hostNetwork: true
  dnsPolicy: ClusterFirstWithHostNet

Конфігурація DNS для Podʼа

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

Конфігурація DNS для Podʼа дозволяє користувачам мати більше контролю над налаштуваннями DNS для конкретного Podʼа.

Поле dnsConfig є необовʼязковим і може використовуватися з будь-якими налаштуваннями dnsPolicy. Однак, коли поле dnsPolicy Podʼа встановлено в "None", поле dnsConfig повинно бути вказано.

Нижче наведені значення, які користувач може вказати у полі dnsConfig:

  • nameservers: список IP-адрес, які будуть використовуватися як DNS-сервери для Podʼа. Можна вказати не більше 3 IP-адрес, але коли політика DNS Podʼа встановлена на "None", список повинен містити принаймні одну IP-адресу, інакше ця властивість є необовʼязковою. Зазначені сервери будуть обʼєднані з базовими серверами, згенерованими з вказаною політикою DNS, з вилученням дубльованих адрес.
  • searches: список доменів пошуку DNS для пошуку імен в хостах у Podʼі. Ця властивість є необовʼязковою. При вказанні, вказаний список буде обʼєднаний з базовими доменами пошуку, згенерованими з вибраної політики DNS. Дубльовані доменні імена вилучаються. Kubernetes дозволяє до 32 доменів пошуку.
  • options: необовʼязковий список обʼєктів, де кожний обʼєкт може мати властивість name (обовʼязкова) і властивість value (необовʼязкова). Зміст цієї властивості буде обʼєднаний з параметрами, згенерованими з вказаної політики DNS. Дубльовані елементи вилучаються.

Тут наведено приклад Podʼа з власними налаштуваннями DNS:

apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
    - name: test
      image: nginx
  dnsPolicy: "None"
  dnsConfig:
    nameservers:
      - 192.0.2.1 # тут адреса для прикладу
    searches:
      - ns1.svc.cluster-domain.example
      - my.dns.search.suffix
    options:
      - name: ndots
        value: "2"
      - name: edns0

Коли створюється Pod, контейнер test отримує наступний зміст у своєму файлі /etc/resolv.conf:

nameserver 192.0.2.1
search ns1.svc.cluster-domain.example my.dns.search.suffix
options ndots:2 edns0

Для налаштування IPv6 шляху пошуку та сервера імен слід встановити:

kubectl exec -it dns-example -- cat /etc/resolv.conf

Вивід буде подібний до наступного:

nameserver 2001:db8:30::a
search default.svc.cluster-domain.example svc.cluster-domain.example cluster-domain.example
options ndots:5

Обмеження списку доменів пошуку DNS

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

Kubernetes сам по собі не обмежує конфігурацію DNS до тих пір, поки довжина списку доменів пошуку не перевищить 32 або загальна довжина всіх доменів пошуку не перевищить 2048. Це обмеження стосується файлу конфігурації резолвера вузла, конфігурації DNS Podʼа та обʼєднаної конфігурації DNS відповідно.

DNS на вузлах з операційною системою Windows

  • ClusterFirstWithHostNet не підтримується для Podʼів, які працюють на вузлах з операційною системою Windows. У Windows всі імена з крапкою . розглядаються як повністю кваліфіковані та пропускають розгортання FQDN.
  • На Windows існують кілька резолверів DNS, які можна використовувати. Оскільки вони мають трохи відмінну поведінку, рекомендується використовувати Resolve-DNSName для отримання імені.
  • У Linux у вас є список суфіксів DNS, який використовується після того, як розгортання імені як повністю кваліфіковане не вдалося. У Windows можна вказати лише 1 суфікс DNS, який є суфіксом DNS, повʼязаним з простором імен цього Podʼа (наприклад, mydns.svc.cluster.local). Windows може розгортати FQDN, служби або мережеве імʼя, яке може бути розгорнуто за допомогою цього єдиного суфікса. Наприклад, Pod, створений у просторі імен default, матиме суфікс DNS default.svc.cluster.local. Всередині Windows імʼя Podʼу можна розгортати як kubernetes.default.svc.cluster.local, так і kubernetes, але не в частково кваліфіковані імена (kubernetes.default або kubernetes.default.svc).

Що далі

Для керівництва щодо адміністрування конфігурацій DNS дивіться Налаштування служби DNS

8 - Подвійний стек IPv4/IPv6

Kubernetes дозволяє налаштувати мережеве зʼєднання з одним стеком IPv4, з одним стеком IPv6 або з подвійним стеком з обома сімействами мереж. Ця сторінка пояснює, як це зробити.
СТАН ФУНКЦІОНАЛУ: Kubernetes v1.23 [stable]

Двостекова мережа IPv4/IPv6 дозволяє виділяти як адреси IPv4, так і IPv6 для Podʼів та Serviceʼів.

Двостекова мережа IPv4/IPv6 є стандартно увімкненою у вашому кластері Kubernetes починаючи з версії 1.21, що дозволяє одночасно призначати адреси як IPv4, так і IPv6.

Підтримувані функції

Двостекова мережа IPv4/IPv6 у вашому кластері Kubernetes надає наступні можливості:

  • Мережа Pod із двома стеками (призначення адреси IPv4 і IPv6 на один Pod)
  • Serviceʼи з підтримкою IPv4 і IPv6
  • Маршрутизація egress Pod за межі кластера (наприклад, в Інтернет) через інтерфейси IPv4 та IPv6

Передумови

Для використання двостекових кластерів Kubernetes IPv4/IPv6 потрібні наступні передумови:

  • Kubernetes 1.20 або новіше

    Для отримання інформації щодо використання двостекових Serviceʼів із попередніми версіями Kubernetes, дивіться документацію для відповідної версії Kubernetes.

  • Підтримка постачальником двостекової мережі (постачальник хмари або інший повинен забезпечити вузлам Kubernetes маршрутизовані мережеві інтерфейси IPv4/IPv6)

  • Мережевий втулок, який підтримує двостекову мережу.

Налаштування двостекової мережі IPv4/IPv6

Щоб налаштувати подвійний стек IPv4/IPv6, встановіть призначення мережі кластера з подвійним стеком:

  • kube-apiserver:
    • --service-cluster-ip-range=<CIDR IPv4>,<CIDR IPv6>
  • kube-controller-manager:
    • --cluster-cidr=<CIDR IPv4>,<CIDR IPv6>
    • --service-cluster-ip-range=<CIDR IPv4>,<CIDR 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.)

Serviceʼи

Ви можете створювати Serviceʼи, які можуть використовувати адреси IPv4, IPv6 або обидві.

Сімейство адрес Service типово відповідає сімейству адрес першого діапазону IP Service кластера (налаштованого через прапорець --service-cluster-ip-range у kube-apiserver).

При визначенні Service ви можете конфігурувати його як двостековий за власним бажанням. Щоб вказати потрібну поведінку, ви встановлюєте в поле .spec.ipFamilyPolicy одне з наступних значень:

  • SingleStack: Service з одним стеком. Панель управління виділяє IP кластера для Service, використовуючи перший налаштований діапазон IP кластера для Service.
  • PreferDualStack: Виділяє IP-адреси кластерів IPv4 та IPv6 для Service, коли ввімкнено подвійний стек. Якщо подвійний стек не ввімкнено або не підтримується, він повертається до одностекового режиму.
  • RequireDualStack: Виділяє IP-адреси Service .spec.clusterIP з діапазонів адрес IPv4 та IPv6, якщо увімкнено подвійний стек. Якщо подвійний стек не ввімкнено або не підтримується, створення обʼєкта Service API завершиться невдачею.
    • Вибирає .spec.clusterIP зі списку .spec.clusterIPs на основі сімейства адрес першого елемента у масиві .spec.ipFamilies.

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

Ви можете встановити .spec.ipFamilies в будь-яке з наступних значень масиву:

  • ["IPv4"]
  • ["IPv6"]
  • ["IPv4","IPv6"] (два стеки)
  • ["IPv6","IPv4"] (два стеки)

Перше сімейство, яке ви перераховуєте, використовується для легасі-поля .spec.clusterIP.

Сценарії конфігурації двостекового Service

Ці приклади демонструють поведінку різних сценаріїв конфігурації двостекового Service.

Параметри подвійного стека в нових Service

  1. Специфікація цього Service явно не визначає .spec.ipFamilyPolicy. Коли ви створюєте цей Service, Kubernetes виділяє кластерний IP для Service з першого налаштованого service-cluster-ip-range та встановлює значення .spec.ipFamilyPolicy на SingleStack. (Service без селекторів та headless Services із селекторами будуть працювати так само.)

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
      labels:
        app.kubernetes.io/name: MyApp
    spec:
      selector:
        app.kubernetes.io/name: MyApp
      ports:
        - protocol: TCP
          port: 80
    
  2. Специфікація цього Service явно визначає PreferDualStack в .spec.ipFamilyPolicy. Коли ви створюєте цей Service у двостековому кластері, Kubernetes призначає як IPv4, так і IPv6 адреси для Service. Панель управління оновлює .spec для Service, щоб зафіксувати адреси IP. Поле .spec.clusterIPs є основним полем і містить обидві призначені адреси IP; .spec.clusterIP є вторинним полем зі значенням, обчисленим з .spec.clusterIPs.

    • Для поля .spec.clusterIP панель управління записує IP-адресу, яка є з того ж самого сімейства адрес, що й перший діапазон кластерних IP Service.
    • У одностековому кластері поля .spec.clusterIPs та .spec.clusterIP містять лише одну адресу.
    • У кластері з увімкненими двома стеками вказання RequireDualStack в .spec.ipFamilyPolicy працює так само як і PreferDualStack.
    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
      labels:
        app.kubernetes.io/name: MyApp
    spec:
      ipFamilyPolicy: PreferDualStack
      selector:
        app.kubernetes.io/name: MyApp
      ports:
        - protocol: TCP
          port: 80
    
  3. Специфікація цього Service явно визначає IPv6 та IPv4 в .spec.ipFamilies, а також визначає PreferDualStack в .spec.ipFamilyPolicy. Коли Kubernetes призначає IPv6 та IPv4 адреси в .spec.clusterIPs, .spec.clusterIP встановлюється на IPv6 адресу, оскільки це перший елемент у масиві .spec.clusterIPs, що перевизначає типові значення.

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
      labels:
        app.kubernetes.io/name: MyApp
    spec:
      ipFamilyPolicy: PreferDualStack
      ipFamilies:
      - IPv6
      - IPv4
      selector:
        app.kubernetes.io/name: MyApp
      ports:
        - protocol: TCP
          port: 80
    

Параметри подвійного стека в наявних Service

Ці приклади демонструють типову поведінку при увімкненні двостековості в кластері, де вже існують Service. (Оновлення наявного кластера до версії 1.21 або новіше вмикає двостековість.)

  1. Коли двостековість увімкнена в кластері, наявні Service (безперебійно IPv4 або IPv6) конфігуруються панеллю управління так, щоб встановити .spec.ipFamilyPolicy на SingleStack та встановити .spec.ipFamilies на сімейство адрес наявного Service. Кластерний IP наявного Service буде збережено в .spec.clusterIPs.

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
      labels:
        app.kubernetes.io/name: MyApp
    spec:
      selector:
        app.kubernetes.io/name: MyApp
      ports:
        - protocol: TCP
          port: 80
    

    Ви можете перевірити цю поведінку за допомогою kubectl, щоб переглянути наявний Service.

    kubectl get svc my-service -o yaml
    
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/name: MyApp
      name: my-service
    spec:
      clusterIP: 10.0.197.123
      clusterIPs:
      - 10.0.197.123
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app.kubernetes.io/name: MyApp
      type: ClusterIP
    status:
      loadBalancer: {}
    
  2. Коли двостековість увімкнена в кластері, наявні headless Services з селекторами конфігуруються панеллю управління так, щоб встановити .spec.ipFamilyPolicy на SingleStack та встановити .spec.ipFamilies на сімейство адрес першого діапазону кластерних IP Service (налаштованого за допомогою прапорця --service-cluster-ip-range для kube-apiserver), навіть якщо .spec.clusterIP встановлено в None.

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
      labels:
        app.kubernetes.io/name: MyApp
    spec:
      selector:
        app.kubernetes.io/name: MyApp
      ports:
        - protocol: TCP
          port: 80
    

    Ви можете перевірити цю поведінку за допомогою kubectl, щоб переглянути наявний headless Service з селекторами.

    kubectl get svc my-service -o yaml
    
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/name: MyApp
      name: my-service
    spec:
      clusterIP: None
      clusterIPs:
      - None
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app.kubernetes.io/name: MyApp
    

Перемикання Service між одностековим та двостековим режимами

Service можна перемикати з одностекового режиму на двостековий та навпаки.

  1. Для того щоби перемикнути Service з одностекового режиму на двостековий, змініть .spec.ipFamilyPolicy з SingleStack на PreferDualStack або RequireDualStack за необхідності. Коли ви змінюєте цей Service з одностекового режиму на двостековий, Kubernetes призначає відсутнє адресне сімейство, так що тепер Service має адреси IPv4 та IPv6.

    Відредагуйте специфікацію Service, оновивши .spec.ipFamilyPolicy з SingleStack на PreferDualStack.

    До:

    spec:
      ipFamilyPolicy: SingleStack
    

    Після:

    spec:
      ipFamilyPolicy: PreferDualStack
    
  2. Для того щоби змінити 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

Трафік Egress

Якщо ви хочете увімкнути трафік Egress, щоб досягти призначення за межами кластера (наприклад, публічний Інтернет) з Podʼа, який використовує непублічно марковані адреси IPv6, вам потрібно увімкнути Pod для використання публічно-маршрутизованих адрес IPv6 за допомогою механізму, такого як прозорий проксі або IP маскування. Проєкт ip-masq-agent підтримує IP-маскування у двохстекових кластерах.

Підтримка Windows

Kubernetes на Windows не підтримує одностекову мережу "лише IPv6". Однак підтримується двохстекова мережа IPv4/IPv6 для Podʼів та вузлів з одностековими Service.

Ви можете використовувати двохстекову мережу IPv4/IPv6 з мережами l2bridge.

Ви можете дізнатися більше про різні режими мережі для Windows в розділі Мережа у Windows.

Що далі

9 - Маршрутизація з урахуванням топології

Маршрутизацію з урахуванням топології надає механізм для збереження мережевого трафіку в межах зони, з якої він походить. Віддача переваги трафіку в межах однієї зони між Podʼами в вашому кластері може допомогти з надійністю, продуктивністю (мережевою затримкою та пропускною здатністю) або вартістю.
СТАН ФУНКЦІОНАЛУ: Kubernetes v1.23 [beta]

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

Мотивація

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

Увімкнення маршрутизації з урахуванням топології

Ви можете увімкнути маршрутизацію з урахуванням топології, для Service, встановивши анотацію service.kubernetes.io/topology-mode в значення Auto. Коли є достатня кількість точок доступу у кожній зоні, в EndpointSlice будуть заповнені підказки щодо топології для виділення окремих точок доступу конкретним зонам, що призводить до того, що трафік буде маршрутизуватися ближче до місця, звідки він походить.

Найкращий випадок застосування

Ця функція працює найкраще, коли:

1. Вхідний трафік рівномірно розподілений

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

2. У Service є 3 чи більше точок доступу на зону

У кластері з трьома зонами це означає 9 чи більше точок доступу. Якщо кількість точок доступу менше ніж 3 на зону, існує висока (≈50%) ймовірність, що контролер EndpointSlice не зможе рівномірно розподілити точки доступу та повернеться до застосування типового підходу до маршрутизації на рівні кластера.

Як це працює

Характеристика "Auto" намагається пропорційно виділити кількість точок доступу кожній зоні. Зверніть увагу, що цей підхід працює найкраще для сервісів зі значною кількістю точок доступу.

Контролер EndpointSlice

Контролер EndpointSlice відповідає за встановлення підказок на EndpointSlice, коли цей евристичний підхід увімкнено. Контролер виділяє пропорційну кількість точок доступу кожній зоні. Ця пропорція ґрунтується на виділеному обсязі ядер ЦП для вузлів, що працюють в цій зоні. Наприклад, якщо в одній зоні є 2 ядра ЦП, а в іншій зоні лише 1 ядро ЦП, контролер виділить подвійну кількість точок доступу для зони з 2 ядрами ЦП.

Нижче наведено приклад того, як виглядає EndpointSlice, коли підказки вже заповнено:

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: example-hints
  labels:
    kubernetes.io/service-name: example-svc
addressType: IPv4
ports:
  - name: http
    protocol: TCP
    port: 80
endpoints:
  - addresses:
      - "10.1.2.3"
    conditions:
      ready: true
    hostname: pod-1
    zone: zone-a
    hints:
      forZones:
        - name: "zone-a"

kube-proxy

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

Запобіжники

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

  1. Недостатня кількість точок доступу: Якщо точок доступу менше, ніж зон в кластері, контролер не буде додавати жодних підказок.

  2. Неможливо досягнути збалансованого розподілу: У деяких випадках може бути неможливо досягти збалансованого розподілу точок доступу між зонами. Наприклад, якщо zone-a удвічі більша, ніж zone-b, але є лише 2 точки доступу, точка доступу, призначена zone-a, може отримати вдвічі більше трафіку, ніж zone-b. Контролер не призначає підказок, якщо він не може знизити це значення "очікуваного перевантаження" нижче прийнятного порогу для кожної зони. Важливо, що це не ґрунтується на зворотньому звʼязку в режимі реального часу. Можливе перенавантаження окремих точок доступу.

  3. Один чи декілька вузлів має недостатню інформацію: Якщо який-небудь вузол не має мітки topology.kubernetes.io/zone або не повідомляє значення виділеного ЦП, панель управління не встановлює жодних підказок точок доступу з відомостями про зони, і, отже, kube-proxy не фільтрує точки доступу за зоною.

  4. Одна чи декілька точок доступу не має підказки щодо зони: Коли це трапляється, kube-proxy припускає, що відбувається перехід до або з Topology Aware Hints. Фільтрація точок доступу для Serviceʼу в цьому стані була б небезпечною, тому kube-proxy використовує всі точки доступу.

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

Обмеження

  • Topology Aware Hints не використовуються, коли internalTrafficPolicy встановлено в Local для Service. Можливе використання обох функцій у тому ж кластері для різних Serviceʼів, просто не на одному і тому ж Service.

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

  • Контролер EndpointSlice ігнорує непридатні вузли під час розрахунку пропорцій для кожної зони. Це може мати неочікувані наслідки, якщо велика частина вузлів непридатна.

  • Контролер EndpointSlice ігнорує вузли з мітками node-role.kubernetes.io/control-plane або node-role.kubernetes.io/master. Це може бути проблематичним, якщо також на цих вузлах працюють робочі навантаження.

  • Контролер EndpointSlice не враховує tolerations при розгортанні або розрахунку пропорцій для кожної зони. Якщо Podʼи, які підтримують Service, обмежені у підмножині вузлів у кластері, це не буде враховано.

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

Власні евристики

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

Що далі

10 - Мережеві аспекти Windows

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

Мережева взаємодія контейнерів у Windows

Мережевий стек для контейнерів у Windows використовує CNI-втулки. Контейнери у Windows працюють схоже до віртуальних машин з погляду мережі. Кожен контейнер має віртуальний мережевий адаптер (vNIC), який підключений до віртуального комутатора Hyper-V (vSwitch). Host Networking Service (HNS) та Host Compute Service (HCS) спільно працюють для створення контейнерів і підключення віртуальних мережевих адаптерів контейнера до мереж. HCS відповідає за управління контейнерами, тоді як HNS відповідає за управління ресурсами мережі, такими як:

  • Віртуальні мережі (включаючи створення vSwitches)
  • Endpoint / vNIC
  • Namespaces
  • Політика, включаючи інкапсуляцію пакетів, правила балансування навантаження, ACL, та правила NAT.

Windows HNS та vSwitch реалізують простір імен та можуть створювати віртуальні мережеві адаптери за потреби для 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. У таблиці нижче наведено втулки, що не є частиною Kubernetes, які підтримуються у Windows, з рекомендаціями щодо використання кожного CNI:

Драйвер мережіОписМодифікації контейнерних пакетівВтулки мережіХарактеристики втулків мережі
L2bridgeКонтейнери підключені до зовнішнього vSwitch. Контейнери підключені до мережі нижнього рівня, хоча фізична мережа не повинна знати MAC-адреси контейнера, оскільки вони переписуються при вході/виході.MAC переписується на MAC хосту, IP може бути переписаний на IP хосту за допомогою політики HNS OutboundNAT.win-bridge, Azure-CNI, Flannel host-gateway використовує win-bridgewin-bridge використовує режим мережі L2bridge, підключаючи контейнери до нижнього рівня хостів, пропонуючи найкращу продуктивність. Вимагає маршрутів, визначених користувачем (UDR) для міжвузлової зв'язності.
L2TunnelЦе спеціальний випадок l2bridge, але використовується тільки на Azure. Всі пакети відсилаються на віртуальний хост, де застосовується політика SDN.MAC переписується, IP видно в мережі нижнього рівняAzure-CNIAzure-CNI дозволяє інтегрувати контейнери з Azure vNET та використовувати набір можливостей, які Azure Virtual Network надає. Наприклад, безпечно підключатися до служб Azure або використовувати NSG Azure. Див. azure-cni для прикладів
OverlayКонтейнерам надається vNIC, підключений до зовнішнього vSwitch. Кожна мережа має власну підмережу IP, визначену власним IP-префіксом. Драйвер мережі використовує інкапсуляцію VXLAN.Інкапсульований в зовнішній заголовок.win-overlay, Flannel VXLAN (використовує win-overlay)win-overlay слід використовувати, коли потрібна ізоляція віртуальних мереж контейнерів від нижнього рівня хостів (наприклад, з міркувань безпеки). Дозволяє використовувати однакові IP для різних віртуальних мереж (які мають різні теґи VNID), якщо у вас обмеження на IP в вашому датацентрі. Цей варіант вимагає KB4489899 у Windows Server 2019.
Transparent (спеціальний випадок для ovn-kubernetes)Вимагає зовнішнього vSwitch. Контейнери підключені до зовнішнього vSwitch, що дозволяє взаємодію всередині Podʼа за допомогою логічних мереж (логічні свічі та маршрутизатори).Пакет капсулюється через GENEVE або STT для доступу до Podʼів, які не знаходяться на тому самому хості.
Пакети пересилаються чи відкидаються через інформацію про тунель, яку надає контролер мережі ovn.
NAT виконується для комунікації північ-південь.
ovn-kubernetesРозгортається за допомогою ansible. Розподілені ACL можна застосовувати за допомогою політик Kubernetes. Підтримка IPAM. Балансування навантаження можливе без використання kube-proxy. NAT виконується без використання iptables/netsh.
NAT (не використовується в Kubernetes)Контейнерам надається віртуальний мережевий адаптер (vNIC), підключений до внутрішнього vSwitch. DNS/DHCP надається за допомогою внутрішнього компонента, називається WinNATMAC та IP переписуються на MAC/IP хосту.natВключено тут для повноти.

Як вказано вище, Flannel CNI plugin також підтримується у Windows через VXLAN мережевий бекенд (Бета-підтримка; делегує до win-overlay) та host-gateway мережевий бекенд (стабільна підтримка; делегує до win-bridge).

Цей втулок підтримує делегування до одного з втулків CNI за вибором користувача (win-overlay, win-bridge), для співпраці з демоном Flannel у Windows (Flanneld) для автоматичного присвоєння лізингу підмережі вузлу та створення мережі HNS. Цей втулок читає власний файл конфігурації (cni.conf) та агрегує його зі змінними середовища зі створеного FlannelD файлу subnet.env. Потім він делегує одному з втулків CNI для роботи з мережею, надсилаючи правильну конфігурацію, що містить призначену вузлом підмережу до IPAM-втулку (наприклад: host-local).

Для обʼєктів Node, Pod та Service підтримуються наступні потоки даних мережі для TCP/UDP-трафіку:

  • Pod → Pod (IP)
  • Pod → Pod (Імʼя)
  • Pod → Сервіс (Кластерний IP)
  • Pod → Сервіс (PQDN, але тільки якщо немає ".")
  • Pod → Сервіс (FQDN)
  • Pod → зовнішній (IP)
  • Pod → зовнішній (DNS)
  • Node → Pod
  • Pod → Node

Управління IP-адресами (IPAM)

У Windows підтримуються наступні параметри IPAM:

Балансування навантаження та Service

Service Kubernetes є абстракцією, яка визначає логічний набір Podʼів та засіб доступу до них мережею. У кластері, який включає вузли Windows, можна використовувати наступні типи Service:

  • NodePort
  • ClusterIP
  • LoadBalancer
  • ExternalName

Мережева взаємодія контейнерів у Windows відрізняється в деяких важливих аспектах від мережі Linux. Документація Microsoft з мережевої взаємодії контейнерів у Windows надає додаткові відомості та контекст.

У Windows можна використовувати наступні налаштування для конфігурації Service та поведінки балансування навантаження:

Налаштування Сервісів для Windows
ФункціяОписМінімальна підтримувана версія Windows OSЯк ввімкнути
Подібність сесій
(Session affinity)
Забезпечує, що підключення від певного клієнта передається тому самому Podʼу кожен раз.Windows Server 2022Встановіть у service.spec.sessionAffinity значення "ClientIP"
Direct Server Return (DSR)Режим балансування навантаження, де виправлення IP-адреси та LBNAT відбуваються на порту vSwitch контейнера напряму; трафік служби приходить з наблору вихідних IP, встановленого як IP походження Podʼу.Windows Server 2019Встановіть наступні прапорці в kube-proxy: --feature-gates="WinDSR=true" --enable-dsr=true
Збереження-ПризначенняПропускає DNAT-трафік Servicʼу, тим самим зберігаючи віртуальну IP цільового Service в пакетах, що досягають фронтенду Podʼа. Також вимикає пересилання вузол-вузол.Windows Server, версія 1903Встановіть "preserve-destination": "true" в анотаціях служби та увімкніть DSR в kube-proxy.
Подвійний мережевий стек IPv4/IPv6Нативна підтримка IPv4-до-IPv4 поряд з IPv6-до-IPv6 комунікацією до, з і всередині кластераWindows Server 2019Див. Підтримка подвійного стеку IPv4/IPv6
Збереження IP клієнтаЗабезпечує збереження джерела ingress трафіку. Також вимикає пересилання вузол-вузол.Windows Server 2019Встановіть service.spec.externalTrafficPolicy у "Local" та увімкніть DSR в kube-proxy

Обмеження

Наступні функції мережі не підтримуються на вузлах Windows:

  • Режим мережі хосту
  • Локальний доступ NodePort з вузла (працює для інших вузлів або зовнішніх клієнтів)
  • Більше 64 бекенд-Podʼів (або унікальних адрес призначення) для одного Service
  • Зв'язок IPv6 між Pods Windows, підключеними до мереж оверлея
  • Local Traffic Policy в режимі без DSR
  • Вихідна комунікація за допомогою протоколу ICMP через win-overlay, win-bridge, або використовуючи втулок Azure-CNI. Зокрема панель даних Windows (VFP) не підтримує ICMP-перетворення пакетів, і це означає:
    • Пакети ICMP, спрямовані до пунктів призначення в одній мережі (наприклад, звʼязок Pod-Pod за допомогою ping), працюють належним чином;
    • TCP/UDP-пакети працюють, як очікується;
    • Пакети ICMP, спрямовані на проходження через віддалену мережу (наприклад, Pod-зовнішньої точки в інтернет через ping), не можуть бути перенесені та, таким чином, не будуть перенаправлені назад до свого джерела;
    • Оскільки TCP/UDP-пакети все ще можуть бути перетворені, ви можете замінити ping <destination> на curl <destination> при налагодженні зʼєднаності з зовнішнім світом.

Інші обмеження:

  • Референсні мережеві втулки Windows, такі як win-bridge та win-overlay, не мають реалізації специфікації CNI v0.4.0, через відсутність реалізації CHECK.
  • Втулок Flannel VXLAN має наступні обмеження на Windows:
    • Зʼєднаність Node-Pod можлива лише для локальних Podʼів з Flannel v0.12.0 (або вище).
    • Flannel обмежений використанням VNI 4096 та UDP-порту 4789. Див. офіційну Flannel VXLAN документацію про бекенд Flannel VXLAN щодо цих параметрів.

11 - Виділення IP-адрес ClusterIP Serviceʼам

У Kubernetes Service — це абстракція для експозиції застосунку, який працює на наборі Podʼів. Serviceʼи можуть мати віртуальну IP-адресу, доступну на рівні кластера (за допомогою Service з type: ClusterIP). Клієнти можуть підключатися за допомогою цієї віртуальної IP-адреси, і Kubernetes балансує трафік до цього Service між його Podʼами.

Як виділяються IP-адреси ClusterIP Сервісу?

Коли Kubernetes потрібно призначити віртуальну IP-адресу для Service, це відбувається одним із двох способів:

динамічно
панель управління кластера автоматично вибирає вільну IP-адресу з налаштованого діапазону IP для Service з type: ClusterIP.
статично
ви вказуєте IP-адресу за своїм вибором, з налаштованого діапазону IP для Service.

Для всього вашого кластера кожен Service ClusterIP повинен бути унікальним. Спроба створення Service із конкретним ClusterIP, що вже був призначений, призведе до помилки.

З чого випливає необхідність резервування IP-адрес для ClusterIP Service?

Іноді вам може знадобитися мати Serviceʼи, які працюють на відомих IP-адресах, щоб інші компоненти та користувачі в кластері могли їх використовувати.

Найкращим прикладом є Service DNS для кластера. Як мʼяка конвенція, деякі встановлювачі Kubernetes відводять 10-ту IP-адресу з діапазону IP-адрес Service для служби DNS. Припустимо, ви налаштували кластер із діапазоном IP-адрес Service 10.96.0.0/16 і хочете, щоб ваша IP-адреса Service DNS була 10.96.0.10, вам доведеться створити Service, подібний до цього:

apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: CoreDNS
  name: kube-dns
  namespace: kube-system
spec:
  clusterIP: 10.96.0.10
  ports:
  - name: dns
    port: 53
    protocol: UDP
    targetPort: 53
  - name: dns-tcp
    port: 53
    protocol: TCP
    targetPort: 53
  selector:
    k8s-app: kube-dns
  type: ClusterIP

але, як це було пояснено раніше, IP-адреса 10.96.0.10 не була зарезервована; якщо інші Service створюються перед або паралельно з динамічним виділенням, існує шанс, що вони можуть зайняти цю IP-адресу, тому ви не зможете створити Service DNS, оскільки це призведе до конфлікту.

Як уникнути конфліктів IP-адрес ClusterIP Сервісу?

Стратегія виділення, реалізована в Kubernetes для виділення ClusterIPs Service, зменшує ризик колізій.

ClusterIP діапазон поділений на основі формули min(max(16, cidrSize / 16), 256), описано як ніколи менше ніж 16 або більше за 256 із поступовим кроком між ними.

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

Приклади

Приклад 1

У цьому прикладі використовується діапазон IP-адрес: 10.96.0.0/24 (нотація CIDR) для IP-адрес Serviceʼів.

Розмір діапазону: 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-адрес Service.

Розмір діапазону: 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-адрес Service.

Розмір діапазону: 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

Що далі

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

Якщо два Podʼа в вашому кластері хочуть взаємодіяти, і вони обидва фактично працюють на одному й тому ж вузлі, використовуйте Політики внутрішнього трафіку Service, щоб утримувати мережевий трафік в межах цього вузла. Уникнення зворотного зв’язку через кластерну мережу може допомогти підвищити надійність, продуктивність (затримку мережі та пропускну здатність) або вартість.
СТАН ФУНКЦІОНАЛУ: Kubernetes v1.26 [stable]

Політика внутрішнього трафіку Service дозволяє обмежувати внутрішній трафік, маршрутизуючи його лише до endpoint у межах вузла, з якого походить трафік. Тут "внутрішній" трафік означає трафік, який виник з Podʼів у поточному кластері. Це може допомогти зменшити витрати та покращити продуктивність.

Використання політики внутрішнього трафіку Service

Ви можете увімкнути політику тільки для внутрішнього трафіку для Service, встановивши його .spec.internalTrafficPolicy в Local. Це вказує kube-proxy використовувати лише вузлові локальні endpoint для внутрішнього трафіку кластера.

У наступному прикладі показано, як виглядає Service, коли ви встановлюєте .spec.internalTrafficPolicy в Local:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  internalTrafficPolicy: Local

Як це працює

Kube-proxy фільтрує endpointʼи, до яких він виконує маршрутизацію, на основі налаштувань spec.internalTrafficPolicy. Коли вона встановлена в Local, розглядаються тільки вузлові локальні endpointʼи. Коли вона встановлена в Cluster (стандартно), або не встановлена взагалі, Kubernetes розглядає всі endpointʼи.

Що далі