Сегодня ожидается выход очередной версии Kubernetes — 1.29. Среди главных изменений — бэкенд на основе nftables для kube-proxy, множественные CIDR для сервисов и функция QueueingHint, которая помогает решить, как повторно ставить поды в очередь. TaintManager стал отдельным контроллером, а список допустимых значений лейблов для метрики теперь можно настраивать динамически. Еще появился объект VolumeAttributesClass — он позволяет менять атрибуты тома после его заказа. Также стал доступен инструментарий для реализации структурированной auth-конфигурации, предусмотренный в KEP’е от «Фланта», и появилась нативная поддержка операции sleep для PreStop-хуков.

Для подготовки статьи использовалась информация из таблицы Kubernetes enhancements tracking, CHANGELOG-1.29, а также конкретные Issues, Pull Requests и Kubernetes Enhancement Proposals (KEPs).

Мы разбили все изменения на следующие разделы:

Внутри каждого раздела упорядочили изменения по уровню их готовности к использованию. Всего в новом релизе 49 изменений. Из них:

  • Alpha — 20 новых функций; 

  • Beta — 18 продолжают улучшаться;

  • Stable — 11 признаны стабильными.

Примечание

Мы сознательно не переводим названия фич на русский. Они в основном состоят из специальной терминологии, с которой инженеры чаще встречаются в оригинальной формулировке.

Узлы

Alpha-фичи

In-Place Update of Pod Resources 

#1287; KEP

Новая функция позволяет изменять запросы (resources requests) и лимиты (resources limits) ресурсов «на месте», то есть без перезапуска контейнеров. Подробнее — в обзоре Kubernetes 1.27.

Возвращение фичи в альфа-статус связано со значительным пересмотром планов реализации. Изменения в CRI вынесли в отдельный KEP и было решено ради простоты пока воздержаться от добавления политики RestartPod. Также были исправлены некоторые ошибки, оптимизирована производительность и добавлена поддержка Windows в вертикальное масштабирование.

cAdvisor-less, CRI-full Container and Pod Stats

#2371; KEP

Для сбора статистики о работающих контейнерах и подах преимущественно используются summary API и /metrics/cadvisor. За работу первого отвечает kubelet, второго — cadvisor

Метрик, поставляемых CRI API, в настоящее время недостаточно для заполнения всех полей любого из этих эндпоинтов, при этом часть их попадает в summary API. Это приводит к сложностям с выяснением происхождения метрик, дублированию работы cAdvisor и CRI и негативным последствиям для производительности. 

KEP дополняет реализацию метрик CRI, чтобы та удовлетворяла все статистические потребности Kubernetes. На базовом уровне задача разбивается на две части:

  • усовершенствование CRI API — добавление в него метрик, которые нужны для заполнения полей pod и container в summary API непосредственно из CRI;

  • улучшение реализации CRI — трансляция метрик, которые нужны для заполнения полей pod и container в эндпоинте /metrics/cadvisor.

Introducing Sleep Action for PreStop Hook 

#3960; KEP

KEP добавляет новое действие sleep для PreStop-хуков, которое определяет, на какое время контейнер должен приостановиться перед завершением работы. Это усовершенствование упрощает корректное (graceful) завершение работы контейнерами и в целом делает управление их жизненным циклом более удобным. Также оно позволяет нормально закрывать клиентские соединения во время завершения работы пода.

Пример конфигурации:

spec:
      containers:
      - name: nginx
        image: nginx:1.16.1
        lifecycle:
          preStop:
            sleep:
              seconds: 5
        readinessProbe:
          httpGet:
            path: /
            port: 80

На самом деле это очень комичное изменение. Раньше все делали exec и вызывали sleep внутри контейнера. А этот KEP позволяет делать sleep нативно на уровне kubelet. А нужно это упрощение, чтобы убрать бинарник sleep из контейнера.

Максим Набоких, лид платформы Deckhouse

Мотивация

В настоящее время Kubernetes поддерживает два типа действий для хуков PreStop: exec и httpGet. Хотя эти действия обеспечивают гибкость, часто приходится прибегать к кастомным решениям/скриптам, чтобы реализовать банальное sleep-ожидание. Встроенное действие sleep стало бы оптимальным решением для сценариев, в которых контейнеру необходима пауза перед завершением работы, например:

  • корректное высвобождение ресурсов контейнером и закрытие подключений;

  • плавное переключение балансировщиков нагрузки и сервис-мешей;

  • обеспечение буферного периода для внешних систем мониторинга и оповещения.

Support User Namespaces in pods 

#127; KEP

KEP добавляет пользовательские пространства имен. Это необходимо, чтобы иметь возможность запускать процессы в подах с user- и group-идентификаторами, отличными от идентификаторов на хосте. Другими словами, привилегированный процесс в поде будет непривилегированным на хосте. При попытке выйти за пределы контейнера такой процесс не сможет причинить значительного вреда хосту. Предложение полностью или частично закрывает ряд уязвимостей в области безопасности. Их перечень доступен в разделе «Мотивация» KEP’а.

В pod.Spec добавляется булево поле hostUsers. Если его значение true или не задано, тогда, как и раньше, используется пространство имен хоста. Если его значение false, для пода создается новый userns. По умолчанию поле не задано.

Kubelet Support for Image Filesystem being split

#4191; KEP

