Сегодня официально выпустили новую версию Kubernetes — 1.35. Среди главных нововведений — декларирование поддерживаемых фичей узлами, возможность запускать поды в сети хоста, одновременно изолируя с помощью пользовательских пространств имён, более безопасный способ передачи токенов сервисных аккаунтов драйверам CSI, проксирование запросов к API-серверам, групповое планирование подов и перевод контроллера маршрутов на модель на основе watch.

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

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

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

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

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

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

Примечание

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

Узлы

Alpha-фичи

Node Declared Features (formerly Node Capabilities)

#5328; KEP

KEP-5328 вводит механизм декларируемых функций, благодаря которому узлы смогут сами сообщать о доступных экспериментальных (т. е. закрытых переключателями функциональности) фичах в Kubernetes. Это поможет планировщику избежать проблем, связанных с «расползанием» версий (version skew), когда в старых версиях новые фичи могут быть недоступны. 

В статусе узла появляется новое поле declaredFeatures, которое заполняет сам kubelet. Планировщик и admission-контроллеры используют его, чтобы запланировать под на узел, который его поддерживает.

Сам механизм подчиняется строгим правилам, которые обеспечивают его надёжность и актуальность данных. Главная идея в том, что эти фичи не зафиксированы как постоянные атрибуты, а существуют лишь пока kubelet подтверждает их доступность.

Чтобы избежать ситуации, когда поды застревают в состоянии Failed, kubelet определяет полный список доступных на узле фичей во время начальной загрузки (bootstrap sequence). Список фичей пополняется автоматически и возвращается в исходное состояние при попытке ручного редактирования пользователем или контроллером. Он не меняется от запуска до следующей перезагрузки, выступая «единственным источником истины» для функций, декларируемых kubelet’ом, и обеспечивая согласованность для планировщика.

Пример

Функция изменения размера подов «на месте» (In-place Pod resizing) позволяет менять запросы и лимиты CPU и памяти у контейнера, не пересоздавая сам под. Но под может попасть на старый узел, где не поддерживается, к примеру, in-place-изменение размера для подов с классом сервиса Guaranteed. В этой ситуации API-запрос на изменение ресурсов у работающего пода будет отклонён. Если же узел поддерживает новую фичу, то в спецификации пода появится примерно такая запись:

declaredFeatures:
  - GuaranteedQoSPodCPUResize

Restart all containers on container exits

#5532; KEP

KEP-5532 развивает и дополняет функциональность, представленную в KEP-5307. Предыдущий KEP предложил механизм правил restartPolicy для отдельных контейнеров, позволяя kubelet перезапускать их на основе exit-кодов. Текущее улучшение распространяет его на уровень пода. Теперь можно инициировать перезапуск всех контейнеров в поде, а не только сбойного, основываясь на его коде завершения.

При перезапуске история статусов контейнеров полностью сохраняется, а счётчики перезапусков корректно инкрементируются как для отдельных контейнеров, так и для всего пода. Действие выполняется «по месту»: IP-адрес, sandbox и подключённые тома сохраняются, в то время как все init- и основные контейнеры запускаются с нуля. При этом если для пода установлен restartPolicy: Never и один из init-контейнеров аварийно завершается после срабатывания RestartAllContainers, весь под будет помечен как Failed.

Пример

apiVersion: v1
kind: Pod
metadata:
  name: my-ml-worker
spec:
  restartPolicy: Never
  initContainers:
  - name: setup-envs
    image: setup
  - name: watcher-sidecar
    image: watcher
    restartPolicy: Always
    restartPolicyRules:
    - action: RestartAllContainers
      onExit:
        exitCodes:
          operator: In
          values: [88] # Конкретный exit-код, указывающий, что под нужно перезапустить.
  containers:
  - name: main-container
    image: training-app

DRA: Handle extended resource requests via DRA Driver

#5004; KEP

KEP-5004 перебрасывает мост между привычными расширенными ресурсами (Extended Resources) и новым, более гибким фреймворком Dynamic Resource Allocation (DRA). Его главная цель — сделать переход на DRA плавным и безболезненным.

Администратор кластера теперь может указать в спецификации DeviceClass новое поле extendedResourceName через присвоение ему имени знакомого расширенного ресурса, например example.com/gpu. Так Kubernetes поймёт, что запросы на данный ресурс могут быть удовлетворены с помощью устройств, управляемых через DRA.

Если пользователь запросит такой ресурс в спецификации пода, планировщик Kubernetes самостоятельно создаст специальный объект ResourceClaim для внутреннего отслеживания выделенных ресурсов, чем избавит пользователя от необходимости создавать его вручную.

Чтобы kubelet на узле знал, какому именно контейнеру передать выделенное устройство, планировщик запишет необходимую информацию в новое поле pod.status.extendedResourceClaimStatus. Этот статус содержит имя автоматически созданного ResourceClaim и, что более важно, точную карту соответствия, которая связывает конкретный контейнер и его запрос с выделенным ему устройством. С помощью этих данных kubelet сконфигурирует и запустит контейнер с нужными ресурсами. Подробности смотрите в обзоре K8s 1.34.

Pod Level Resources Support With In Place Pod Vertical Scaling

#5419; KEP

KEP-1287, представленный в Kubernetes 1.27, позволяет изменять запросы и лимиты CPU/памяти для отдельных контейнеров без их перезапуска. KEP-2837 (в Kubernetes 1.32) расширил Pod API двумя новыми полями: pod.spec.resources.requests и pod.spec.resources.limit. Эти поля дают возможность устанавливать запросы и лимиты для вычислительных ресурсов, таких как CPU и память, на уровне всего пода в дополнение к существующим настройкам на уровне контейнеров. Однако для применения новых настроек на уровне пода все еще требовался его перезапуск.

KEP-5419 снимает это ограничение. Теперь можно менять pod.spec.resources работающего пода без его перезапуска. Кроме того, KEP расширяет объект PodStatus, включая в него аналог полей статуса контейнеров, но уже для всего пода. Это позволяет увидеть, какой объем ресурсов фактически зарезервирован для пода целиком.

