Kubernetes 1.19: обзор основных новшеств
Сегодня, 25 августа, состоится новый релиз Kubernetes (его в общей сложности задержали почти на 2 месяца) — 1.19. По традиции нашего блога, рассказываем о наиболее значимых изменениях в новой версии.
Информация, использованная для подготовки этого материала, взята из официального анонса, таблицы Kubernetes enhancements tracking, CHANGELOG-1.19, обзора Sysdig, а также соответствующих issues, pull requests, Kubernetes Enhancement Proposals (KEP).
Начнём с нескольких крупных новшеств достаточно общего характера…
С выпуском Kubernetes 1.19 «окно поддержки» для версий Kubernetes было увеличено с 9 месяцев (т.е. 3 последних релизов) до 1 года (т.е. 4 релизов). Почему?
Оказалось, что из-за высокой скорости развития проекта (частых major-релизов) администраторы кластеров Kubernetes не успевают обновлять свои инсталляции. Авторы соответствующего KEP ссылаются на опрос, проведённый рабочей группой в начале прошлого года и показавший, что около трети пользователей Kubernetes имеют дело с устаревшими релизами K8s, запущенными в production:
(На момент опроса актуальной версией Kubernetes была 1.13, т.е. все пользователи K8s 1.9 и 1.10 работали с релизами, которые на тот момент уже не поддерживались.)
Таким образом, предполагается, что продление на 3 месяца периода поддержки релизов Kubernetes — выпуска патчей, исправляющих обнаруженные в коде проблемы, — позволит добиться того, что более 80% пользователей будут работать на поддерживаемых версиях K8s (вместо предполагаемых 50–60% на данный момент).
Другое большое событие: выработан стандарт для структурированных логов. Нынешняя система логирования в control plane не гарантирует единой структуры для сообщений и ссылок на объекты в Kubernetes, что усложняет обработку таких логов. Чтобы решить эту проблему, вводится новая структура для сообщений в логах, для чего библиотеку klog расширили новыми методами, которые предоставляют структурированный интерфейс для формирования логов, а также вспомогательными методами для идентификации K8s-объектов в логах.
Одновременно с миграцией на klog v2 осуществляется и переход на новый формат вывода логов в JSON, который упростит выполнение запросов к логам и их обработку. Для этого появляется флаг --logging-format
, который по умолчанию использует прежний текстовый формат.
Поскольку репозиторий Kubernetes огромен, а авторы KEP по структурированному логированию — реалисты, они сосредоточат свои усилия по воплощению в жизнь новых идей на наиболее общих сообщениях.
Иллюстрация логирования с помощью новых методов в klog:
klog.InfoS("Pod status updated", "pod", "kubedns", "status", "ready")
I1025 00:15:15.525108 1 controller_utils.go:116] "Pod status updated" pod="kubedns"
klog.InfoS("Pod status updated", "pod", klog.KRef("kube-system", "kubedns"), "status", "ready")
I1025 00:15:15.525108 1 controller_utils.go:116] "Pod status updated" pod="kube-system/kubedns" status="ready"
klog.ErrorS(err, "Failed to update pod status")
E1025 00:15:15.525108 1 controller_utils.go:114] "Failed to update pod status" err="timeout"
Использование формата JSON:
pod := corev1.Pod{Name: "kubedns", Namespace: "kube-system", ...}
klog.InfoS("Pod status updated", "pod", klog.KObj(pod), "status", "ready")
{
"ts": 1580306777.04728,
"v": 4,
"msg": "Pod status updated",
"pod":{
"name": "nginx-1",
"namespace": "default"
},
"status": "ready"
}
Ещё одно важное (и очень актуальное) новшество — механизм информирования об устаревших (deprecated) API, реализованный сразу в виде бета-версии (т.е. активен в инсталляциях по умолчанию). Как объясняют авторы, у Kubernetes постоянно множество устаревших возможностей, пребывающих в разном состоянии и с разными временными перспективами. Следить за ними, внимательно читая все Release Notes и вручную вычищая конфиги/настройки, практически нереально.
Для решения этой проблемы теперь при использовании устаревшего API в его ответы добавляется заголовок Warning
, который распознаётся на стороне клиента (client-go
) с возможностью разного реагирования: игнорировать, дедуплицировать, логировать. В утилите kubectl научили выводить эти сообщения в stderr, подсвечивать цветом сообщение в консоли, а также добавили флаг --warnings-as-errors
с говорящим за себя названием.
В дополнение к этому, добавлены специальные метрики, сообщающие об использовании устаревших API и audit-аннотации.
Наконец, разработчики озаботились продвижением фич Kubernetes из бета-версии. Как показал опыт проекта, некоторые новые фичи и изменения в API «застревали» в статусе Beta по той причине, что они уже автоматически (по умолчанию) активировались и не требовали дальнейших действий от пользователей.
Чтобы этого не происходило, предложено автоматически отправлять в список устаревания те фичи, которые находятся в бета-версии на протяжении 6 месяцев (двух релизов) и не удовлетворяют ни одному из этих условий:
- соответствуют критериям GA и продвигаются в стабильный статус;
- имеют новую бета-версию, которая делает устаревшей прошлую бету.
А теперь — о других изменениях в Kubernetes 1.19, разбитых по категориям соответствующих им SIG.
Хранилища
Новые объекты CSIStorageCapacityпризваны улучшить процесс планирования pod’ов, в которых используются CSI-тома: они не будут размещаться на узлах, в хранилищах которых закончилось место. Для этого информация о доступном дисковом пространстве будет храниться в API-сервере, доступна CSI-драйверам и планировщику. Текущий статус реализации — альфа-версия; подробности — в KEP.
Другое новшество в альфа-версии — возможность определения эфемерных томов прямо в спецификациях pod’ов, generic ephemeral inline volumes (KEP). Эфемерные тома создаются для определённых pod’ов во время их появления и удаляются вместе с завершением их работы. Их можно было определять и раньше (в том числе, прямо в спецификации, т.е. методом inline), однако существующий подход, доказав состоятельность самой фичи, покрывал не все случаи её использования.
Новый механизм предлагает простой API, позволяющий определять эфемерные тома для любого драйвера с поддержкой динамического provisioning’а (раньше для этого пришлось бы модифицировать драйвер). Он позволяет работать с любыми эфемерными томами (и CSI, и in-tree вроде EmptyDir
), а также обеспечивает поддержку другой новой фичи (описанной чуть выше) — отслеживания доступного пространства хранилища.
Пример высокоуровневого объекта Kubernetes, использующего новый эфемерный том (generic inline):
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
volumeMounts:
- name: varlog
mountPath: /var/log
- name: scratch
mountPath: /scratch
volumes:
- name: varlog
hostPath:
path: /var/log
- name: scratch
ephemeral:
metadata:
labels:
type: fluentd-elasticsearch-volume
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "scratch-storage-class"
resources:
requests:
storage: 1Gi
Здесь контроллер DaemonSet создаёт pod’ы с именами вида fluentd-elasticsearch-b96sd
, после чего для такого pod’а будет добавлен PersistentVolumeClaim fluentd-elasticsearch-b96sd-scratch
.
И последняя полностью новая фича в области хранения, появившаяся как альфа-версия, — новое поле csidriver.spec.SupportsFSGroup
для CSI-драйверов, указывающее на факт поддержки определения прав доступа на основе FSGroup (KEP). Мотивация: смена владельца для CSI-тома выполняется перед тем, как он монтируется в контейнер, однако не все виды хранилищ поддерживают такую операцию (например, NFS), из-за чего сейчас она может приводить к ошибкам.
До бета-версии (т.е. включения по умолчанию) «доросли»:
Узлы / Kubelet
Поддержка seccomp объявлена стабильной (GA). В частности, эти работы привели к переходу на поля для seccomp в API вместо аннотаций, объявленных устаревшими (новые Kubelet’ы игнорируют аннотации), и затронули PodSecurityPolicy.
В PodSpec добавлено новое поле fqdnInHostname
, позволяющее задавать FQDN (Fully Qualified Domain Name) для хоста pod’а. Цель — улучшение поддержки устаревших (legacy) приложений в Kubernetes. Вот как авторы объясняют свои намерения:
«Традиционно Unix и некоторые Linux-дистрибутивы, такие как Red Hat и CentOS, рекомендовали устанавливать FQDN-хост в поле ядра hostname. Как следствие, многие приложения, созданные до Kubernetes, полагаются на такое поведение. Наличие подобной фичи поможет контейнеризировать существующие приложения без рискованных изменений кода».
Значением по умолчанию будет false
, чтобы сохранить прежнее (для Kubernetes) поведение. Статус фичи — альфа-версия, которую планируется объявить стабильной уже в следующем релизе (1.20).
Принято решение отказаться от метрик Accelerator Metrics, собираемых Kubelet. Сбор таких метрик предлагается выполнять внешними агентами мониторинга через PodResources API. Сам этот API был созданно именно с целью выноса всех специфичных для устройств метрик из основного репозитория Kubernetes, позволив вендорам реализовывать их без внесения изменений в ядро Kubernetes. PodResources API находится в бета-версии (за него отвечает feature gate KubeletPodResources
) и скоро станет стабильным. Для текущего релиза процесс отказа имеет статус альфа-версии, подробности — в KEP.
Отныне Kubelet можно собирать без Docker: под этим «без» авторы подразумевают отсутствие любого специфичного для Docker кода и зависимости от Golang-пакета docker/docker
. Конечная цель этой инициативы — прийти к полностью «dockerless» (т.е. лишенному зависимости от Docker’а) Kubelet. Подробнее о мотивации можно прочитать, как всегда, в KEP. Эта возможность сразу получила статус GA.
Менеджер топологии узла (Node Topology Manager), достигший своей бета-версии в прошлом релизе K8s, получил возможность выравнивания ресурсов на уровне pod’ов.
Планировщик
Ещё в Kubernetes 1.18 мы писали про глобальную конфигурацию для равномерного распределения pod’ов (Even Pod Spreading), однако тогда эту фичу было решено отложить по итогам тестирования производительности. Теперь она вошла в Kubernetes (в статусе альфа-версии).
Суть новшества заключается в добавлении глобальных ограничений (DefaultConstraints
), позволяющих регулировать правила распределения pod’ов на более высоком уровне — на уровне кластера, а не только в PodSpec
(через topologySpreadConstraints
), как было до сих пор. Конфигурация по умолчанию будет схожа с нынешним плагином DefaultPodTopologySpread
:
defaultConstraints:
- maxSkew: 3
topologyKey: "kubernetes.io/hostname"
whenUnsatisfiable: ScheduleAnyway
- maxSkew: 5
topologyKey: "topology.kubernetes.io/zone"
whenUnsatisfiable: ScheduleAnyway
Подробности — в KEP.
Другая возможность, связанная с Even Pod Spreading: распределение группы pod’ов по failure domains (регионам, зонам, узлам и т.п.), — переведена из альфа-версии в бету (включена по умолчанию).
Аналогичного «повышения» достигли и три другие фичи в планировщике:
Сети
Ресурс Ingress наконец-то объявлен стабильным и получил версию v1
в API. В связи с этим, немало обновлений было представлено в соответствующей документации. Особое внимание стоит обратить на заметные пользователю изменения из этого PR: например, там есть такие переименования, как spec.backend
→ spec.defaultBackend
, serviceName
→ service.name
, servicePort
→ service.port.number
…
В статус бета-версии переведены поле AppProtocol для Services и Endpoints, а также EndpointSlice API (kube-proxy на Linux начинает использовать EndpointSlices по умолчанию, но для Windows остался в альфа-версии) и поддержка протокола SCTP.
kubeadm
Две новые фичи (в альфа-версии) представлены для утилиты kubeadm.
Первая — использование патчей для модификации манифестов, генерируемых kubeadm. Их модификация уже была возможна с помощью Kustomize (в альфа-версии), однако разработчики kubeadm решили, что использование обычных патчей является более предпочтительным способом (поскольку Kustomize становится лишней зависимостью, что не приветствуется).
Теперь применение raw-патчей возможно (через флаг --experimental-patches
) для команд kubeadm init
, join
и upgrade
, а также их фаз. Реализацию на базе Kustomize (флаг --experimental-kustomize
) объявят устаревшей и удалят.
Вторая фича — новый подход к работе с конфигами компонентов, с которыми работает kubeadm. Утилита генерирует, валидирует, устанавливает значения по умолчанию, хранит конфиги (в виде ConfigMaps) для таких компонентов кластера Kubernetes, как Kubelet и kube-proxy. Со временем стало ясно, что это приносит ряд сложностей: как различать конфиги, сгенерированные kubeadm или переданные пользователем (а если никак, то что делать с миграцией конфига)? Какие поля со значениями по умолчанию были автоматически сгенерированы, а какие — намеренно установлены?…
Для решения этих проблем и представлен большой комплекс изменений, включающий в себя: отказ от выставления значений по умолчанию (это должны делать сами компоненты), делегацию валидации конфигов самим компонентам, подписывание каждого сгенерированного ConfigMap и т.п.
Прочие изменения
- Статус GA получили 3 фичи в области аутентификации: CertificateSigningRequest API, ограничение доступа узлов к определённым API (через admission-плагин
NodeRestriction
), bootstrap и автоматическое обновление клиентского сертификата Kubelet. - Также объявлен стабильным новый Event API с измененным подходом к дедупликации (во избежание перегрузки кластера событиями);
- Kubelet и стандартный Docker runtime теперь поддерживают запуск эфемерных контейнеров в пространстве имен процессов target-контейнера, определяемого полем
TargetContainerName
в EphemeralContainer (реализация в других исполняемых средах ожидается). - Поддержка cri-containerd в Windows достигла бета-версии.
Изменения в зависимостях:
- версия CoreDNS в составе kubeadm — 1.7.0;
- cri-tools 1.18.0;
- CNI (Container Networking Interface) 0.8.6;
- etcd 3.4.9;
- используемая версия Go — 1.15.0-rc.1.
P.S.
Читайте также в нашем блоге: