Перехід від Endpoints до EndpointSlices у Kubernetes

З моменту виходу початкової альфа-версії EndpointSlices (KEP-752) у v1.15 та їх загальної доступності з v1.21, мережеві можливості Kubernetes поступово відходять від застарілого API Endpoints. Сучасні функції сервісів, такі як двохстекова мережа та вдосконалене розподілення трафіку, реалізуються виключно через EndpointSlices. Внаслідок цього всі проксі-сервіси, шлюзи в кластері та кастомні контролери були оновлені для роботи з ресурсами discovery.k8s.io/v1 EndpointSlice, а не з v1 Endpoints. На сьогоднішній день API Endpoints існує переважно для збереження зворотної сумісності з існуючими робочими навантаженнями та автоматизаційними сценаріями.
З версією Kubernetes 1.33 API Endpoints офіційно вважається застарілим. Будь-яка операція читання або запису з v1 Endpoints тепер викликає попередження про застарілість від API сервера, спонукаючи користувачів переходити до EndpointSlice API. Тим часом, KEP-4974 визначає плани щодо видалення вимоги до Endpoints controller з тестів на відповідність Kubernetes, оскільки більшість сучасних кластерів більше не покладаються на нього.
Згідно з політикою застарілості Kubernetes, тип Endpoints може залишатися в режимі тільки для читання або з попередженням безстроково. Однак користувачі з автоматизацією, CI/CD процесами чи контролерами, які все ще запитують або генерують Endpoints, повинні перейти на EndpointSlices, щоб уникнути майбутніх проблем, скористатися новими мережевими функціями та зменшити витрати під час виконання.
Примітки щодо міграції з Endpoints на EndpointSlices
Використання EndpointSlices замість Endpoints
Найзначніша зміна при використанні EndpointSlices полягає в тому, що один сервіс може відповідати кільком EndpointSlices. У той час як кожен сервіс з селектором генерує лише один об’єкт Endpoints, названий так само, як і сервіс.
$ kubectl get endpoints myservice
Попередження: v1 Endpoints застаріло у v1.33+; використовуйте discovery.k8s.io/v1 EndpointSlice
NAME       ENDPOINTS           AGE
myservice  10.180.3.17:443     2h
$ kubectl get endpointslice -l kubernetes.io/service-name=myservice
NAME                   ADDRESSTYPE   PORTS   ENDPOINTS         AGE
myservice-7vzhx        IPv4          443     10.180.3.17       35s
myservice-jcv8s        IPv6          443     2001:db8:123::5   35s
Як видно, двохстекові сервіси генерують два слайси — один для IPv4 і один для IPv6. Старий об’єкт Endpoints показує лише адреси основної сім’ї. Контролер EndpointSlice також розподіляє слайси за визначеннями портів і обмежує кожен слайс максимум до 100 кінцевих точок, щоб зменшити розмір об’єкта. Оскільки імена слайсів генеруються з унікальними суфіксами, споживачі повинні перераховувати слайси за міткою:
kubectl get endpointslice -l kubernetes.io/service-name=myservice
Нижче наведені ключові сценарії, в яких виникають кілька слайсів:
- Розділення IP-сімей: Кожен EndpointSliceможе містити лише одну сім’ю адрес. Отже, двохстекові сервіси генерують окремі слайси для IPv4 та IPv6.
- Зміни портів під час розгортання: Якщо ви вносите зміни, які модифікують порти контейнерів (наприклад, порт 80 → 8080), Kubernetes створить окремі слайси для старих і нових портів до завершення розгортання.
- Обмеження кількості кінцевих точок: Щоб уникнути створення великих об’єктів, контролер розподіляє кінцеві точки на кілька слайсів, як тільки їх кількість перевищує 100 адрес на слайс.
Генерація EndpointSlices замість Endpoints
Для контролерів або YAML-описів, які генерують дані про кінцеві точки, перехід на EndpointSlices є простим. Схема змінюється незначно — переходячи від subsets до масивів endpoints верхнього рівня з флагами conditions.ready для кожної кінцевої точки — і вимагає додавання мітки та addressType. Приклад:
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  generateName: myservice-
  labels:
    kubernetes.io/service-name: myservice