Allow HostNetwork Pods to Use User Namespaces

#5607; KEP

В настоящее время Kubernetes ставит перед выбором: можно запустить под в сети хоста (hostNetwork: true), но в таком случае нельзя воспользоваться преимуществами пользовательских пространств имён (hostUsers: false) для изоляции пользователей. API-сервер запрещает такую комбинацию.

Многие компоненты управляющего слоя Kubernetes (такие как kube-apiserver и kube-controller-manager) часто запускаются в виде статических подов с доступом к сети хоста (hostNetwork: true). Это нужно, чтобы напрямую прослушивать порты хоста или взаимодействовать с его сетевым стеком. Но из-за описанного выше ограничения такие поды не могут применять пользовательские пространства имён для изоляции, что повышает риски их эксплуатации по сравнению с обычными подами.

KEP-5607 позволяет обойти это ограничение. Если активировать переключатель функциональности UserNamespacesHostNetworkSupport, API-сервер больше не будет отклонять спецификации подов, в которых одновременно указаны hostNetwork: true и hostUsers: false. То есть можно будет запускать поды в сети хоста, изолируя их пользователей с помощью пользовательских пространств имён.

Beta-фичи

Support User Namespaces in pods 

#127; KEP

KEP добавляет поддержку пользовательских пространств имён в stateless-подах. Идея в том, чтобы запускать процессы в подах с другими ID пользователя и ID группы, а не только с унаследованными с хоста. В этом случае привилегированный процесс в поде будет непривилегированным на хосте. Если такой процесс «вырвется» за пределы контейнера, потенциальный вред будет минимизирован, поскольку на хосте его привилегии будут ограничены. Подробнее — в обзоре Kubernetes 1.27.

KEP в третий раз выходит как бета. В этой версии завершена интеграция со стандартами безопасности пода (Pod Security Standards) и удален переключатель функциональности UserNamespacesPodSecurityStandards.

Expose Node Topology Labels via Downward API

#4742; KEP

KEP добавляет механизм, который будет автоматически копировать стандартные топологические лейблы с узла на под, когда тот планируется на узел. После этого приложение внутри контейнера сможет получить к ним доступ через стандартный механизм Downward API так же легко, как и к любым другим лейблам пода. Подробности смотрите в обзоре Kubernetes 1.33.

Новая функциональность теперь включена по умолчанию, то есть у пода теперь доступны лейблы topology.kubernetes.io/zone и topology.kubernetes.io/region, если они есть на узле, на котором этот под работает. Также была дополнена документация.

VolumeSource: OCI Artifact and/or Image

#4639; KEP

KEP добавляет в Kubernetes новый VolumeSource, поддерживающий OCI-образы и/или OCI-артефакты. Теперь пользователи смогут упаковывать файлы и шарить их в контейнерах пода, не включая в основной образ. Это позволит снизить уязвимости и упростит создание образов. Подробности в обзоре Kubernetes 1.31.

KEP повторно выходит как бета. В этой версии функциональность (ImageVolume) включена по умолчанию и добавлены три kubelet-метрики image_volume_requested_total, image_volume_mounted_success и image_volume_mounted_error.

Add FileEnvSource and FileKeySelector to add environment generated on the fly

#3721; KEP

Существующий подход к доставке переменных окружения с помощью ConfigMap или Secret довольно трудоёмкий. Когда initContainer генерирует конфигурацию (скажем, временный токен доступа), её нужно передать основному контейнеру. Текущий подход требует создания дополнительного объекта ConfigMap или Secret через API-сервер.

KEP решает эту проблему, позволяя initContainer'у записывать переменные в файл в общем томе emptyDir, а основному контейнеру — считывать их оттуда напрямую при старте, без лишних обращений к API.

В секцию env.valueFrom в API пода (PodSpec) добавляется новая структура fileKeyRef. Пример смотрите в бзоре Kubernetes 1.34.

Container restart rules to customize the pod restart policy

#5307; KEP

KEP-5307 повышает гранулярность перезапуска отдельных контейнеров в поде. Теперь Kubernetes сможет перезапускать контейнер «на месте», даже если у пода стоит restartPolicy = Never. Это особенно пригодится в ситуациях, когда пересоздание пода и его перенос на другой узел длятся долго и обходятся дорого.

В спецификацию контейнера добавилась новая секция restartPolicyRules со списком правил, которые описывают условия и действия. В альфа-версии доступны только одно условие — код завершения контейнера (onExitCodes) — и только одно действие — Restart (перезапуск). Пользователь может указать, например, что, если контейнер завершился с кодом 42, его нужно немедленно перезапустить (см. пример ниже). Если код завершения другой, будет применяться стандартная политика перезапуска, заданная для всего пода. Подробнее.

Ensure secret pulled images

#2535; KEP

KEP-2535 вводит механизм, который заставляет kubelet проверять учетные данные пода перед использованием уже загруженного образа. Учетные данные, которые были использованы для загрузки образа, теперь сохраняются. Когда новый под пытается использовать образ, kubelet проверяет, совпадают ли учетные данные этого пода с теми, что использовались для первоначального извлечения образа. Подробнее смотрите обзор Kubernetes 1.33.

Другими словами, даже при наличии образа на узле, под должен иметь соответствующие imagePullSecrets, чтобы его использовать.

В бета-версии переключатель функциональности KubeletEnsureSecretPulledImages по умолчанию активирован, а kubelet следует политике проверки образов NeverVerifyPreloadedImages (отключена проверка прав доступа для образов, которые уже существуют на узле). Кроме того, кеш kubelet’а теперь хранится не только на диске, но и в памяти. Это обеспечивает большую устойчивость к ошибкам ввода-вывода при чтении с диска. 

Remove cgroup v1 support

#5573; KEP

KEP убирает поддержку cgroup v1 из кодовой базы Kubernetes. Этот процесс будет поэтапным, при этом уже текущая бета-версия более не позволит kubelet’у запускаться на узлах с cgroup v1.

Окончательные сроки пока не определены. Само удаление будет произведено не ранее версии 1.38, чтобы соблюсти политику K8s по отказу от устаревших функций.

Configure the max CrashLoopBackOff delay

#5593; KEP

Этот KEP разделяет (уже реализованный и находящийся в стадии альфа-тестирования) KEP-4603 на два суб-KEP’а, чтобы перевести часть функциональности в стадию бета-тестирования. 

Переключатель функциональности KubeletCrashLoopBackOffMax теперь активирован по умолчанию. Кроме того, этот KEP вводит механизм, позволяющий слою управления контейнерами передавать определенное значение backoff-выдержки в цикл синхронизации подов kubelet’а, в частности, для контейнеров в состоянии CrashLoopBackOff.

В настоящее время, когда контейнер переходит в состояние CrashLoopBackOff, менеджер контейнеров kubelet’а рассчитывает backoff — время ожидания до следующей попытки запуска. Однако оно не передается под-воркеру, который планирует синхронизацию подов. В результате под-воркер использует собственное значение backoff по умолчанию, что приводит к несоответствию между рассчитанной и фактической выдержкой.

Чтобы решить эту проблему, KEP вводит новый тип ошибки — BackoffError — который включает в себя значение backoff. Эта ошибка возвращается в случаях, когда перезапуск контейнера должен быть отложен; цикл синхронизации получает обновленное значение и использует его.

Stable-фичи

Add CPUManager policy option to restrict reservedSystemCPUs to system daemons and interrupt processing

#4540; KEP

Новая опция strict-cpu-reservation в статической политике CPU Manager’а гарантирует, что процесоры, зарезервированные для системы (reservedSystemCPUs), будут использоваться только ею (то есть поды burstable и best-effort не смогут получить к ним доступ, как это было ранее). Примеры смотрите в обзоре Kubernetes 1.32.

Pod Generation

#5067; KEP

KEP устраняет неопределённость: теперь можно точно определить, получил ли kubelet последнюю версию PodSpec. Разработчики воспользовались существующим полем metadata.generation. Теперь API-сервер будет устанавливать его значение в 1 (единицу) при создании пода и увеличивать на 1 (единицу) при каждом изменении в PodSpec. Кроме того, в PodStatus добавится новое целочисленное поле status.observedGeneration. Подробности в обзоре Kubernetes 1.33.

In-Place Update of Pod Resources

#1287; KEP

KEP позволяет обновлять запросы и лимиты пода «на месте» — то есть теперь не нужно перезапускать под или его контейнеры. PodSpec становится частично изменяемой (mutable). PodStatus также доработан — он предоставляет информацию о ресурсах, выделенных для пода, а также о фактических ресурсах, потребляемых подом и его контейнерами (подробнее).

Fine-grained SupplementalGroups control

#3619; KEP

Новое поле SupplementalGroupsPolicy в API позволяет контролировать, какие дополнительные группы навешиваются на первый процесс в контейнере, следуя «принципу наименьшей неожиданности». Администраторы кластера смогут настраивать политики безопасности, регулирующие использование SupplementalGroupsPolicy в кластере, что позволит устранять проблему неожиданного обхода SupplementalGroups. Также пользователи смогут определять, какие группы на самом деле навешены на процессы в контейнерах. Подробнее — в обзоре Kubernetes 1.31.

DRA: structured parameters

#4381; KEP

KEP делает более прозрачными параметры запросов (claim) на ресурсы при динамическом распределении ресурсов (DRA). Вместо того чтобы самостоятельно обрабатывать семантику всех параметров запросов, драйверы теперь управляют ресурсами и описывают их с помощью определённой «структурированной модели». Это позволяет компонентам, осведомлённым об этой «структурированной модели», принимать решения о ресурсах, не передавая их сторонним контроллерам. Подробнее.

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.

kubelet image GC after a maximum age

#4210; KEP

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

KEP-4622: Add a TopologyManager policy option for MaxAllowableNUMANodes

#4622; KEP

Новый параметр политики TopologyManager под названием max-allowable-numa-nodes позволяет настраивать значение maxAllowableNUMANodes. Текущее строго заданное на уровне кода значение (8) добавили как временную меру несколько лет назад. Теперь пользователи смогут увеличить этот предел при необходимости.

KEP не меняет существующие политики TopologyManager и просто вводит новый параметр (по сути, реализуя поддержку CPU с более чем 8 NUMA-узлами).

Kubelet limit of Parallel Image Pulls

#3673; KEP

В kubelet на уровне узла добавляется ограничение (параметр maxParallelImagePulling) на число параллельно скачиваемых образов. Подробнее — в обзоре Kubernetes 1.27.

Хранилище

Alpha-фичи

Mutable PersistentVolume Node Affinity

#5381; KEP

В настоящее время после создания PersistentVolume его поле PersistentVolume.spec.nodeAffinity  (привязка к определенным узлам кластера) неизменяемо. KEP-5381 предлагает разрешить администраторам его изменять (то есть сделать mutable).

CSI driver opt-in for service account tokens via secrets field

#5538; KEP

KEP вводит новый, более безопасный способ передачи токенов сервисных аккаунтов драйверам CSI. В настоящее время такие токены передаются через поле volume_context в NodePublishVolumeRequest. Ключевая проблема состоит в том, что volume_context не предназначено для хранения конфиденциальной информации, что небезопасно (см., например, уязвимости CVE-2023-2878 и CVE-2024-3744, когда токены случайно попали в логи).

Новый механизм позволяет драйверам CSI явно запрашивать токены через специальное поле secrets, предназначенное для хранения конфиденциальных данных. Спецификация ресурса CSIDriver получает новое поле serviceAccountTokenInSecrets. Если оно установлено в false (поведение по умолчанию), токены продолжают отправляться через volume_context, что обеспечивает полную обратную совместимость с существующими драйверами. Если оно установлено в true, токены будут передаваться исключительно через поле secrets.

Beta-фичи

Mutable CSINode Allocatable Property

#4876; KEP