У Kubelet’а есть две файловые системы: Node и Image. Обычно они находятся на одном диске. Но иногда их нужно распределить на несколько дисков — отделить, например, writable-уровень от read-only-уровня. В этом случае данные kubelet’а и контейнера будут на одном диске, а образы — на другом. Плюс такого разделения в том, что образы, как правило, занимают много места, в то время как writable-слой обычно невелик.

В существующей реализации раздельных дисков контейнеры и образы должны храниться на одном и том же диске. В этом случае сборщик мусора сможет при необходимости их удалить. Чтобы успешно отделить writable-слой (контейнеры) от read-only-слоя (образы), необходимо соответствующим образом настроить сборку мусора и статистику. В противном случае это может привести к поломке kubelet’а. 

KEP дополняет kubelet — теперь тот будет работать, даже если: 

  • образы и контейнеры находятся на разных дисках; 

  • writeable-слой находится на том же диске, что и kubelet

  • образы находятся в отдельной файловой системе.

kubelet image GC after a maximum age 

#4210; KEP

В настоящее время сборка мусора для удаления образов запускается при превышении порогового значения использования диска (ImageGCLowThresholdPercent). Но в некоторых случаях могут пригодиться дополнительные условия, например максимальный возраст. Если образ длительное время не используется, он вряд ли будет использован снова. Точное значение возраста определяется для конкретного случая, например несколько недель.

Характерный кейс — кластеры с автоматическим обновлением. После обновления в кластере обычно остаются образы старого релиза. В итоге эти образы будут удалены при достижении порогового значения для использования диска, но до того момента они будут впустую занимать место на диске.

KEP добавляет в объект KubeletConfiguration опцию ImageMaximumGCAge, которая позволяет администратору указать время, по истечении которого неиспользуемые образы будут удаляться независимо от использования диска, а также соответствующий feature gate для включения этого поведения.

Support image pull per runtime class

#4216; KEP

Сегодня образы контейнеров в средах исполнения идентифицируются следующим образом:

  • по имени образа — ссылка на образ;

  • по дайджесту образа — обычно это криптографический хэш содержимого в SHA-256. 

Содержимое образа, на который ссылаются, представляет собой либо манифест образа, либо манифест индекса образа. Индекс образа обычно содержит список манифестов образов по платформам (linux, windows,...). Вот пример такого индекса. В случае ссылки на индекс образов используется логика сопоставления платформ, чтобы определить и извлечь из индекса соответствующего манифеста образ для платформы, на которой должен работать контейнер.

Например, в рантайме containerd для каждой платформы есть отдельный platform matcher (согласователь) по умолчанию. Он используется для выбора манифеста образа из индекса образов на основе ОС/платформы, на которой работает узел (Linux, Windows, Darwin и т. д.). В случае linux такой согласователь смотрит, чтобы хостовая ОС совпадала с гостевой и, опционально, чтобы совпадали их variant’ы. В то же время windows platform matcher требует точного совпадения версий ОС хоста и гостя (поле OSVersion в ImageSpec OCI используется в основном только для манифестов windows). Если манифест с таким точным совпадением найден, он запрашивается. Если нет, выдается ошибка.

Такое поведение желательно для изолированных контейнеров windows, работающих на той же версии ядра, на которой работает хост. Однако оно неоптимально для windows-контейнеров hyperV. Дело в том, что версия ОС хоста и образа UVM не обязательно должна совпадать. Например, образы контейнеров Windows Server 2019 могут работать внутри виртуальной машины Utility VM (UVM) на хосте с Windows Server 2022. Так как контейнер будет работать в UVM, должна быть возможность запрашивать образы для инстансов UVM, соответствующие платформе.

Проблему можно решить, если рантаймы контейнеров, CRI и kubelet будут ссылаться на образы не по имени/дайджесту (imageName/imageDigest), а по tuple (imageName/imageDigest, runtimeClass). В этом случае можно будет указать runtimeClass, на котором запускается конкретный образ. Тогда контейнерные рантаймы (после необходимых дополнений) смогут извлекать соответствующие манифесты из индексов образов. 

KEP описывает детальные изменения в дизайне и API, которые нужны kubelet’у и CRI, чтобы извлекать образы на базе опции runtimeClass. При этом функциональность не должна измениться, если пользователь не использует опцию runtimeClass для извлечения образов.

Beta-фичи

Decouple TaintManager from NodeLifecycleController 

#3902; KEP

KEP не предусматривает изменений в API, поэтому выпускается сразу в beta-версии.

NodeLifecycleController навешивает на нездоровые узлы, которые не готовы или без связи, taint’ы NoExecute, например Unreachable, NotReady. После этого TaintManager приступает к удалению работающих на этих узлах подов.

KEP отделяет TaintManager, который вытесняет (evict) поды на основе taint’ов, от NodeLifecycleController и превращает их в два отдельных контроллера:

  • NodeLifecycleController, который будет навешивать taint’ы на нездоровые узлы; 

  • TaintEvictionController, который будет удалять поды на узлах с NoExecute.

Такое разделение не только улучшает организацию кода, но и облегчает работу над TaintEvictionController или создание собственных eviction-реализаций на основе taint’ов.

Связанный с taint-менеджером код удаляется из controller/nodelifecycle/node_lifecycle_controller.go. Таким образом получается новый NodeLifecycleManager. Параллельно на основе controller/nodelifecycle/taint-manager.go создается контроллер верхнего уровня, управляемый kube-controller-manager.

Переключатель функциональности SeparateTaintEvictionController позволяет использовать новый TaintEvictionController или вернуться к старому контроллеру NodeLifecycleController.

Sidecar Containers

