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

Этой ночью, 8 декабря (по американскому времени), состоялся новый релиз Kubernetes — 1.20. По традиции нашего блога, рассказываем о наиболее значимых изменениях в новой версии.

qwbvvkobtb76zxaqup9wrorl9mu.png

Информация, использованная для подготовки этого материала, взята из таблицы Kubernetes enhancements tracking, CHANGELOG-1.20, обзора Sysdig, а также соответствующих issues, pull requests, Kubernetes Enhancement Proposals (KEP).

Docker как deprecated


Пожалуй, главной темой этого релиза стал отказ от Docker в kubelet, о чём широкой общественности стало известно благодаря твиту Davanum Srinivas — инженера из VMware, который и стал непосредственным автором самого изменения:
Если говорить о технической сути произошедшего и очень кратко, то, пожалуй, достаточно демонстрации таких двух схем (заимствованы из публикации Tariq Islam — Cloud Solutions Engineer из Google).

Запуск контейнеров в Kubernetes до сих пор выглядел так:

heemk_yjopmn1g4uj2vuirxi268.png

Но мир не стоит на месте, а уж cloud native-мир со всеми его контейнерами, механизмами взаимодействия с ними и стандартами — подавно. Поэтому длинная цепочка упрощается до следующей:

v0szj6zk-fc-xhboznnrrqvtepy.png

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


Узлы Kubernetes (kubelets)


И продолжим со связанного с dockershim изменения — повышения статуса поддержки CRI (Container Runtime Interface) до бета-версии (KEP-2040). Исполняемые среды для контейнеров на базе интерфейса CRI — CRI-O и containerd — уже долгое время (более года) используются разными компаниями в production с текущим API, поэтому авторы данного изменения «хотят показать пользователям, что CRI API готово к production и можно не бояться переходить с dockershim, который признан deprecated». Когда же CRI планируют перевести на итоговый уровень стабильности (stable/GA), пока не сообщается.

Попутно стоит отметить, что поддержка cri-containerd для Windows объявлена стабильной. (GA для Linux-версии была объявлена более 2 лет назад.)

Новая возможность для kubelet’ов — Graceful Node Shutdown (KEP-2000) — призвана сообщать им о завершении работы узла и вызывать корректное, «мягкое» (graceful) выключение соответствующих pod’ов. Предусматривается обработка команд shutdown -h, systemctl poweroff, физического нажатия на кнопку питания и его аналогов для виртуальных машин и облачных инстансов (например, gcloud compute instances stop). В реализации отслеживаются ACPI-сигналы, предусмотрено взаимодействие с systemd-logind, а в конфигурации kubelet для этого появился параметр ShutdownGracePeriod (по умолчанию равен 0). Текущая версия — альфа, повышение до беты ожидается в Kubernetes 1.21.

Другая новая фича в альфа-версии — изменяемый размер томов, хранимых в оперативной памяти (KEP-1967). Сейчас размер для томов emptyDir, которые хранятся в оперативной памяти (tmpfs), по умолчанию выделяется в объеме 50% памяти Linux-хоста. Однако это вызывает ряд сложностей (при активном использовании /dev/shm и других задач вроде AI/ML, а также в переносимости), которые и призвано решить нововведение. Оно устанавливает размер таких томов по умолчанию равным объёму выделяемой pod’у памяти и позволяет изменять это значение на меньшее.

Многие фичи переведены в статус стабильных (GA):


Но и это ещё не всё:

  • kubelet научили учитывать таймаут для вызова проб (альфа-версия, KEP-1972);
  • Node Topology Manager, хоть и остался в бета-версии, получил новую возможность — scope, — определяющую уровень, на котором требуется выравнивать ресурсы (например, pod или container);
  • добавлена поддержка HugePages в downward API (KEP-2053): теперь этот ресурс виден pod’ам так же, как и CPU, память и другие (пока в альфа-версии).


Аутентификация и безопасность


Новая возможность на пересечении sig-auth и sig-storage — альфа-версия поддержки Service Account Token для CSI-драйверов (KEP-1855). Идея в том, чтобы CSI-драйверы могли запрашивать и получать у kubelet’а токены ServiceAccount для pod’ов, которым они монтируют тома, — в противовес существующему подходу с прямым считыванием токенов из файловой системы. Эти токены действительны ограниченное время, поэтому у драйверов также предусмотрена возможность повторного вызова NodePublishVolume для монтирования томов.

