Kubernetes 1.19: обзор основных новшеств

Сегодня, 25 августа, состоится новый релиз Kubernetes (его в общей сложности задержали почти на 2 месяца) — 1.19. По традиции нашего блога, рассказываем о наиболее значимых изменениях в новой версии.

ikfkvcpsfthwkjwnot2onqz2b0i.png

Информация, использованная для подготовки этого материала, взята из официального анонса, таблицы 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:

ayggsrh5hzldlr36zntman-i6do.png
(На момент опроса актуальной версией 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 месяцев (двух релизов) и не удовлетворяют ни одному из этих условий:

  1. соответствуют критериям GA и продвигаются в стабильный статус;
  2. имеют новую бета-версию, которая делает устаревшей прошлую бету.


А теперь — о других изменениях в 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.backendspec.defaultBackend, serviceNameservice.name, servicePortservice.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.


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

© Habrahabr.ru