KEP делает поле CSINode.Spec.Drivers[*].Allocatable.Count изменяемым (mutable). Оно задает максимальное число томов CSI, которые можно подключить к узлу. Также добавляются механизмы динамического обновления его значения: kubelet может периодически посылать запросы на эндпойнт NodeGetInfo CSI-драйвера (интервал задаётся в новом поле CSIDriver.Spec.NodeAllocatableUpdatePeriodSeconds) или немедленно реагировать на ошибки нехватки ресурсов (ResourceExhausted) при попытке подключения тома, обновляя значение в CSINode.

Сеть

Beta-фичи

Allows setting any FQDN as the pod's hostname

#4762; KEP

KEP обеспечивает полный контроль над именем хоста внутри пода, позволяя устанавливать любое полное доменное имя (FQDN).

В podSpec добавляется новое поле hostnameOverride. Если оно заполнено, его значение будет использовано в качестве имени хоста пода, при этом текущие поля hostname, subdomain и setHostnameAsFQDN будут игнорироваться. Указанное FQDN будет прописано в файл /etc/hosts внутри контейнера, что позволит приложению самому узнавать его. Новое поведение можно активировать через переключатель функциональности HostnameOverride. Подробнее — в обзоре Kubernetes 1.34.

Stable-фичи

PreferSameNode Traffic Distribution (formerly PreferLocal traffic policy / Node-level topology)

#3015; KEP

Раньше в Kubernetes была опция TrafficDistribution: PreferClose, которая должна была направлять трафик на близкие инстансы сервиса. Однако понятие «близкие» определялось неоднозначно — это мог быть тот же узел, та же зона доступности или что-то ещё.

KEP убирает неоднозначность: старое значение PreferClose переименовано в PreferSameZone — «предпочитать ту же зону доступности». Кроме того, появляется опция PreferSameNode, которая предписывает направлять трафик на тот же узел, если на нём есть копия целевого сервиса. Это очень полезно, например, для локальных DNS-кешей.

API

Alpha-фичи

Unknown Version Interoperability Proxy

#4020; KEP

В процессе обновления кластеров Kubernetes версии их API-серверов могут разойтись (что известно как version skew). Из-за этого они могут поддерживать различные наборы встроенных API-ресурсов, что потенциально ведет к неполноте данных и ошибкам. Например, клиент (такой как контроллер или kubectl) может подключиться к API-серверу, который не знает о запрашиваемом ресурсе, даже если другой API-сервер в кластере его поддерживает, и получить ошибку 404. Также это грозит сбоями в работе системных компонентов: сборщик мусора, получив ошибку 404, может ошибочно удалить объекты, полагая, что их владелец был удален, а контроллер жизненного цикла пространств имен (Namespace Lifecycle Controller) может заблокировать удаление пространства имен, так как не может подтвердить, что оно пусто (или удалить его преждевременно, оставив «мусор» в etcd).

KEP позволяет API-серверам проксировать запросы, которые те не могут обработать. Вместо немедленного ответа с ошибкой 404 API-сервер сначала проверяет, может ли другой сервер в кластере обработать запрос, и перенаправляет его. Если ни один узел не может обслужить запрос, сервер возвращает ошибку 503 «Service Unavailable», сигнализируя о временной проблеме (более безопасное поведение).

Чтобы решить проблему с тем, что разные серверы видят разный набор ресурсов, KEP предлагает задействовать существующий механизм Aggregated Discovery. Он обеспечивает каждому API-серверу полное и консистентное представление обо всех ресурсах кластера, устраняя пробелы в обнаружении, вызванные расхождением версий.

Beta-фичи

Move Storage Version Migrator in-tree

#4192; KEP

KEP облегчает выполнение миграций хранилищ, делая процесс более автоматизированным и простым. Для этого:

  • существующая логика контроллера SVM переносится в in-tree менеджера контроллеров Kubernetes;

  • существующие API SVM REST также переносятся в in-tree.

В бета-версии функция включена по умолчанию. Кроме того, добавлена обработка непредвиденных событий (например, прерванных миграций) и проверка поддержки Create/Update объектами API. Подробнее см. обзор Kubernetes 1.30.

Stable-фичи

Remove gogo protobuf dependency for Kubernetes API types

#5589; KEP

KEP описывает процесс удаления зависимости от gogo/protobuf из кодовой базы Kubernetes и её замены на официальную библиотеку от Google — google.golang.org/protobuf. Авторы ставят цель сохранить существующее поведение и минимизировать влияние на потребителей типов Go API Kubernetes.

Transition from SPDY to WebSockets

#4006; KEP

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

Comparable Resource Version

#5504; KEP

KEP предлагает официально закрепить правило, что resourceVersion — это не просто строка, а монотонно возрастающее целое число (именно так оно выглядит внутри apiserver’а), представленное в виде строки. Клиенты в результате смогут определять, какая из версий ресурса новее. Для этого предлагается:

  • В client-go добавить новую вспомогательную функцию CompareResourceVersion(rv1, rv2), которая сможет сказать, какая из версий больше, меньше или они равны.

  • Изменить официальную документацию, явно прописав, что resourceVersion — это сравниваемое целое число.

  • Добавить conformance-тесты, которые будут гарантировать, что любой кластер, заявляющий о совместимости с Kubernetes, будет следовать этому правилу.

Аутентификация и авторизация

Alpha-фичи

Harden Kubelet Serving Certificate Validation in Kube-API server

#4872; KEP

В настоящее время механизм проверки TLS-сертификатов в kube-apiserver’е допускает «ослабленную» валидацию при подключении к kubelet’у: если настроен корневой центр сертификации (--kubelet-certificate-authority), сервер проверяет цифровую подпись, но не всегда требует, чтобы IP-адрес или имя хоста в поле Subject Alternative Name (SAN) сертификата соответствовали фактическому адресу назначения.

В результате кластер становится уязвимым для атак типа man-in-the-middle. Злоумышленник с действительным сертификатом (подписанным доверенным CA, но выданным на другое имя/IP) может перехватить соединение от API-сервера к kubelet’у (например, при выполнении команд kubectl exec или kubectl logs).