#753; KEP

KEP вводит поле restartPolicy в init-контейнеры, которое указывает на то, что init-контейнер является sidecar-контейнером. В этом случае kubelet будет запускать init-контейнеры с restartPolicy = Always в том же порядке, что и другие init-контейнеры. Но вместо того, чтобы дожидаться завершения их работы, он будет ждать завершения последовательности запуска контейнера.

Условие завершения последовательности запуска — успешное выполнение startup-пробы и завершение обработчика PostStart. Подробнее — в обзоре новых фич K8s 1.28.

Add support for a drop-in kubelet configuration directory 

#3983; KEP

KEP добавляет поддержку drop-in-директории для конфигов kubelet. Ее можно задать с помощью флага --config-dir, например /etc/kubernetes/kubelet.conf.d. По умолчанию флаг будет пустым, и если его не указать, то поддержка drop-in не будет включена. Синтаксис в файлах конфигурации должен быть такой же, как в kubelet.conf.

[KEP-3085] Add condition for sandbox creation (xposted from original issue)

#4138; KEP

Успешное создание песочницы пода является критической фазой его жизненного цикла. KEP добавляет условие PodReadyToStartContainers к статусу пода для индикации готовности песочницы. Подробнее в обзоре Kubernetes 1.25.

Add CDI devices to device plugin API 

#4009; KEP

KEP добавляет поле с ID устройств Container Device Interface (CDI) в AllocateResponse и тем самым расширяет API плагинов устройств. Оно дополняет существующие поля, такие как аннотации, и позволяет различным реализациям плагинов ссылаться на ресурсы однозначно, используя полные имена CDI-устройств.

Stable-фичи

Kubelet Resource Metrics Endpoint

#727; KEP

KEP реализует новый эндпоинт /metrics/resource в kubelet’е для отдачи метрик по основным ресурсам. Подробнее — в обзоре Kubernetes 1.14.

Приложения

Beta-фичи

Backoff Limit Per Index For Indexed Jobs 

#3850; KEP

Ранее для индексированных задач устанавливался общий лимит повторных попыток (backoff limit). При его достижении задача помечалась как Failed, а занятые ей ресурсы высвобождались, включая индексы, которые еще не завершили свою работу. Такая реализация не охватывала ситуацию, когда рабочая нагрузка реально параллельна — все индексы независимы.

KEP позволяет задавать число повторных попыток (поле .spec.backoffLimitPerIndex) для каждого индекса в индексированных задачах, тем самым дополняет API Job. Также поле .spec.maxFailedIndexes контролирует максимальное количество сбойных индексов. При превышении этого числа задание помечается как Failed и его выполнение прекращается.

Также KEP дополняет политику PodFailurePolicy новым действием — FailIndex. Оно позволит индексу завершить свою работу до достижения backoff limit’а на индекс.

Allow for recreation of pods once fully terminated in the job controller

#3939; KEP

KEP вводит новое поле в API Job. Оно позволит пользователям указывать, хотят ли они, чтобы поды на замену стартовали сразу после того, как старые поды обретают статус terminating (обычное поведение), или только после полного завершения работы старых подов (новое поведение). Также добавляется поле Status.terminating для отслеживания количества подов со статусом terminating. Подробнее — в обзоре Kubernetes 1.28.

Stable-фичи

Track Ready Pods in Job status

#2879; KEP

KEP добавляет в API поле Job.status.ready, чтобы отслеживать все поды в состоянии готовности (Ready). Новая фича избавляет от необходимости следить за обновлением состояния отдельных подов.

Хранилище

Alpha-фичи

Kubernetes VolumeAttributesClass ModifyVolume

#3751; KEP

Облачные провайдеры и поставщики систем хранения предлагают тома, которые позволяют задавать параметры качества IO-обслуживания (Performance): IOPS или пропускная способность. Также эти тома позволяют настраивать их по мере эксплуатации рабочих нагрузок (1, 2, 3, 4, 5, 6). Эти параметры можно указать при инициализации, однако API Kubernetes не умеет их изменять. Изменить можно только объем через API-расширения тома. KEP дополняет API Kubernetes Persistent Volume, позволяя управлять этими параметрами тома динамически.

В API Kubernetes добавляется новый объект VolumeAttributesClass, новый admission-контроллер и контроллер защиты VAC.

Причина, по которой нельзя использовать StorageClass.parameters, заключается в том, что StorageClass на данный момент неизменяем (immutable). Идея состоит в том, чтобы внедрить VolumeAttributesClass с параметрами. Эти параметры по-прежнему неизменяемы внутри VolumeAttributesClass, однако имя VolumeAttributesClass в PVC может быть изменено. Это позволяет изменять параметры, которые представляют атрибуты тома, после его создания.

Пример ресурса VolumeAttributesClass с параметрами:

// Example VolumeAttributesClass
apiVersion: storage.k8s.io/v1alpha1
kind: VolumeAttributesClass
metadata:
  name: silver
parameters:
  iops: "500"
  throughput: "50MiB/s"

Beta-фичи

PersistentVolume last phase transition time 

#3762; KEP

KEP добавляет новое поле PersistentVolumeStatus, которое содержит временную метку последнего изменения фазы PersistentVolume.

Некоторые пользователи столкнулись с потерей данных при использовании политики Delete и вернулись к более безопасной политике Retain. При использовании политики Retain все тома, которые хранятся, но остаются невостребованными, имеют фазу Released. Со временем такие тома накапливаются. Приходится вручную удалять старые тома, основываясь на времени их последнего использования — когда том перешел в фазу Released.