Другое улучшение безопасности затрагивает инфраструктуру для сборки и релизов Kubernetes: представлена защита от логирования секретов на основе статического анализа (KEP-1933). Появление такого механизма мотивируется результатами аудита безопасности кодовой базы K8s, проведенного американской компанией Trail of Bits в прошлом году (проверка осуществлялась на версии Kubernetes 1.13.4). Его авторы заключают, что конфиденциальная информация не должна открыто появляться в логах. Для реализации соответствующего статического анализа используется утилита go-flow-levee от Google, вызываемая в системе Prow при тестировании pull-запросов, поступающих в репозитории Kubernetes.

scsnvodfieexhtf1vfereiumyfi.png
Фрагмент итогов аудита Kubernetes от Trail of Bits

Другая инициатива, связанная с логами и безопасностью, — logs sanitization (KEP-1753), т.е. постоянная очистка логов от потенциально опасных данных. В его рамках решаются следующие задачи: предотвращение попадания в логи известных видов конфиденциальных данных, упрощённая возможность добавлять новые источники таких данных в фильтры, а также ограничение влияния всех этих процессов на общую производительность.

Для client-go credential plugins добавили поддержку переменной окружения KUBERNETES_EXEC_INFO: через неё можно (опционально) передавать информацию о кластере, для которого плагин получает учётные данные. Сама поддержка таких внешних провайдеров осталась в бета-версии, их стабилизация отложена до следующих релизов Kubernetes.

Наконец, поддержка TokenRequest и TokenRequestProjection (из KEP-1205) для того, чтобы pod’ы могли запрашивать ServiceAccount-токены, объявлена стабильной. Но работа над интеграцией TokenRequest API и Kubelet в целом ещё не завершена: другие её изменения ждут более стабильных версий.

Сети


В альфа-версии стало возможнымотключать NodePorts для сервисов с типом LoadBalancer (KEP-1864). До сих пор для каждого порта сервиса LoadBalancer в Kubernetes автоматически выделялся порт узла. Хотя это действительно чаще всего необходимо, в жизни так происходит не всегда: примерами подобных исключений являются MetalLB и kube-router. Теперь в Service.Spec есть специальное булево поле allocateLoadBalancerNodePort, регулирующее соответствующую настройку.

Достигла своей альфа-версии и другая возможность, связанная с LoadBalancer’ами и развиваемая с начала этого года. Теперь в сервисах LoadBalancer можно определять одни и те же порты для разных протоколов (KEP-1435). Например, стала доступной такая конфигурация:

apiVersion: v1
kind: Service
metadata:
  name: mixed-protocol
spec:
  type: LoadBalancer
  ports:
    - name: dns-udp
      port: 53
      protocol: UDP
    - name: dns-tcp
      port: 53
      protocol: TCP
  selector:
    app: my-dns-server


Набор допустимых протоколов при этом определяется облачным провайдером.

Работа над поддержкой двойного сетевого стека IPv4/IPv6 продолжается. Хоть эта фича и осталась в альфа-версии, она принесла значительные обновления, которые появились в ответ на запросы пользователей/сообщества. В частности, теперь можно переключать сервисы с single-stack на dual-stack (и наоборот) — параметром ipFamilyPolicy в спецификации, который принимает говорящие за себя значения: SingleStack, PreferDualStack, RequireDualStack. Пример конфигурации для сервиса с dual-stack:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  labels:
    app: MyApp
spec:
  ipFamilyPolicy: PreferDualStack
  ipFamilies:
  - IPv6
  type: LoadBalancer
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80


Подробности по использованию dual-stack — см. в KEP и документации.

В EndpointSlice API добавлена возможность отслеживания endpoint’ов, которые завершают свою работу (KEP-1672). Для этого в структуру EndpointConditions введено новое поле (terminating), информирующее о том, что endpoint сейчас прекращает свою работу. Теперь достаточно считать его вместо того, чтобы отслеживать статусы pod’ов, связанных с endpoint’ом, как было раньше.

Среди других сетевых новшеств:


Хранилища


Функция создания/восстановления снапшотов томов для CSI-драйверов (KEP-177) стала стабильной. Документация не изменилась и доступна на прежнем месте.

Других изменений в sig-storage не так много:

  • возможность для CSI-драйверов определять права доступа на основе FSGroup перешла в бета-версию;
  • возможность пропускать рекурсивную смену владельца/прав перед bind-монтированием тома в контейнер (для лучшей производительности) тоже объявлена бетой.


Прочие изменения