KEP заставляет API-сервер проверять поле Common Name (CN) в сертификате kubelet’а на соответствие формату system:node:<nodename>, где nodename — это имя объекта Node, сообщаемое kubelet’ом.

Примечание: включение этой фичи может нарушить работу существующих кластеров, использующих кастомные serving-сертификаты kubelet’а. Перед её активацией их необходимо перевыпустить.

Constrained Impersonation

#5284; KEP

Исторически механизм имперсонации в Kubernetes не обладал достаточной гранулярностью. Если пользователь или сервисный аккаунт получал право на имперсонацию другого пользователя (например, someUser), ему предоставлялись абсолютно все привилегии этого пользователя. Такой подход нарушал принцип наименьших привилегий и создавал серьезные риски для безопасности.

KEP-5284 вводит концепцию так называемой ограниченной имперсонации (constrained impersonation), а также два новых префикса для действий (verbs):

  • impersonate:<mode>: — для имперсонации субъекта определенного типа (пользователя, сервисного аккаунта и т.д.);

  • impersonate-on:<mode>:<verb>: — для выполнения конкретного действия над ресурсом.

Теперь для выполнения действия от имени другого пользователя субъект, выполняющий имперсонацию, должен обладать:

  • разрешением на ограниченную имперсонацию целевого пользователя (это разрешение действует в пределах всего кластера),

  • явным разрешением на выполнение конкретного действия, определяемого глаголом API (например, list). Оно может действовать как в пределах кластера, так и в пределах пространства имен.

Beta-фичи

Pod Certificates

#4317; KEP

KEP-4317 позволяет нативно доставлять сертификаты X.509 в рабочие нагрузки кластера. Проблема была в том, что, хотя API certificates.k8s.io и даёт гибкий способ запрашивать сертификаты, их доставкой и управлением внутри подов приходилось заниматься разработчикам и администраторам.

Теперь под может напрямую запросить сертификат у конкретного издателя, включив в запрос всю информацию о себе. Также в рамках KEP добавили новый источник для проецируемых томов (projected volumes) — PodCertificate. С этим томом, примонтированным в под, kubelet может осуществлять весь жизненный цикл управления учётными данными: генерировать приватный ключ, создавать PodCertificateRequest, дожидаться выпуска сертификата и монтировать ключ вместе с цепочкой сертификатов в файловую систему пода. Пример смотрите в обзоре Kubernetes 1.34.

Stable-фичи

Structured Authentication Config

#3331; KEP

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

CLI

Beta-фичи

KYAML

#5295; KEP

KEP вводит новый формат YAML — KYAML (Kubernetes YAML), который решает проблемы классического YAML следующим образом:

  • Все строки всегда заключаются в кавычки, чтобы избежать случайного преобразования типов (например, «no» не будет преобразовано в false).

  • Явно используется flow-style-синтаксис: [] для lists и {} для maps.

  • Снижена чувствительность к пробелам и отступам.

Подробнее смотрите в обзоре Kubernetes 1.34.

Separate kubectl user preferences from cluster configs

#3104; KEP

KEP вводит новый опциональный конфигурационный файл kuberc для хранения пользовательских настроек утилиты kubectl, отделяя их от данных для подключения к кластерам, которые остаются в kubeconfig. Это позволяет избежать перезаписи настроек при смене kubeconfig. Теперь пользовательские настройки будут применяться независимо от значения флага --kubeconfig или переменной окружения $KUBECONFIG.

Stable-фичи

Include kubectl command metadata in http request headers

#859; KEP

Фича, которая появилась в далекой версии 1.21, наконец, обрела стабильный статус. Напомним, KEP добавляет в kubectl возможность отправлять произвольные HTTP-заголовки в запросах к API-серверу Kubernetes. Операторы кластеров могут их использовать для отладки или сбора телеметрии о том, как пользователи взаимодействуют с кластером.

Планировщик

Alpha-фичи

Gang Scheduling Support in Kubernetes

#4671; KEP

Kubernetes широко применяется для AI-, ML- и HPC-задач, где требуется одновременный запуск множества процессов. Стандартный планировщик Kubernetes обрабатывает поды поочередно, последовательно распределяя их по узлам. Когда ресурсов мало, возникает риск, что не все воркеры, необходимые для выполнения задачи, будут запланированы. Например, если кластер может принять только пять из десяти требуемых воркеров, они займут узлы и будут блокировать ресурсы в ожидании остальных. Результат — взаимные блокировки и неэффективное использование ресурсов.

KEP решает эту проблему с помощью так называемого группового планирования (gang scheduling). Оно обеспечивает соблюдение принципа «Всё или ничего» (All-or-Nothing): группа подов (gang) планируется на узлы только в том случае, если ресурсы есть для всех её членов (или для минимально необходимого кворума, определяемого параметром minCount).

В API появляется новый базовый тип Workload, который управляет жизненным циклом группы подов как единой сущностью, позволяя планировщику обрабатывать всю задачу целиком. Логика ассоциации основана на PodGroups, где определяются параметры группы, такие как minCount (минимальное количество подов для запуска). Спецификация пода получает поле для ссылки на родительский объект Workload — так планировщик поймет, что под принадлежит к группе. Объекты Workload поддерживают рабочие нагрузки со сложной внутренней структурой, такие как встроенные Job и StatefulSet, а также кастомные, например, JobSet, LeaderWorkerSet, MPIJob и TrainJob.

Пример определения Workload:

apiVersion: scheduling.k8s.io/v1alpha1
kind: Workload
metadata:
  namespace: ns-1
  name: job-1
spec:
  podGroups:
    - name: "pg1"
      policy:
        gang:
          minCount: 100

Extended Toleration Operators for Threshold-Based Placement

#5471; KEP