При этом к задаче можно подойти более глобально и просто сохранять временную метку перехода тома в любую фазу, а не только в Released. Это позволит любому пользователю, в том числе и тестам производительности, измерять время, например, между PV Pending и Bound. Еще такая метка может пригодиться для метрик и SLO.

Stable-фичи

ReadWriteOncePod PersistentVolume Access Mode

#2485; KEP

Режим доступа ReadWriteOncePod работает для PersistentVolumes, для которых доступ нужно ограничить единственным подом на одном узле. Для сравнения: существующий режим ReadWriteOnce (RWO) ограничивает доступ к узлу, но разрешает одновременный доступ к этому узлу из нескольких подов на этом узле.

Introduce nodeExpandSecret in CSI PV source

#3107; KEP

KEP добавляет новое поле secretRef в запрос nodeExpandVolume, который kubelet отправляет CSI-драйверу. Оно позволяет передавать секреты в RPC-запросах к CSI-драйверам при расширении емкости томов на узле. Подробнее — в обзоре Kubernetes 1.25.

Сеть

Alpha-фичи

nftables kube-proxy backend

#3866; KEP

Реализация kube-proxy по умолчанию в Linux в настоящее время основана на iptables. Эта технология, начиная с вышедшего в 2001 году ядра 2.4, выступала основной системой фильтрации и обработки пакетов в ядре Linux. Однако проблемы с производительностью iptables привели к разработке преемника — nftables. Впервые он появился в 2014 году в ядре 3.13 и с тех пор постоянно обрастает новыми функциями. В итоге он постепенно превращается в полноценную замену iptables. В настоящее время разработка iptables практически прекращена, новые функции внедряются в основном в nftables.

Данный KEP предлагает создать новый официальный поддерживаемый бэкенд nftables для kube-proxy. В перспективе он сможет заменить iptables и ipvs и станет режимом kube-proxy по умолчанию в Linux. Замена и вывод из эксплуатации старых бэкендов пройдут в рамках отдельного KEP’а в будущем.

