Этой ночью представят новую версию Kubernetes. Среди главных изменений на первое место разработчики поставили стабилизацию функции CSI Migration — отказ от внутренних плагинов хранилищ в пользу CSI-драйверов. Также в этой версии устаревший контроллер PodSecurityPolicy заменен на новый PodSecurity Admission.
По традиции, в обзоре рассказываем обо всех новых функциях (alpha), а также упоминаем те, что перешли на уровень выше (beta, stable).
Для подготовки статьи использовалась информация из таблицы Kubernetes enhancements tracking, CHANGELOG-1.25, обзора Sysdig, а также конкретные issues, pull requests и Kubernetes Enhancement Proposals (KEPs).
Всего в новом релизе 40 изменений. Из них:
-
15 новых функций (alpha);
-
10 продолжают улучшаться (beta);
-
13 признаны стабильными (stable);
-
2 устарели.
Примечание
Мы сознательно не переводим названия фич на русский. Они состоят преимущественно из специальной терминологии, с которой инженеры чаще встречаются в оригинальной формулировке.
Главное изменение: стабилизация CSI Migration
Масштабный проект по миграции со встроенных плагинов томов на CSI-драйверы стартовал в 2017-м, когда в Kubernetes 1.9 появилась альфа-версия функции Out-of-Tree Volume Plugins (CSI). С тех пор Kubernetes последовательно отключает встроенные плагины популярных хранилищ — от AWS до Portwox.
В этом релизе в статус GA перешли три миграции: ядро (Core CSI), а также плагины GCE PD и AWS EBS. Как подчеркивают разработчики Kubernetes, это важный шаг на пути к полному избавлению Kubernetes от встроенных плагинов томов.
Узлы
Add support for user namespaces
Сейчас Kubernetes не поддерживает пользовательские пространства имен (user namespaces). ID пользовательского или группового процесса (UID/GID), который запущен в Pod’е, всегда идентичен ID хоста. Из-за этого могут возникать проблемы. Например, если в контейнере запущен вредоносный привилегированный процесс, под угрозой оказываются и Pod, и хост, на котором этот Pod запущен, потому что для хоста это тоже привилегированный процесс.
Новая функция добавляет в K8s поддержку пользовательских пространств имен. Теперь процессам в контейнерах можно назначать пользовательские и групповые ID, отличные от ID хоста. Это значит, что для контейнера процесс можно сделать привилегированным, а для хоста — обычным. Фича активируется через поле hostUsers
в pod.Spec
.
Главная цель — еще больше изолировать Pod от хоста. Авторы KEP’а приводят список известных уязвимостей, которые новая функция полностью или частично закрывает.
Forensic Container Checkpointing
Улучшение, которое буквально переводится как «контрольная точка контейнера для криминалистического анализа», помогает скрыто выявлять подозрительную активность в контейнерах. Контрольная точка контейнера — его состояние на определенный момент времени; она создается из снапшота в виде копии целевого контейнера. Копия разворачивается во внешней среде — например, на другом узле вне кластера K8s — и проверяется на наличие вредоносной активности внешними инструментами. Инструменты проверки остаются за рамками фичи и на усмотрение администратора. Что важно, целевой контейнер не «подозревает» о проверке и существовании своей копии.
Последовательность шагов:
-
Создается контрольная точка:
curl -skv -X POST "https://localhost:10250/checkpoint/default/counters/wildfly"
-
Архив с контрольной точкой берется из
/var/lib/kubelet/checkpoints
и перемещается в другую среду, вне K8s. -
Выполняется
crictl restore --import=<archive>
, чтобы восстановить копию контейнера в другой среде.
Для реализации фичи расширены API CRI (Container Runtime Interface) и функциональность kubelet. Включается feature gate’ом ContainerCheckpoint
.
Kubelet OpenTelemetry tracing
Взаимодействие API-сервера и kubelet — основной способ коммуникации между управляющим слоем Kubernetes (control plane) и узлами. Это взаимодействие организовано с помощью gRPC- и HTTP API-запросов. Авторы улучшения считают, что трассировка таких запросов расширит возможности поиска и отладки проблем с узлами и kubelet’ом, в том числе при взаимодействии kubelet’а со средой исполнения контейнеров.
Фича помогает обнаруживать источники различных задержек во время:
-
создания, удаления, запуска и остановки контейнеров;
-
монтирования и подключения томов, на которые ссылается Pod;
-
проброса портов контейнеров.
Для реализации трассировки используется имплементация OpenTelemetry для Go. Собирает трейсы специальный агент — collector, который запускается в виде sidecar’а, Deployment’а или DaemonSet’а. Для экспорта спанов применяется связка OTLP exporter, OTLP trace provider и context propagator.
Pod sandbox ready condition
Создание песочницы Pod’а (Pod sandbox) — критически важная фаза его жизненного цикла. Завершение этой фазы говорит о том, что сеть для Pod’а настроена успешно. Проблема в том, что Kubernetes не отслеживает статус процесса создания песочницы и не сообщает о результате пользователю — по крайней мере так же однозначно, как, например, в случае с ContainersReady
при создании контейнеров. Есть состояние Initialized
, которое актуально для init-контейнеров, есть PodScheduled
, которое показывает, запланирован ли Pod — но этого недостаточно.
Информация о статусе процесса может быть полезной для сторонних сервисов мониторинга (например, kube-state-metrics) и контроллеров. С ее помощью можно более точно оценивать состояние Pod’ов, выявлять задержки при настройке сети, лучше согласовывать работу Pod’ов и связанных с ними ресурсов вроде PVC.
Авторы улучшения предложили расширить возможности kubelet и добавить новое состояние Pod’а — PodHasNetwork
со статусом true
или false
. Kubelet генерирует PodHasNetwork
как часть существующих вызовов generateAPIPodStatus()
.
Пример отчета о состоянии Pod’а:
status:
conditions:
...
- lastProbeTime: null
lastTransitionTime: "2022-12-06T15:33:49Z"
status: "True"
type: PodHasNetwork
CPU Manager policy: socket alignment
В Kubernetes 1.23 появилась альфа-версия функции, которая помогает равномерно распределять ресурсы процессора между NUMA-узлами (Non-Uniform Memory Architecture). Для этого включается политика distribute-cpus-across-numa
. В нынешнем релизе представлено улучшение, которое расширяет возможности распределения.
В CPU Manager добавлена новая политика align-by-socket
. Она гарантирует, что приложения могут рассчитывать на выравнивание ресурсов по крайней мере в пределах одного сокета — в дополнение к выравниванию между NUMA-узлами. При этом CPU Manager может задействовать доступные процессорные мощности всех NUMA-узлов, которые входят в сокет. Обе политики — align-by-socket
и distribute-cpus-across-numа
— обеспечивают более предсказуемую производительность приложений, чувствительных к задержкам.
Beta-фичи
Ephemeral storage quotas улучшает возможности по отслеживанию утилизации локальных эфемерных хранилищ с помощью квот файловой системы. Альфа-версию фичи представили ещё три года назад в Kubernetes 1.15.
Add configurable grace period to probes — новое поле в конфигурации liveness-проверок probe.terminationGracePeriodSeconds
. Через этот параметр можно настроить принудительное завершение проверки, если она по каким-то причинам подвисает, и не дожидаться, когда отработает стандартное условие terminationGracePeriodSeconds
.
Seccomp by default включает режим seccomp по умолчанию и блокирует неразрешенные системные вызовы. (Подробнее об этой важной для защиты узлов функции читайте в нашем анонсе.)
Stable-фичи
Ephemeral containers — продвинутая отладка ошибок у работающих Pod’ов с помощью тестового эфемерного контейнера. Он запускается в том же пространстве имен, что и Pod.
Cgroup v2 — совместимость K8s c функцией Linux, которая используется для распределения вычислительных ресурсов между контейнерам и их изоляции. Cgroup v2 была объявлена стабильной около трех лет назад, и с тех пор многие дистрибутивы Linux используют ее по умолчанию.
Хранилище
NodeExpansion secret
Сейчас Kubernetes не поддерживает передачу секретов в RPC-запросах к CSI-драйверам при расширении емкости томов на узле с помощью операции nodeExpandVolume
. Хотя такая возможность пригодилась бы в случаях, когда вместе с запросом нужно передать ключ или пароль — например, для расширения тома на узле с зашифрованным LUKS-диском.
Как раз для этого в запрос nodeExpandVolume
, которое kubelet отправляет CSI-драйверу, добавлено новое поле secretRef
. Фича активируется с помощью двух параметров в настройках storage class. Пример:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-storage-sc
parameters:
csi.storage.k8s.io/node-expand-secret-name: secret-name
csi.storage.k8s.io/node-expand-secret-namespace: mysecretsns
Также в объект CSIPersistentVolumeSource
добавлен параметр NodeExpandSecretRef
, чтобы можно было передавать секрет в PVC-запросах на расширение тома.
Reconcile default StorageClass in PVCs
Если пользователю требуется хранилище, он создает PVC-запрос. При этом есть два режима provisioning’а:
-
Static provisioning, когда уже есть PV, к которому может привязаться PVC. В этом случае указывать storage class не нужно.
-
Dynamic provisioning, когда нет существующего PV, поэтому PVC указывает storage class либо ссылается на существующий storage class, который используется по умолчанию.
Это нормальный сценарий. Однако возможны и проблемные:
-
Если в кластере уже есть storage class (SC) по умолчанию, трудно заменить его другим SC так, чтобы не возникло ошибок.
-
Когда пользователь хочет изменить параметры SC по умолчанию, он должен удалить и пересоздать SC, потому что K8s запрещает его изменять. Если, например, для старого SC установлена квота, она пропадет после пересоздания SC, потому что привязывается к его имени.
-
Инструменты для установки Kubernetes-кластера могут быть интегрированы с облачными провайдерами и дополнениями, которым требуется хранилище. Эти инструменты должны быть достаточно «умными», чтобы уметь создавать SC до того, как какой-нибудь из компонентов не начнет генерировать PVC.
Для решения проблем предложено изменить поведение PV-контроллера. Как только любой SC помечен в качестве SC по умолчанию, контроллер сразу же назначает его всем не привязанным PVC со значением pvc.spec.storageClassName=nil
. После того, как администратор создаст SC по умолчанию, вместо nil
появится имя этого SC.
SELinux relabeling using mount options
На хостах с SELinux в принудительном режиме (enforcing mode) пользователи одного контейнера не могут получить доступ к другому контейнеру или к хосту. Это обеспечивается за счет:
-
контекста, который уникален для каждого контейнера. Например:
system_u:system_r:container_t:s0:c309,c383
; -
соответствующих лейблов, которые назначаются каждому файлу на каждом томе хранилища. Например:
system_u:object_r:container_file_t:s0:c309,c383
.
Доступ к файлам с лейблом container_file_t:s0:c309,c383
может получить только процесс с контекстом ...:container_t:s0:c309,c383
. Злоумышленник, которому удалось выбраться из контейнера, не сможет получить доступ к данным в других контейнерах, потому что у каждого контейнера свои тома со своими лейблами.
Однако такая защита может усложнять жизнь пользователям, которые разворачивают кластеры на базе SELinux: при запуске нового контейнера запускается рекурсивное переназначение лейблов для всех файлов в привязанном к Pod’у томе. Если том большой, процесс переназначения может затянуться и тормозить связанные процессы.
Новая функция дает возможность пропустить этап переназначения лейблов, чтобы ускорить монтирование тома. Для этого при монтировании используется опция -o context=XYZ
, которая устанавливает общий контекст для всех файлов тома. Поскольку все файлы тома уже снабжены нужным контекстом и соответствующим лейблом, переназначения лейблов не происходит.
Альфа-версия фичи работает только для томов, смонтированных с помощью PVC в режиме ReadWriteOncePod
.
Beta- и Stable-фичи
CSI driver migration для томов Portworx и vSphere (Beta) — миграция со встроенных в кодовую базу Kubernetes плагинов хранилищ на CSI-драйверы.
Local ephemeral storage resource management (Stable) — поддержка изоляции общих разделов локального хранилища для Pod’ов и контейнеров. Регулируется через requests.ephemeral-storage
и limits.ephemeral-storage
аналогично тому, как это реализовано для CPU и памяти.
CSI Ephemeral volumes (Stable) дает возможность использовать CSI-драйверы для создания не только удаленных, но и локальных эфемерных томов. При этом использовать PV или PVC не нужно: определять CSI-том можно прямо в спецификации Pod’а.
Планировщик
Take taints/tolerations into consideration when calculating PodTopologySpread
Узлы с какими-либо taints сообщают планировщику, что их нельзя использовать для запуска Pod’ов. Исключение делается для Pod’ов, у которых есть «допуск» — toleration. Два этих свойства помогают планировщику правильно распределять Pod’ы по узлам.
Еще один механизм регулировки распределения — набор ограничений на распространение топологии (topology spread constraints), которые указываются в поле topologySpreadConstraints
в настройках Pod’а. Одно из этих ограничений — skew, или «перекос». Он указывает, какое количество Pod’ов может быть распределено по узлам неравномерно через параметр maxSkew
. Параметр указывает максимальную разницу в количестве Pod’ов между двумя заданными топологическими доменами.
Когда планировщик вычисляет skew, он не отличает узлы с taints от обычных. Это может вызывать неожиданное подвисание Pod’а в статусе Pending
, потому что ограничение skew работает только с taint-узлами.
Цель улучшения — сделать так, чтобы планировщик учитывал свойства taints и tolerations при обработке ограничений на распространение топологии, а также — дать пользователям возможность явно указывать, стоит ли учитывать taints. Для этого в TopologySpreadConstraint
добавлены два новых поля — NodeAffinity
и NodeTaints
, которые устанавливаются в значение Ignore
/ Respect
с помощью новой политики NodeInclusionPolicy
. Пример того, как это работает:
-
NodeAffinity: Respect
означает, что узлы, указанные вnodeAffinity
иnodeSelector
, будут включены в skew-процесс; -
NodeAffinity: Ignore
(активно по умолчанию) означает, что в skew-процесс будут включены все узлы.
Аналогично работает и политика NodeTaint
.
Respect PodTopologySpread after rolling upgrades
Еще одно улучшение, связанное с топологией распределения Pod’ов. На этот раз решается проблема с несбалансированным распределением Pod’ов при плавающих обновлениях Depolyment’а (на эту тему есть соответствующие issues: #98215, #105661 — и обсуждение на StackOverflow).
В TopologySpreadConstraint
вводится новое поле MatchLabelKeys
в качестве дополнения к существующему labelSelector
. В новом поле передается набор ключей для лейблов Pod’ов — и это еще одно ограничение, которое планировщик учитывает при распределении. Пример:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
matchLabelKeys:
- app
- pod-template-hash
Плагин PodTopologySpread
ищет лейблы по ключам в matchLabelKeys
. Полученные лейблы объединяются с данными в поле labelSelector
для фильтрации и группировки Pod’ов. В результате Pod’ы, которые принадлежат одной группе, участвуют в распределении PodTopologySpread
.
Фича позволяет применять ограничения PodTopologySpread
только в границах новой ревизии Depolyment’а, а не во всех ревизиях, как это происходит сейчас.
Beta- и Stable-фичи
Min domains in PodTopologySpread (Beta) добавила новое поле minDomains
в настройки PodSpec.TopologySpreadConstraint
. Поле ограничивает минимальное количество доменов, через которые могут распределяться Pod’ы. Функция появилась в прошлом релизе K8s (подробности — в нашем обзоре).
Graduate the kube-scheduler ComponentConfig to GA (Stable) — стабилизация KubeSchedulerConfiguration. Поддержка v1beta2
в apiVersion
признана устаревшей; вместо нее нужно использовать v1beta3
или v1
. Также удален плагин SelectorSpread
, вместо которого используется PodTopologySpread
.
Сеть
Cleaning up IPTables Chain Ownership
Kubelet при запуске создает цепочки iptables. Некоторые из этих цепочек kubelet’у больше не нужны в связи с удалением модуля dockershim. Другие же дублируют цепочки, которые создает kube-proxy.
Решение — отказаться от большинства цепочек iptables, создаваемых kubelet’ом. Для этого добавлена опция IPTablesOwnershipCleanup
, которая:
-
Запрещает kubelet’у создавать цепочки
KUBE-MARK-DROP
,KUBE-MARK-MASQ
,KUBE-POSTROUTING
иKUBE-KUBELET-CANARY
(остается лишьKUBE-FIREWALL
для обработки марсианских пакетов). -
Предупреждает, что аргументы kubelet’а
--iptables-masquerade-bit
и--iptables-drop-bit
устарели и больше не работают.
Нельзя сказать, что улучшение сильно расширяет функциональность K8s, скорее — способствует «гигиене» кластера.
Multiple ClusterCIDRs
NodeIPAM-контроллер (IP Address Management) распределяет диапазоны IP-адресов между кластерами таким образом, что одному кластеру достается строго определенный набор IP-адресов — cluster CIDRs (Classless Inter-Domain Routing). Этот набор нельзя изменить, что ограничивает возможности распределения IP-адресов для Pod’ов. Например, когда нужно расширить кластер, для запуска новых Pod’ов может не хватить IP-адресов.
Новый ресурс ClusterCIDRConfig
реализует механизм распределения CIDRs для узлов, при котором пользователи могут менять диапазоны IP-адресов для Pod’ов (CIDR’ов) динамически и даже заранее настраивать их размер.
Также вместе с фичей добавлена поддержка нового NodeIPAM-контроллера, который «наблюдает» за объектами ClusterCIDRConfig
и узлами.
Beta- и Stable-фичи
Reserve Service IP Ranges For Dynamic and Static IP Allocation (Beta) — фича, которую представили в прошлом релизе Kubernetes. Жестко закрепляет определенный диапазон IP-адресов для статической и динамической раздачи clusterIP сервисам. Цель — снизить вероятность конфликтов при создании сервисов со статическими IP (см. наш обзор).
NetworkPolicy port range (Stable) добавила возможность определять в объекте NetworkPolicy диапазон портов, в то время как раньше нужно было определять каждый порт по отдельности. Функция помогает более гибко настраивать обработку ingress- и egress-трафика приложений. Пример настройки:
spec:
egress:
- ports:
- protocol: TCP
port: 32000
endPort: 32768
Разное
Auto-refreshing Official CVE Feed
По мере роста популярности Kubernetes увеличивается количество связанных с технологией уязвимостей (CVE). И хотя большинство из них оперативно закрываются, единого места, где хранилась бы актуальная информация о CVE, нет. Меж тем среди пользователей Kubernetes, включая K8s-провайдеров, немало тех, кому такая информация была бы полезна.
Авторы улучшения предлагают создать автоматически обновляемый список Kubernetes CVEs и разместить его по адресу https://kubernetes.io/docs/reference/issues-security/official-cve-feed
со ссылкой на странице Kubernetes Security and Disclosure Information. Список будет пополняться issues, которым присвоен лейбл official-cve-feed.
KMS v2 Improvements
Фича подразумевает многоэтапное улучшение сервиса Key Management Service (KMS), который используется для шифрования данных etcd по схеме envelope encryption. Глобальная цель фичи — упростить работу с KMS; также:
-
сократить время готовности кластеров с большим количеством зашифрованных ресурсов;
-
уменьшить вероятность превышения допустимого лимита для KMS-плагина;
-
улучшить наблюдаемость envelop-операций kube-apiserver’ом, KMS-плагинами и самим сервисом KMS.
Авторы KEP’а приводят подробный план реализации улучшения, включая примеры диаграмм запросов на шифрование и дешифрование.
Retriable and non-retriable Pod failures for Jobs
Чтобы ограничить время выполнения Job, используются два параметра:
-
activeDeadlineSeconds
— максимальное время выполнения Job’а; -
backoffLimit
— количество попыток запуска Job’а за отведенное (в предыдущем параметре) время.
Если Job не запускается, и политика перезапуска установлена в OnFailure
, Kubernetes попытается заново запустить Job — столько раз, сколько указано в backoffLimit
.
Job может не запускаться по разным причинам, и параметр backoffLimit
это не учитывает. В некоторых случаях могут возникать нежелательные перезапуски Job’а и, как следствие, Pod’а — например, когда есть ошибки в коде приложения, а в backoffLimit
указано 5
. В идеале такому Pod’у лучше бы вообще не запускаться, но Job руководствуется тем, что прописано в backoffLimit
, и перезапускает Pod. Проблема усугубляется в больших кластерах: перезапуск тысяч Pod’ов съедает немало времени и вычислительных ресурсов.
Нововведение помогает учитывать некоторые причины незапуска Job’а и, при необходимости, завершать его досрочно, игнорируя backoffLimit
. Для этого в Job API добавлено новое поле podFailurePolicy
. Ниже — пример для случая, когда требуется завершить Job, который не запускается из-за ошибок в исполняемом файле:
apiVersion: v1
kind: Job
spec:
template:
spec:
containers:
- name: job-container
image: job-image
command: ["./program"]
backoffLimit: 6
podFailurePolicy:
rules:
- action: Terminate
onExitCodes:
operator: NotIn
values: [40,41,42]
В параметре values
указаны допустимые коды завершения работы контейнера. Если контейнер завершает работу с другими кодами, Job завершается досрочно, не учитывая установленный backoffLimit
.
Beta-фичи
CRD Validation Expression Language предлагает упрощенный вариант проверки пользовательских ресурсов в CRD (Custom Resource Definition). Теперь, помимо вебхуков, для описания правил можно использовать скриптовый язык CEL.
Server Side Unknown Field Validation перекладывает функцию проверки неизвестных и дублирующих полей в запросах к API-серверу с клиентской части (пользователя) на серверную. Мотив: проверку на стороне клиента организовать значительно сложнее, чем на стороне сервера.
TimeZone support in CronJob добавляет новое поле в CronJob API — .spec.timeZone
, где можно заранее установить часовой пояс для запуска Job’а. Помогает избежать возможной несогласованности между часовыми поясами kube-controller-manager’а и Job’а, который он запускает.
Stable-фичи
MaxSurge support for DaemonSets позволяет обновлять рабочие нагрузки DaemonSet’а во время плавающих обновлений без простоя: старый Pod отключается только после того, как запускается новый. Функция регулируется параметром updateStrategy.rollingUpdate.maxSurge
в поле updateStrategy
, где указывается, сколько новых Pod’ов нужно создать на замену старым.
Add minReadySeconds to Statefulsets — фича добавила в настройки StatefulSet’а новое поле minReadySeconds
. В нем определяется количество секунд, по истечении которых созданный Pod может считаться готовым к работе. Функция аналогична уже реализованным для Deployment’а, DaemonSet’а и ReplicasSet’а.
Identify Windows pods at API admission level authoritatively — нововведение, призванное улучшить процесс идентификации ОС Pod’а при его подключении к API-серверу.
PodSecurity admission (PodSecurityPolicy replacement) — новый контроллер доступа, который заменил устаревший PodSecurityPolicy. PodSecurity admission определяет стандарты безопасности Pod’ов на уровне пространства имен, ориентируясь на лейблы. Подробнее о работе нового контроллера мы писали в обзоре K8s 1.22. Для тех, кто пока еще использует PodSecurityPolicy, есть инструкция по миграции на PodSecurity Admission Controller.
Некоторые из удаленных фич
-
Контроллер PodSecurityPolicy.
-
Флаг
--service-account-api-audiences
в запросе к API-серверу заменен на--api-audiences
. -
VSphere версии ниже 7.0 U2.
-
Windows winkernel Kube-proxy больше не поддерживает Windows HNS v1 APIs.
-
Встроенные плагины томов GlusterFS, flocker, quobyte, storageos.
-
Неиспользуемые флаги в
kubectl run
. -
Ряд аннотаций seccomp.
Обновления в зависимостях Kubernetes
-
containerd v1.4.9;
-
Go 1.18.3;
-
etcd v3.5.4;
-
cri-tools v1.24.2.
P.S.
Читайте также в нашем блоге:
Автор: Oleg Zinovyev