KEP расширяет структуру Toleration API в core/v1, добавляя новые операторы математического сравнения к стандартным Equal (равно) и Exists (существует): Lt (меньше чем) и Gt (больше чем). Также обновляется логика плагина планировщика TaintToleration, который теперь должен интерпретировать значения taints и tolerations как числа, а не просто сравнивать их как строки. Хотя данные в полях Value технически остаются строковыми, при использовании новых операторов система пытается преобразовать их в 64-битные целые числа (int64). Если хотя бы одно из значений в паре «Taint-Toleration» не является допустимым целым числом, сравнение считается неуспешным, и толерантность не применяется. Поддержка чисел с плавающей запятой намеренно исключена во избежание ошибок точности; вместо этого пользователям рекомендуется использовать масштабирование (например, записывать «95.5%» как целое число 955).

Пример: допустим, необходимо запускать чувствительные к задержкам поды исключительно на узлах с SLA > 95%. При этом они должны вытесняться с узла, если его SLA опускается ниже этого порога. Новый KEP позволяет реализовать это (в отличие от NodeAffinity):

# Нужен узел с высоким SLA.
apiVersion: v1
kind: Node
metadata:
  name: ondemand-node-1
spec:
  taints:
  - key: node.kubernetes.io/sla
    value: "950"
    effect: NoExecute
---
# Сервису инференса нужны узлы с SLA > 950 и грейс-период в 30 секунд
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inference-service
spec:
  template:
    spec:
      tolerations:
      - key: node.kubernetes.io/sla
        operator: Gt
        value: "950"
        effect: NoExecute
        tolerationSeconds: 30

DRA: Partitionable Devices

#4815; KEP

Изначально Dynamic Resource Allocation (DRA) задумывался для динамического выделения не только целого устройства, но и части его ресурсов (partition). Классический API плагинов устройств поддерживал только статическое разбиение устройства на партиции, DRA же позволил создавать их по требованию, тем самым повысив эффективность использования ресурсов.

С развитием DRA от «классического» до «структурированных параметров» эта возможность динамического разбиения устройств на партиции была утрачена. KEP возвращает эту возможность в рамки «структурированных параметров». Кроме того, он предоставляет примитивы для представления как полных устройств, так и их партиций более компактным способом, чем это возможно сегодня. Подробнее.

DRA: Device Binding Conditions

#5007; KEP

Стандартный планировщик Kubernetes предполагает, что все ресурсы на узле доступны в момент привязки пода. Однако это не всегда справедливо для таких устройств, как GPU с подключением через коммутируемую матрицу (fabric-attached), которым нужно динамическое присоединение по PCIe или CXL, и FPGA, требующих затратного по времени перепрограммирования перед использованием. Преждевременная привязка пода к узлу до того, как такое устройство будет полностью готово, приводит к сбоям при запуске пода и требует ручного вмешательства.

KEP решает эту проблему, позволяя планировщику откладывать финальную привязку пода (фаза PreBind) до тех пор, пока внешний контроллер не подтвердит готовность необходимого ресурса. Это делает процесс планирования более предсказуемым и надёжным. Подробнее.

DRA: device taints and tolerations

#5055; KEP

В DRA драйверы публикуют информацию об устройствах, которыми управляют, в ResourceSlice. Эта информация используется планировщиком при выборе устройств под нужды пользователей в ResourceClaim.

KEP позволяет драйверам DRA навешивать taints (ограничения) на устройства — в этом случае новые поды на них не будут планироваться. Кроме того, поды, которые уже работают на устройствах с taint, могут быть автоматически остановлены. Администраторы кластера могут навешивать taint’ы с помощью ResourceSlicePatch.

Также в ResourceClaim можно добавлять tolerations (допуски) для определённых taint’ов.

DRA: Consumable Capacity

#5075; KEP

Ранее можно было совместно использовать устройства только в том случае, если несколько подов или контейнеров ссылались на один и тот же ResourceClaim, который уже выделил это устройство. KEP 5075 даёт возможность независимым запросам ResourceClaim претендовать на доли одного и того же устройства. Теперь никак не связанные поды (даже из разных пространств имён) могут использовать ресурсы совместно.

Новый механизм позволяет устройству объявлять, что оно допускает множественное распределение. Для этого служит поле allowMultipleAllocations в разделе devices ResourceSlice. Кроме того, пользователи теперь могут запросить определённую «ёмкость» от такого делимого устройства с помощью нового поля CapacityRequests в ResourceClaim. Пример.

Beta-фичи

Use NominatedNodeName to express the expected pod placement

#5278; KEP

Привязка (binding) подов может занимать продолжительное время (иногда даже минуты). В течение всего этого времени компоненты кластера ничего не знают о том, на какой именно узел планируется под. Без этой информации они могут предпринять конфликтующие действия. Например, компонент автомасштабирования кластера (Cluster Autoscaler) может удалить целевой узел. Кроме того, сам планировщик за это время может быть перезапущен и т. п. Если учесть, что решения о планировании хранятся только в памяти планировщика, его новая реинкарнация ничего не будет знать о прошлых решениях и может запланировать под на другой узел. Это приведет к пустой трате ресурсов и увеличению задержек.

KEP превращает поле NominatedNodeName из узкоспециализированного индикатора приоритизации (preemption) в двусторонний канал коммуникации между планировщиком и другими компонентами кластера, чем значительно расширяет его функциональность в спецификации пода. Основная цель — сделать процесс размещения подов более предсказуемым и эффективным. Подробнее см. обзор Kubernetes 1.34.

DRA: Prioritized Alternatives in Device Requests

#4816; KEP

KEP 4381 «Динамическое распределение ресурсов с помощью структурированных параметров» (см. обзор Kubernetes 1.30) позволил запрашивать специфические типы ресурсов с помощью ResourceClaim. Однако текущая реализация API не позволяет пользователю задавать приоритеты, если потребностям рабочей нагрузки удовлетворяют несколько типов или конфигураций устройств. KEP 4816 решает эту проблему: теперь можно указать несколько вариантов запросов на динамические ресурсы (например, разные типы GPU) в виде упорядоченного списка. Планировщик попытается удовлетворить эти запросы по очереди, начиная с самого предпочтительного. Подробнее — в обзоре Kubernetes 1.33.