Новое улучшение для Horizontal Pod Autoscaler добавляет возможность учёта потребления ресурсов отдельными контейнерами при принятии решений о масштабировании. Сейчас вместо этого для горизонтального масштабирования используются общие значения со всех pod’ов, однако бывают сценарии, где подобные решения не являются оптимальными, т.е. нет прямой корреляции потребления ресурсов отдельными контейнерами на общее. Авторы приводят такие примеры:

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


Новый подход, пока реализованный как альфа-версия и описанный в этом KEP, вводит дополнительный источник метрики ContainerResourceMetricSource (вдобавок к существующему ResourceMetricSource).

Пример конфигурации HPA для случая, когда требуется масштабировать на основе данных только одного из контейнеров:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: mission-critical
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: mission-critical
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: ContainerResource
    resource:
      name: cpu
      container: application
      target:
        type: Utilization
        averageUtilization: 30


Пополнение в метриках — альфа-версия Pod Resource Request Metrics (KEP-1748). Идея заключается в создании «из коробки» достаточного количества метрик, необходимых для планирования ресурсов кластера и простого представления модели ресурсов Kubernetes. Для её реализации в kube-scheduler появились новые метрики по запрашиваемым ресурсам (kube_pod_resource_requests) и желаемым лимитам (kube_pod_resource_limits) для всех запущенных pod’ов — они активируются по HTTP на /metrics/resources при использовании флага --show-hidden-metrics-for-version=1.20.

С новой фичей, названной Kubelet Credential Provider или Out-of-Tree Credential Providers (KEP), kubelet получил возможность динамически получать учетные данные (credentials) для реестров контейнерных образов (container registry), вызывая сторонние плагины — специфичные для облачных провайдеров биинарники. Взаимодействие с плагинами происходит по Kubernetes API через stdio. Вынос специфичного кода провайдеров из ядра Kubernetes следует общему тренду смены in-tree на out-of-tree для растущей кодовой базы проекта. Текущая реализация — альфа-версия, подробности — в документации Kubernetes.

CronJob API, который до сих пор находился в бета-версии (с релиза Kubernetes 1.8, а это более 3 лет назад!), решили продвинуть до стабильного уровня, однако одновременно с этим его код переписывают (KEP) с целью улучшить масштабируемость (использовать информеры вместо polling) и добавить метрики (пропускная способность контроллера, задержки и т.п.). Для активации необходимо включить feature gate под названием CronJobControllerV2.

Кроме того:

  • представленный в K8s 1.18 механизм API Priority and Fairness (APF) для более тонкого контролирования ограничения запросов к API-серверу (с продвинутой системой приоритетов) переведён в бета-версию;
  • команда kubectl debug перешла в бета-версию (все вызовы kubectl alpha debug необходимо заменить на kubectl debug);
  • label и taint под названием node-role.kubernetes.io/master, добавляемый kubeadm’ом на узлы, переименован в node-role.kubernetes.io/control-plane;
  • каждому kube-apiserver в HA-кластерах теперь назначается уникальный идентификатор, а у контроллеров есть возможность просмотра их списка во всем кластере (альфа-версия, KEP-1965).


Прочие изменения


Обновления в зависимостях Kubernetes:

  • cri-tools 1.19.0;
  • CNI (Container Networking Interface) 0.8.7, Calico 3.15.2;
  • etcd 3.4.13;
  • используемая версия Go — 1.15.5.


Немного статистики


В составе релиза Kubernetes 1.20 насчитывается 42 улучшения: 11 перешли в stable, 15 — beta, 16 — alpha.

За время его подготовки — 11 недель с 25 сентября по 9 декабря — в репозитории проекта внесли свою лепту 967 компаний и 1335 индивидуумов (44 из них сделали это впервые) из 26 стран.

В число этих компаний попал и «Флант» с несколькими contributions (см. «Flant» в этом списке).

Топ-10 компаний по числу contributions (включают в себя коммиты, PR, issues и т.п.) для последнего релиза выглядит следующим образом:

  1. Google (32284);
  2. VMware (17598);
  3. Red Hat (10935);
  4. Microsoft (7062);
  5. IBM (5857);
  6. The Scale Factory (2151);
  7. Samsung SDS (1471);
  8. Glassdoor (1406);
  9. SUSE (1319);
  10. Kubermatic (1300).


P.S.


Разработчики Kubernetes присвоили релизу v1.20 имя «raddest» (английский сленг, который переводится как «отличный, замечательный, классный»). Потому что, несмотря на сложный для всех год, сообществу удалось привнести рекордное число значимых изменений в этот релиз.

А такой кот стал официальным логотипом релиза Kubernetes v1.20:

niyrlngczhvjzoyav9lg2032vr0.jpeg

P.P. S.


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

© Habrahabr.ru