addressType: IPv4
endpoints:
  - addresses: ["10.180.3.17"]
    nodeName: node-4
    conditions:
      ready: true
  - addresses: ["10.180.5.22"]
    nodeName: node-9
    conditions:
      ready: true
  - addresses: ["10.180.6.6"]
    nodeName: node-8
    conditions:
      ready: false
ports:
  - name: https
    protocol: TCP
    port: 443
Ключові відмінності:
- Необхідно вказати addressType(IPv4абоIPv6).
- Мітка kubernetes.io/service-nameпов’язує слайс зі своїм сервісом.
- Кожен запис endpointsвключає умови для кожної кінцевої точки (готова/не готова), замінюючи окремі масивиaddressesтаnotReadyAddresses.
- Великі набори кінцевих точок автоматично розподіляються на кілька слайсів контролером, тому ручне розподілення не потрібне, якщо не реалізується кастомний контролер.
Врахування продуктивності
EndpointSlices зменшують споживання пам’яті та пропускної здатності API сервера, обмежуючи розмір об’єктів. Тестування від Kubernetes SIG-Network вказує на зменшення навантаження на події спостереження до 50% у великих кластерах (10,000+ кінцевих точок). Менші JSON-документи означають менше навантаження на CPU на kube-apiserver та нижчу затримку в kube-proxy і кастомних контролерах, які спостерігають за сервісами в масштабах.
Експериментальні тести показують, що в кластері з 5,000 вузлів з двохстековою архітектурою Kube-Proxy на основі EndpointSlice споживає приблизно на 30% менше CPU в порівнянні зі спостереженням за застарілими Endpoints, завдяки інкрементним оновленням та меншим розмірам списків. Крім того, функціональні можливості, такі як EndpointSliceProxying, можуть бути включені для поступового впровадження поліпшень проксі в середовищах з суворими вимогами до стабільності.
Найкращі практики міграції
- Аудит існуючих контролерів: Визначте будь-які кастомні контролери або сценарії, що використовують CoreV1().Endpoints(), та сплануйте оновлення доDiscoveryV1().EndpointSlices().
- Оновлення CRD та інструментів: Якщо ви керуєте кастомними ресурсами, що генерують кінцеві точки, додайте підтримку EndpointSliceта протестуйте під v1.33+ з увімкненими попередженнями.
- Управління функціональними можливостями: Переконайтеся, що функціональні можливості EndpointSliceтаEndpointSliceProxyingувімкнені на обох API сервері та контролері-менеджері в тестових кластерах перед розгортанням у продакшені.
- Поступове впровадження: Використовуйте двохстекові або мультіпортові тестові сервіси для перевірки поведінки розподілу слайсів та моніторингу метрик з kube-proxy та CNI плагінів.
Майбутні напрямки та дорожня карта
KEP-4974 передбачає остаточне видалення контролера Endpoints з тестів на відповідність та можливу деактивацію в kube-controller-manager. Хоча API об’єкт може залишатися безстроково для сумісності, утримувачі SIG-Network розглядають режим видалення Endpoints як приховану функціональну можливість, що додатково зменшить навантаження на CPU контролера-менеджера в масштабних кластерах. У майбутніх вдосконаленнях discovery.k8s.io/v1 передбачаються більш детальні topologyHints та розширена метадані кінцевих точок для інтеграцій з сервісними мережами.
З ростом впровадження Kubernetes у випадках використання на краю та в IoT, EndpointSlices закладають основи для ефективного виявлення сервісів у багатокластерному середовищі, дозволяючи федеративним контролерам агрегувати слайси з різних регіонів з мінімальними витратами. Організації, що планують майбутнє розширення, повинні завершити свою міграцію, щоб розблокувати ці вдосконалені мережеві можливості.