Opportunistic batching

#5598; KEP

KEP сразу выходит как бета. Новый механизм пакетирования (batching) нацелен на существенное сокращение затрат ресурсов на планирование подов в крупных кластерах или для больших задач (Jobs). По сути, планировщик теперь может повторно использовать принятые решения о планировании одного пода для других подов с такой же сигнатурой. Для этого авторы KEP вводят понятие «сигнатуры планирования пода» (Pod scheduling signature), которая представляет собой сводку требований пода для его размещения на узле.

Сигнатура планирования вычисляется на основе полей PodSpec, влияющих на размещение пода. Идея в том, чтобы выявить поды, которые планировщик будет считать «идентичными» — то есть для них будут одинаковые результаты на этапах фильтрации (поиск допустимых узлов) и оценки (выбор наилучшего узла). Сигнатура пода зависит от различных параметров, таких как ImageLocality, NodeAffinity, NodeName, HostPorts, NodeVolumeLimits и др. С другой стороны, определённые параметры (например, DynamicResources, PodAffinity/AntiAffinity или PodTopologySpread) делают под непригодным для создания сигнатуры и, следовательно, для пакетирования.

Механизм пакетирования управляется двумя основными операциями:

  • Create вызывается для первого пода с новой сигнатурой. Эта операция выполняет полный скоринг и кэширует список подходящих узлов.

  • Update вызывается для последующих подов с той же сигнатурой. Она берёт следующий лучший узел из кэша и удаляет его из списка, если на нём больше нельзя разместить поды. Если на узел всё ещё можно добавлять поды, текущий кэш пакетирования сбрасывается, и выполняется повторная оценка (rescoring), чтобы избежать размещения других подов на узле, который, возможно, уже не является оптимальным. (Операция Nominate резервирует узлы для этих пакетированных подов, записывая имя выбранного узла в поле NominatedNodeName пода.)

Приложения

Consider Terminating Pods in Deployments

#3973; KEP

В некоторых ситуациях общее количество запущенных и завершающих свою работу подов (terminating) в развертывании может превышать заданные лимиты (т. е., например, spec.replicas + maxSurge для стратегии RollingUpdate). Несмотря на то что terminating-поды помечены для удаления, они продолжают потреблять ресурсы кластера в течение периода, установленного параметром terminationGracePeriodSeconds.