Авторы отмечают, что ни одна из существующих реализаций kube-proxy на базе nftables (kube-nftlb, nfproxy, kpng's nft backend) не кажется подходящей ни для прямого внедрения, ни для использования в качестве отправной точки (см. раздел Notes/Constraints/Caveats). Подробнее об их подходе к разработке нового бэкенда можно почитать в разделе Design Details.

Make Kubernetes aware of the LoadBalancer behaviour

#1860; KEP

Различные реализации kube-proxy привязывают внешние IP-адреса LoadBalancer-сервиса к каждому узлу — iptables создает правила для перенаправления пакетов непосредственно на сервис, ipvs привязывает IP к одному интерфейсу на узле. Это позволяет:

  • перенаправлять трафик подов, направляемый на IP LoadBalancer’а и сервис, минуя балансировщик нагрузки для оптимизации пути;

  • маршрутизировать IP-адрес на нужный сервис в случае, когда LB отправляет пакеты с IP-адресом назначения, равным IP-адресу LB.

Но такое поведение связано с рядом проблем:

  • Некоторые облачные провайдеры, например Scaleway и Tencent Cloud, используют внешний IP LB или приватный IP в качестве IP-адреса источника при отправке пакетов на кластер. Для kube-proxy в ipvs-режиме это не подходит, так как IP привязан к интерфейсу и healthcheck’и от LB не возвращаются.

  • Часть облачных провайдеров, например DigitalOcean и Scaleway, реализуют дополнительные возможности на уровне LB (терминация TLS, протокол PROXY и т. д.). Обход LB означает, что эти функции не обрабатывают пакеты, которые поступают на сервис, что приводит к ошибкам в протоколах.

KEP добавляет новое поле (ipMode) в поле loadBalancer в статусе сервиса. С его помощью kube-proxy будет решать, когда не привязывать внешний IP LoadBalancer’а к узлу как в режиме ipvs, так и в режиме iptables. Значение VIP по умолчанию будет означать обычное поведение, если оно не задано для инстанса. А Proxy будет пускать трафик через LoadBalancer.

Multiple Service CIDRs

#1880; KEP

Сервисы — абстрактный способ подключения к приложению, которое работает на наборе подов. Некоторые типы сервисов, например ClusterIP, NodePort и LoadBalancer, используют виртуальный IP-адрес ClusterIP, внутренний для кластера (cluster-scoped). Каждый ClusterIP сервиса должен быть уникальным в пределах кластера. Попытка создать сервис с ClusterIP, который уже занят, приведет к ошибке.

Текущая реализация логики выделения IP-адресов для сервисов имеет ряд ограничений:

  • Нельзя изменять или увеличивать диапазоны IP-адресов, которые назначаются сервисам. Это приводит к проблемам при наличии перекрывающихся сетей или исчерпании доступных IP-адресов в кластере.

  • Диапазон IP-адресов сервиса не раскрывается (expose), поэтому другие компоненты кластера не могут его использовать.

  • Конфигурирование осуществляется для каждого apiserver’а. Единый консенсус отсутствует, и разные apiserver’ы могут конкурировать и удалять чужие IP.

  • Логика распределения несовершенна. Возможна утечка — сокращение числа адресов ClusterIP (kubernetes/kubernetes#87603).

  • Размер CIDR: для IPv4 размер префикса ограничен /12, но для IPv6 он может быть /112 или меньше. Такое ограничение мешает пользователям IPv6, поскольку стандартная и минимально рекомендуемая длина префикса — /64.

  • Переключатель функциональности, реализованный в KEP-3070 (см. обзор Kubernetes 1.24), позволяет использовать только ограниченный зарезервированный диапазона IP-адресов для сервиса (kubernetes/kubernetes#95570).

KEP реализует новую логику работы аллокатора на базе двух новых объектов API: ServiceCIDR и IPAddress и создает новые ServiceCIDR, тем самым позволяет динамически увеличивать количество доступных IP-адресов для сервиса.

Новый аллокатор сможет «автомагически» потреблять IP-адреса из любого доступного ServiceCIDR. Эту модель можно сравнить с добавлением дополнительных дисков в систему хранения данных для увеличения ее емкости.

Чтобы упростить модель, сделать ее обратно совместимой и избежать конфликтов с другими API, вводятся следующие ограничения:

  • ServiceCIDR будет неизменяемым (immutable) после создания, при этом в beta-версии это может измениться.

  • ServiceCIDR может быть удален, только если с ним не связан ни один Service IP. За этим следит финализатор.

  • Могут существовать перекрывающиеся ServiceCIDR.

  • Apiserver будет периодически убеждаться в существовании ServiceCIDR по умолчанию, чтобы охватить флаги CIDR-сервисов и сервис kubernetes.default.

  • Любой IPAddress из тех, которые есть в кластере, должен принадлежать диапазону CIDR сервиса, задаваемому ServiceCIDR.

  • Ожидается, что любой сервис с назначенным ClusterIP всегда будет иметь связанный с ним объект IPAddress.

  • Удаляемый ServiceCIDR не может быть использован для выделения новых IP-адресов.

Перекрывающиеся ServiceCIDR объединяются в памяти, IPAddress берется не из конкретного объекта ServiceCIDR, а из любого ServiceCIDR, включающего данный IP.

Deprecate status.nodeInfo.kubeProxyVersion field

#4004; KEP

Предлагается признать поле kubeProxyVersion в NodeStatus устаревшим (deprecated). Оно использовалось облачным провайдером GCP до версии 1.28 для устаревшего встроенного cloud-provider-gcp (#117806), а до версии 1.29 — для внешнего cloud-provider-gcp (#533). Поле может использоваться и другими компонентами, поэтому авторы на всякий случай предусмотрели соответствующий переключатель функциональности DisableNodeKubeProxyVersion.

Beta-фичи

Kube-proxy improved ingress connectivity reliability 

#3836; KEP

Контроллер сервисов в менеджере облачных контроллеров Kubernetes (Kubernetes cloud controller manager, KCCM) настраивает LoadBalancer и соответствующую проверку работоспособности (health check, HC) по событиям, которые связаны с сервисом. Затем эту проверку LoadBalancer использует для определения инстансов — кандидатов на балансировку трафика. Для некоторых облачных провайдеров (GCP) KCCM настраивает HC на получение этой информации через прокси-сервер Kubernetes. 

KEP реализует механизм разгрузки соединений (connection draining) для terminating-узлов и добавляет путь /livez в сервер проверки работоспособности kube-proxy (proxier_health.go) (подробнее — в обзоре K8s 1.28). Также планируется выпустить рекомендации для поставщиков облачных услуг с перечнем более эффективных способов проверки работоспособности кластеров Kubernetes.

Примечание: KEP затрагивает только kube-proxy, так как это единственный сервисный прокси, который находится в ведении проекта Kubernetes.

Field status.hostIPs added for Pod 

#2681; KEP

KEP добавляет поле status.hostIPs и вносит необходимые изменения в Downward API — позволяет контейнерам получать информацию о себе или кластере без использования клиента Kubernetes или сервера API.

Поле status.hostIP в Downward API хранит существующий IP-адрес пода. Новое поле status.hostIPs будет содержать список IP-адресов, выделенных хосту. Потребность в этом возникла из-за того, что новый API пода обзаведется рядом структур для дополнительных IP-адресов.

Kubelet будет возвращать status.hostIPs в виде разделенной запятыми строки.

Cloud Dual-Stack --node-ip Handling

#3705; KEP

KEP вносит изменения, позволяющие администраторам кластеров, в которых используются внешние облачные ресурсы, гибко менять IP-адреса узлов, назначаемые облаком:

  • переопределять IP-адрес узла в dual-stack-кластере, и это не будет приводить к тому, что узел станет single-stack;

  • переопределять оба IP-адреса узла в dual-stack-кластере;

  • изменять порядок IP-адресов узлов в dual-stack-кластере — задавать первичность IPv6 или IPv4;

  • переключать узлы в single-stack-режим, когда поставщик облачных услуг предлагает dual-stack-режим, без необходимости указывать конкретный IP-адрес узла в формате IPv4 или IPv6.

Подробности — в обзоре Kubernetes 1.27.

Stable-фичи

Remove transient node predicates from KCCM's service controller

#3458; KEP

Контроллер сервисов в KCCM добавляет и удаляет узлы из набора узлов LoadBalancer’ов в следующих случаях:

  1. Когда на узел навешивается или с узла удаляется taint ToBeDeletedByClusterAutoscaler

  2. Когда узел переходит в состояние Ready или NotReady.

Второй случай относится только к сервисам с externalTrafficPolicy: Cluster. При этом в обоих случаях удаление узла из набора узлов LoadBalancer’ов приведет к тому, что все соединения на этом узле будут мгновенно прерваны. 

Подобное поведение неоптимально для узлов в переходном состоянии готовности или завершающих свою работу и выглядит как ошибка. Причина этого — в таких случаях соединениям не разрешается разрываться, даже если LoadBalancer предоставляет такую возможность.

KEP предусматривает прекращение синхронизации набора узлов LoadBalancer’ов в таких случаях. Для удобства в систему интегрирован feature gate StableLoadBalancerNodeSet.

Reserve nodeport ranges for dynamic and static allocation 

#3668; KEP

KEP развивает идею KEP-3070 (подробнее — в обзоре нововведений Kubernetes 1.24) и помогает избежать конфликтов при резервировании портов для сервисов типа NodePort. Подробнее — в обзоре нововведений Kubernetes 1.27.

API

Alpha-фичи

Transition from SPDY to WebSockets

#4006; KEP

KEP предлагает перейти с SPDY/3.1 на WebSockets для kubectl exec, kubectl attach и kubectl cp в части взаимодействия между kubectl и сервером API. Также предлагается расширить участок, на котором коммуникация ведется по протоколу WebSockets от API Server’а до kubelet’а. После этого между kubectl и Kubelet’ом будет происходить потоковая передача данных по WebSockets, проксируемая через API Server

Некоторые клиенты Kubernetes взаимодействуют с сервером API с помощью двунаправленного потокового протокола вместо стандартного механизма HTTP-запросов и ответов. Это позволяет клиенту и серверу обмениваться данными многократно. Например, команды kubectl exec и kubectl attach, которые выигрывают от такого протокола. А kubectl cp построена на основе примитивов kubectl exec, поэтому также использует потоковую передачу. В настоящее время для этих команд используется устаревший SPDY/3.1.

В рамках KEP’а предлагается:

  • добавить в kubectl WebSocketExecutor, который реализует WebSocket-клиент с использованием новой версии подпротокола (v5.channel.k8s.io), и создать FallbackExecutor для решения проблемы несовпадения версий клиент/сервер. FallbackExecutor сначала будет пытаться установить соединение с помощью WebSocketExecutor. Если не получится сделать это, он будет возвращаться к традиционному SPDYExecutor. Примечание: такой механизм может потребовать двух запросов/ответов вместо одного;

  • модифицировать поток данных SPDY между kubectl и API Server’ом путем условного добавления StreamTranslatorProxy на сервере API. Обработчик будет делегировать запросы о переходе на WebSocket с протоколом RemoteCommand: v5.channel.k8s.io StreamTranslatorProxy вместо UpgradeAwareProxy. Этот транслирующий прокси будет терминировать WebSocket-соединение и демультиплексировать потоки для передачи данных в SPDY-соединение.

Схема StreamTranslatorProxy
Схема StreamTranslatorProxy

Declarative Validation

#4153; KEP

KEP позволяет объявлять правила валидации с помощью IDL-тегов в файлах types.go, которые определяют нативные типы API Kubernetes. Пример:

// staging/src/k8s.io/api/core/v1/types.go

// +validationRule="!self.hostNetwork || self.containers.all(c, c.containerPort.all(cp, cp.hostPort == cp.containerPort))"
type PodSpec struct {
  Containers []Container `json:...`
}

type Container struct {
  // ...

  Ports []ContainerPort `json:...`

  // ...
}

type ContainerPort struct {
  // ...

  // ...
  //
  // +minimum=1
  // +maximum=65535
  HostPort int32 `json:...`

  // ...
  //
  // +minimum=1
  // +maximum=65535
  ContainerPort int32 `json:...`

  // ...
}

В примере выше +validationRule, +minimum и +maximum — IDL-теги. Kube-apiserver будет использовать декларативные правила валидации для проверки API-запросов. Также они будут включаться в опубликованный OpenAPI:

// Pod Spec
"openAPIV3Schema": {
  "type": "object",
  "x-kubernetes-validations": [
    {
      "rule": "!self.hostNetwork || self.containers.all(c, c.containerPort.all(cp, cp.hostPort == cp.containerPort))"
    }
  ],
}

...

// Container Port
"openAPIV3Schema": {
  "type": "object",
  "properties": {
    "hostPort": {
      "minimum": 1,
      "maximum": 65535
      ...
    }
    "containerPort": {
      "minimum": 1,
      "maximum": 65535
      ...
    }
  }
}

Beta-фичи

CRD Validation Ratcheting

#4008; KEP

В нынешнем виде валидация полей, которые не менялись, выступает препятствием для авторов CRD и разработчиков Kubernetes. KEP добавляет переключатель функциональности (feature flag) CRDValidationRatcheting. Если флаг установлен, обновления custom resources, которые не прошли валидацию, будут завершаться успешно. Это будет происходить, когда ошибки валидации связаны с ключевыми путями, которые не менялись (пример см. в обзоре Kubernetes 1.28).

CEL for Admission Control

#3488; KEP

KEP предлагает новый способ admission-контроля без необходимости задействовать вебхуки. Это базируется на #2876 (см. обзор Kubernetes 1.27).

В группу admissionregistration.k8s.io вводится новый ресурс ValidatingAdmissionPolicy. Он содержит CEL-выражения для валидации запросов и объявляет, как политика может быть сконфигурирована для использования. Подробнее — в обзоре Kubernetes 1.26.

Stable-фичи

Priority and Fairness for API Server Requests

#1040; KEP

KEP реализует продвинутую систему приоритетов для более тонкого контролирования ограничения запросов к API-серверу. В ней определяются разные типы запросов через объекты FlowSchema и им назначаются ресурсы через объекты RequestPriority. Пример в обзоре Kubernetes 1.18.

Support paged LIST queries from the Kubernetes API

#365; KEP

KEP, представленный в Kubernetes 1.8, наконец переходит в статус стабильного. Он реализует в API новый подход к выдаче ответов на запросы LIST — APIListChunking. Теперь они разбиваются на небольшие куски и выдаются клиенту в соответствии с указанным им лимитом.

CRD Validation Expression Language

#2876; KEP

KEP реализует упрощенный вариант проверки пользовательских ресурсов в CRD (Custom Resource Definition). Теперь, помимо вебхуков, для описания правил можно использовать скриптовый язык CEL. Подробнее — в обзоре Kubernetes 1.23.

Аутентификация

Alpha-фичи

Structured Authorization Configuration

#3221; KEP

Сегодня kube-apiserver позволяет настраивать цепочку авторизации с помощью набора флагов командной строки вида --authorization-*. При этом администраторы кластеров могут включить в цепочку авторизации только один вебхук, используя флаг --authorization-modes. В текущей реализации нет возможности указать несколько вебхуков для авторизации пользователей. KEP позволяет передавать apiserver’у структурированный файл конфигурации. С его помощью можно решить проблемы, которые раньше были нерешаемы. Что появилось:

  • возможность задавать несколько авторизационных вебхуков;

  • новые опции для авторизационных вебхуков;

  • hot reload (горячая перезагрузка) конфигурации без перезагрузки apiserver’а.

Пример конфигурации с описанием всех полей доступен в разделе Design Details KEP’а.

ClusterTrustBundles (previously Trust Anchor Sets)

#3257; KEP

В настоящее время API-группа certificates.k8s.io предоставляет гибкий подключаемый механизм для запросов сертификатов рабочими нагрузками в кластере. Но сертификаты имеют смысл, только если они привязаны к какому-либо CA. Однако в Kubernetes отсутствует стандартизированный механизм, который позволяет доставлять сертификаты в контейнеры (поды).

KEP реализует объект certificates.k8s.io ClusterTrustBundle для использования в пределах кластера. Он позволяет удостоверяющим центрам доставлять сертификаты до рабочих нагрузок.

Также представлен новый тип тома pemTrustAnchors, который позволяет смонтировать сертификаты внутрь тома.

Structured Authentication Config 

#3331; KEP

KEP от «Фланта» реализует структурированную конфигурацию для аутентификации, которая обладает рядом весомых преимуществ по сравнению с традиционным подходом. Он поддерживает любые JWT-совместимые токены, динамическое изменение конфигурации, одновременную работу с несколькими провайдерами аутентификации и Common Expression Language. Подробнее о KEP’е — в заметке.

Bound service account token improvements

#4193; KEP

KEP дополняет генерируемые токены при обработке вызова TokenRequest create kube-apiserver-функциями для автоматического включения name и UID узла, с которым ассоциирован под (через spec.nodeName).

Так как в этой области кода уже есть под, который содержит имя узла, необходимо пробросить геттер (get) для объектов Node на уровень хранения TokenRequest. Это нужно, чтобы можно было получать UID узла аналогично тому, как это делается для объектов Pod и Secret.

Beta-фичи

Reduction of Secret-based Service Account Tokens

#2799; KEP

KEP предлагает изменить цикл управления служебными учетными записями в контроллере токенов так, чтобы Secret’ы для них не создавались автоматически. Еще он предупреждает об использовании автоматически создаваемых токенов служебных учетных записей на основе Secret’ов и рекомендует пользователям применять API TokenRequest или токены, создаваемыми вручную.

Stable-фичи

KMS v2 Improvements

#3299; KEP

KEP предусматривает поэтапное улучшение сервиса KeyManagementService, который используется для шифрования данных etcd по схеме envelope encryption. Предполагается:

  • обеспечить частично автоматизированную ротацию ключей на актуальный ключ без перезапуска сервера API;

  • повысить надежность проверки работоспособности KMS-плагинов;

  • улучшить наблюдаемость envelope-операций между kube-apiserver, KMS-плагинами и KMS.

CLI

Beta-фичи

Improve kubectl plugin resolution for non-shadowing subcommands

#3638; KEP

KEP позволяет использовать внешние плагины в качестве подкоманд встроенных команд, если подкоманда не существует. При попытке выполнить неизвестную подкоманду kubectl будет искать ее во внешних плагинах со структурой имени, аналогичной текущему механизму поиска плагинов, например kubectl-create-foo. Пример:

$ kubectl create foo

После ввода этой команды запустится плагин kubectl-create-foo.

kubectl delete: Add interactive(-i) flag

#3895; KEP

KEP вводит интерактивный режим для команды kubectl delete, чтобы защитить администраторов кластера от случайного безвозвратного удаления критических ресурсов.

При добавлении флага --interactive/-i в команду kubectl delete все ресурсы, которые планируется удалить, будут показываться пользователю в виде превью. Если набрать y, пользователь подтвердит удаление. При этом n или другое значение, отличное от y, прервет процесс удаления, а команда вернет сообщение с нулевым кодом выхода.

Планировщик

Alpha-фичи

Introduce MatchLabelKeys to Pod Affinity and Pod Anti Affinity

#3633; KEP

KEP вводит дополнительные поля MatchLabelKeys и MismatchLabelKeys в PodAffinityTerm. Это позволит пользователям контролировать применимость PodAffinity или PodAntiAffinity для подов в дополнение к существующему LabelSelector’у.

Во время скользящего обновления рабочей нагрузки в кластере — в зависимости от стратегии обновления — могут сосуществовать старые и новые версии подов. Поскольку планировщик не в состоянии отличить старую версию от новой, он не может правильно соблюсти API-семантику PodAffinity и PodAntiAffinity во время обновления. В худшем случае новая версия пода не будет запланирована. Вот три ссылки на issues, в которых описывается подобная ситуация: 1, 2, 3.

При этом в кластере, который простаивает, результат планирования будет неоптимальным, так как некоторые узлы, отвечающие требованиям, будут отсеяны ошибочно.

Эта же проблема относится и к другим директивам планирования. Например, MatchLabelKeys была введена в topologyConstaint в KEP-3243.

Подробности реализации

При создании пода kube-apiserver получит лейблы из лейблов пода по ключу в matchLabelKeys или mismatchLabelKeys и объединит их с labelSelector PodAffinityTerm в зависимости от поля:

  • matchLabelKeys: key in (value) объединяется с labelSelector;

  • mismatchLabelKeys: key notin (value) объединяется с labelSelector.

Например, при создании следующего пода:

apiVersion: v1
kind: Pod
metadata:
  name: sample
  namespace: sample-namespace
  labels:
    tenant: tenant-a
...
  affinity:
    podAntiAffinity:  
      requiredDuringSchedulingIgnoredDuringExecution:
      - mismatchLabelKeys:
          - tenant
        labelSelector:
          matchExpressions:
          - key: tenant
            operator: Exists
        topologyKey: node-pool

kube-apiserver изменяет labelSelector следующим образом:

affinity:
  podAntiAffinity:  
    requiredDuringSchedulingIgnoredDuringExecution:
      - mismatchLabelKeys:
          - tenant
        labelSelector:
          matchExpressions:
          - key: tenant
            operator: Exists
+         - key: tenant
+           operator: NotIn
+           values: 
+             - tenant-a
        topologyKey: node-pool

Beta-фичи

Per-plugin callback functions for accurate requeueing in kube-scheduler

#4247; KEP

KEP базируется на KEP-3063 (из обзора Kubernetes 1.26) и добавляет в планировщик функцию QueueingHint. Она позволяет получать предложения о том, как повторно ставить поды в очередь от каждого плагина. При этом будет сокращаться количество бесполезных повторных попыток и тем самым повышаться пропускная способность планировщика. При этом попытка планирования осуществляется, только если высока вероятность ее успеха.

Кроме того, возможность пропускать выдержку (backoff) в соответствующих случаях улучшает время планирования подов с динамическим распределением ресурсов.

Разное

Beta-фичи

Metric cardinality enforcement

#2305; KEP

Метрики с неограниченными измерениями могут вызывать проблемы с памятью в инструментируемых компонентах. KEP добавляет возможность динамически настраивать список допустимых значений лейблов для метрики во время работы.

Removing In-Tree Cloud Providers

#2395; KEP

Цель KEP’а — удалить из репозитория k8s.io/kubernetes специфичный для облачных провайдеров код с минимальными неудобствами для конечных пользователей и разработчиков. Для этого будут предприняты следующие шаги:

  • Весь код в k8s.io/kubernetes/pkg/cloudprovider/providers/<provider> будет перемещен в k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/<provider>/. Для этого будет необходимо удалить все внутренние зависимости для каждого облачного провайдера в k8s.io/kubernetes.

  • Переход на сборку/релиз CCM из внешних репозиториев (k8s.io/cloud-provider-<provider>) с возможностью импорта старых провайдеров из k8s.io/legacy-cloud-providers/<provider>. Это позволит cloud-controller-manager’у выбирать между старым in-tree-поведением (по соображениям совместимости) или создать новую реализацию провайдера. На этом этапе разработка облачных провайдеров in-tree по-прежнему ведется в k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/<provider>.

  • Удаление всего кода в k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers и перенос разработки в k8s.io/cloud-provider-<provider>. Внешние репозитории облачных провайдеров по-прежнему смогут импортировать k8s.io/legacy-cloud-providers, но они больше не будут импортироваться из основных компонентов в k8s.io/kubernetes.

Stable-фичи

Kubernetes Component Health SLIs

#3466; KEP

KEP позволяет отправлять данные SLI в структурированном виде и последовательно. Это происходит таким образом, чтобы агенты мониторинга могли использовать эти данные с более высокими интервалами очистки и создавать SLO и алерты на основе этих SLI. Подробнее — в обзоре Kubernetes 1.26.

Устаревшие и удаленные фичи

Ниже приведен список фич, которые признаны устаревшими в Kubernetes 1.29.

Удаленные версии API

Удалена версия flowcontrol.apiserver.k8s.io/v1beta2 из FlowSchema и PriorityLevelConfiguration.

Устаревшие примитивы — перейти на альтернативу до выхода следующего релиза

В рамках подготовки к его удалению в будущем релизе поле .status.kubeProxyVersion для объектов Node помечено как устаревшее. Это поле не является точным и устанавливается kubelet’ом, который не знает версию kube-proxy, а также запущен kube-proxy или нет.

Перед обновлением рекомендуем ознакомиться с CHANGELOG’ом.

P. S.

Читайте также в нашем блоге:

Комментарии (1)


  1. zolti
    13.12.2023 14:34

    Спасибо за материал.