Результат — проблемы вроде избыточного автомасштабирования узлов (см. #95498 или #99513) или невозможность планирования новых подов в кластерах с ограниченными ресурсами до тех пор, пока старые поды не будут полностью удалены (#98656). Поведение при обновлении различается в зависимости от стратегии: RollingUpdate создает новые поды немедленно (TerminationStarted), тогда как Recreate ожидает полного завершения старых подов (TerminationComplete).

Чтобы решить эту проблему, KEP-3973 добавляет в спецификацию Deployment’а новое поле .spec.podReplacementPolicy. Оно позволяет контролировать момент создания замещающих подов. Доступны две опции: TerminationStarted и TerminationComplete. Первая позволяет Deployment'у запускать новые поды, не дожидаясь полного завершения старых. Вторая заставляет Deployment ожидать, пока поды с меткой deletionTimestamp не перейдут в состояние Succeeded или Failed (т. е. их работа будет полностью завершена, а описание удалено из etcd). Также для отслеживания terminating-подов в Deployment и ReplicaSet добавлено новое поле статуса, .status.terminatingReplicas.

Mutable Container Resources when Job is suspended

#5440; KEP

Часто потребности в ресурсах для пакетных рабочих нагрузок (batch workloads) в Kubernetes неизвестны в момент их создания и зависят от доступной емкости кластера. Данный KEP оптимизирует утилизацию ресурсов в кластере, предоставляя способ изменять запросы и лимиты ресурсов для приостановленных заданий, что позволяет запускать их с конфигурациями, соответствующими реальным условиям в кластере.

Прежде всего меняется логика валидации шаблона пода. Теперь проверка поля Template в Job становится менее строгой, что позволяет на лету изменять ресурсы контейнера (запросы и лимиты по CPU/GPU и памяти, а также экзотику вроде TPU/FPGA) для приостановленных задач (Job.Spec.Suspend=true).

Beta-фичи

maxUnavailable for StatefulSets

#961; KEP

KEP вводит в RollingUpdate дополнительное поле maxUnavailable. В нем указывается количество подов, которые можно обновить (и пересоздать) одновременно. Фича полезна, например, в случае stateful-приложений, реализующих подход с leader/followers: одновременное падение нескольких followers может быть менее критично, чем скорость обновления приложения. С помощью maxUnavailable выкат обновлений будет происходить быстрее, чем ранее.

Stable-фичи

Job API managed-by mechanism

#4368; KEP

KEP вводит поле managedBy в спецификацию задачи, которое позволяет делегировать ее синхронизацию внешнему контроллеру.

Разное

Alpha-фичи

Statusz for Kubernetes Components

#4827; KEP

KEP добавляет observability-эндпоинт /statusz в ключевые компоненты Kubernetes (kube-apiserver, kubelet, kube-controller-manager, kube-scheduler, kube-proxy). Он будет выводить важную информацию о состоянии компонента — версию, сведения о сборке, используемой версии Go, совместимости с API Kubernetes, полезные ссылки на другие важные эндпоинты (/healthz, /livez, /readyz и /metrics). Подробнее.

Flagz for Kubernetes Components

#4828; KEP

По аналогии с предыдущим KEP в ключевые компоненты Kubernetes добавляется эндпоинт /flagz. Он будет возвращать информацию о флагах, с которыми был запущен компонент. Изначально данные (имя флага и его значение) будут выдаваться в простом текстовом виде. В будущем может быть добавлена поддержка структурированных форматов. Доступ к /flagz будут иметь члены RBAC-роли system:monitoring.

Integrate CSI Volume attach limits with cluster autoscaler

#5030; KEP

В настоящее время при симуляции планирования подов для принятия решений о масштабировании Cluster Autoscaler (CAS) не учитывает лимиты на подключение томов, налагаемые драйверами CSI. Это приводит к тому, что CAS создает недостаточное количество новых узлов, поскольку по умолчанию он предполагает, что на этих узлах достаточно томов для новых подов, хотя в действительности это не так.

Кроме того, планировщик может попытаться разместить под, требующий том, на только что созданном узле, где соответствующий драйвер CSI еще не инициализирован. Из-за отсутствия информации от драйвера планировщик ошибочно полагает, что никаких ограничений нет и размещает под. В результате под переходит в состояние Pending на узле, который не в состоянии подключить его том.

KEP-5030 решает эти проблемы путем внесения изменений в оба компонента Kubernetes. Теперь CAS учитывает лимиты томов при симуляции масштабирования. Он создает «шаблон» для нового узла, который включает информацию о лимитах. Эта информация получается либо от существующего узла в той же группе (если узлы уже есть), либо напрямую от облачного провайдера, если группа масштабируется с нуля.

В свою очередь, планировщик интерпретирует отсутствие информации от драйвера CSI на узле как нулевой лимит на подключение томов для этого драйвера. Это предотвращает размещение подов на узлах, которые еще не готовы к работе с их томами.

CCM: watch-based route controller reconciliation using informers

#5237; KEP

В настоящее время контроллер маршрутов в Kubernetes по умолчанию выполняет сверку (reconciliation) каждые 10 секунд, проверяя все узлы и все маршруты у облачного провайдера, чтобы убедиться в их соответствии желаемому состоянию. Это создает постоянную и часто избыточную нагрузку на API облачного провайдера, поскольку проверка выполняется даже при отсутствии изменений в кластере.

Авторы KEP предлагают перейти на модель, основанную на отслеживании событий (watch-based), где сверка запускается событиями, связанными с узлами: добавлением, удалением или обновлением таких полей, как status.addresses и spec.PodCIDRs.

Для надежности полная периодическая сверка все равно останется, но будет запускаться гораздо реже. Она нужна для самовосстановления и для подчистки «зависших» маршрутов, которые могли остаться, если какое-то событие было пропущено (например, узел удалили, пока контроллер был неактивен). Кроме того, появится новая метрика route_controller_route_sync_total для подсчета количества сверок.

Beta-фичи

Configurable tolerance for Horizontal Pod Autoscalers

#4951; KEP

Чтобы защититься от незначительных колебаний метрики, в инструмент горизонтального масштабирования (HPA) Kubernetes интегрирована область нечувствительности (tolerance), которая по умолчанию составляет 10 %. То есть HPA не будет реагировать на изменения значений метрики, если они меньше 10 %. Проблема в том, что значение tolerance единое для всего кластера, что не очень удобно, поскольку для одних приложений оно может быть слишком велико (например, в кластере из 1000 подов 10 % — это сотни лишних или недостающих копий), а для других — недостаточно.

KEP добавляет поле tolerance в разделы spec.behavior.scaleUp и spec.behavior.scaleDown, чем позволяет настраивать порог чувствительности для каждого HPA. Причём можно задать разные пороги для увеличения (scale-up) и уменьшения (scale-down) количества подов.

Stable-фичи

Invariant Testing

#5468; KEP

KEP-5468 вводит инвариантное тестирование в end-to-end (e2e) тесты Kubernetes. В отличие от стандартных тестов, проверяющих изолированные сценарии, инвариантные тесты будут проверять, что фундаментальные системные свойства (инварианты) не были нарушены во время выполнения всего набора тестов. Эта методология, реализованная через хук ReportAfterSuite (часть Gingko), позволяет отлавливать сложные баги, вызванные непредвиденным взаимодействием между тестами, проверяя состояние кластера уже после их завершения. Также вводится строгая модель владения для каждого инвариантного теста, чтобы обеспечить быструю реакцию на сбои и минимизировать блокировку CI/CD пайплайна.

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

Окончание поддержки cgroup v1 

На Linux-узлах среды исполнения контейнеров (runtimes) используют cgroups. Kubernetes поддерживает cgroup v2, начиная с версии v1.25. Она ­— отличная альтернатива cgroup v1 с кучей полезных функций (единая иерархия контрольных групп, лучшая изоляция ресурсов и др.). См. KEP-5573.

Удаление поддержки cgroup v1 затронет только администраторов кластеров, использующих узлы на старых дистрибутивах Linux, которые не поддерживают cgroup v2; на таких узлах kubelet не сможет запуститься.

Депрекация режима ipvs в kube-proxy

Некоторое время назад в kube-proxy был добавлен режим ipvs. Его внедрили для высокопроизводительной балансировки нагрузки сервисов, так как он работал быстрее существовавшего тогда режима iptables. Однако поддерживать функциональный паритет между ipvs и другими режимами kube-proxy стало сложно из-за технических трудностей и различий в требованиях. В результате накопился серьезный технический долг, и поддерживать ipvs вместе с новыми сетевыми функциями стало непрактично.

Чтобы упростить кодовую базу kube-proxy, в релизе v1.35 режим ipvs объявляется устаревшим. Для Linux-узлов уже сейчас рекомендуемым режимом является nftables. См. KEP-5495.

Депрекация containerd v1.y

Хотя Kubernetes v1.35 все еще поддерживает containerd 1.7 и другие LTS-релизы containerd, сообщество Kubernetes SIG Node официально согласовало график прекращения поддержки containerd v1.X. Kubernetes v1.35 — последний релиз с поддержкой этой линейки версий (что совпадает с окончанием жизненного цикла containerd 1.7).

Важно: если вы используете containerd 1.X, необходимо перейти на версию 2.0 или новее перед обновлением Kubernetes на следующую версию. Метрика kubelet_cri_losing_support помогает узнать, используют ли какие-либо узлы в кластере версию containerd, поддержка которой скоро будет прекращена. Дополнительную информацию можно найти в блоге или в KEP-4033.

P. S.

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

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