Этой ночью, 8 декабря (по американскому времени), состоялся новый релиз Kubernetes — 1.20. По традиции нашего блога, рассказываем о наиболее значимых изменениях в новой версии.
Информация, использованная для подготовки этого материала, взята из таблицы Kubernetes enhancements tracking, CHANGELOG-1.20, обзора Sysdig, а также соответствующих issues, pull requests, Kubernetes Enhancement Proposals (KEP).
Пожалуй, главной темой этого релиза стал отказ от Docker в kubelet, о чём широкой общественности стало известно благодаря твиту Davanum Srinivas — инженера из VMware, который и стал непосредственным автором самого изменения:
Если говорить о технической сути произошедшего и очень кратко, то, пожалуй, достаточно демонстрации таких двух схем (заимствованы из публикации Tariq Islam — Cloud Solutions Engineer из Google).
Запуск контейнеров в Kubernetes до сих пор выглядел так:
Но мир не стоит на месте, а уж cloud native-мир со всеми его контейнерами, механизмами взаимодействия с ними и стандартами — подавно. Поэтому длинная цепочка упрощается до следующей:
Подробнее останавливаться на этом событии не будем, поскольку уже переводили для своего блога официальное заявление проекта Kubernetes по этому поводу: «Не паникуйте: Kubernetes и Docker». Кроме того, в интернете легко найти другие многочисленные материалы по теме. Среди них:
И продолжим со связанного с 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'ов. Предусматривается обработка команд
Другая новая фича в альфа-версии — изменяемый размер томов, хранимых в оперативной памяти (KEP-1967). Сейчас размер для томов
Многие фичи переведены в статус стабильных (GA):
Но и это ещё не всё:
Новая возможность на пересечении sig-auth и sig-storage — альфа-версия поддержки Service Account Token для CSI-драйверов (KEP-1855). Идея в том, чтобы CSI-драйверы могли запрашивать и получать у kubelet'а токены ServiceAccount для pod'ов, которым они монтируют тома, — в противовес существующему подходу с прямым считыванием токенов из файловой системы. Эти токены действительны ограниченное время, поэтому у драйверов также предусмотрена возможность повторного вызова
Другое улучшение безопасности затрагивает инфраструктуру для сборки и релизов Kubernetes: представлена защита от логирования секретов на основе статического анализа (KEP-1933). Появление такого механизма мотивируется результатами аудита безопасности кодовой базы K8s, проведенного американской компанией Trail of Bits в прошлом году (проверка осуществлялась на версии Kubernetes 1.13.4). Его авторы заключают, что конфиденциальная информация не должна открыто появляться в логах. Для реализации соответствующего статического анализа используется утилита go-flow-levee от Google, вызываемая в системе Prow при тестировании pull-запросов, поступающих в репозитории Kubernetes.
Фрагмент итогов аудита Kubernetes от Trail of Bits
Другая инициатива, связанная с логами и безопасностью, — logs sanitization (KEP-1753), т.е. постоянная очистка логов от потенциально опасных данных. В его рамках решаются следующие задачи: предотвращение попадания в логи известных видов конфиденциальных данных, упрощённая возможность добавлять новые источники таких данных в фильтры, а также ограничение влияния всех этих процессов на общую производительность.
Для client-go credential plugins добавили поддержку переменной окружения
Наконец, поддержка
В альфа-версии стало возможным отключать NodePorts для сервисов с типом LoadBalancer (KEP-1864). До сих пор для каждого порта сервиса LoadBalancer в Kubernetes автоматически выделялся порт узла. Хотя это действительно чаще всего необходимо, в жизни так происходит не всегда: примерами подобных исключений являются MetalLB и kube-router. Теперь в
Достигла своей альфа-версии и другая возможность, связанная с LoadBalancer'ами и развиваемая с начала этого года. Теперь в сервисах LoadBalancer можно определять одни и те же порты для разных протоколов (KEP-1435). Например, стала доступной такая конфигурация:
Набор допустимых протоколов при этом определяется облачным провайдером.
Работа над поддержкой двойного сетевого стека IPv4/IPv6 продолжается. Хоть эта фича и осталась в альфа-версии, она принесла значительные обновления, которые появились в ответ на запросы пользователей/сообщества. В частности, теперь можно переключать сервисы с single-stack на dual-stack (и наоборот) — параметром
Подробности по использованию dual-stack — см. в KEP и документации.
В EndpointSlice API добавлена возможность отслеживания endpoint'ов, которые завершают свою работу (KEP-1672). Для этого в структуру
Среди других сетевых новшеств:
Функция создания/восстановления снапшотов томов для CSI-драйверов (KEP-177) стала стабильной. Документация не изменилась и доступна на прежнем месте.
Других изменений в sig-storage не так много:
Новое улучшение для Horizontal Pod Autoscaler добавляет возможность учёта потребления ресурсов отдельными контейнерами при принятии решений о масштабировании. Сейчас вместо этого для горизонтального масштабирования используются общие значения со всех pod'ов, однако бывают сценарии, где подобные решения не являются оптимальными, т.е. нет прямой корреляции потребления ресурсов отдельными контейнерами на общее. Авторы приводят такие примеры:
Новый подход, пока реализованный как альфа-версия и описанный в этом KEP, вводит дополнительный источник метрики
Пример конфигурации HPA для случая, когда требуется масштабировать на основе данных только одного из контейнеров:
Пополнение в метриках — альфа-версия Pod Resource Request Metrics (KEP-1748). Идея заключается в создании «из коробки» достаточного количества метрик, необходимых для планирования ресурсов кластера и простого представления модели ресурсов Kubernetes. Для её реализации в kube-scheduler появились новые метрики по запрашиваемым ресурсам (
С новой фичей, названной 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 под названием
Кроме того:
Обновления в зависимостях Kubernetes:
В составе релиза Kubernetes 1.20 насчитывается 42 улучшения: 11 перешли в stable, 15 — beta, 16 — alpha.
За время его подготовки — 11 недель с 25 сентября по 9 декабря — в репозитории проекта внесли свою лепту 967 компаний и 1335 индивидуумов (44 из них сделали это впервые) из 26 стран.
В число этих компаний попал и «Флант» с несколькими contributions (см. «Flant» в этом списке).
Топ-10 компаний по числу contributions (включают в себя коммиты, PR, issues и т.п.) для последнего релиза выглядит следующим образом:
Разработчики Kubernetes присвоили релизу v1.20 имя «raddest» (английский сленг, который переводится как «отличный, замечательный, классный»). Потому что, несмотря на сложный для всех год, сообществу удалось привнести рекордное число значимых изменений в этот релиз.
А такой кот стал официальным логотипом релиза Kubernetes v1.20:
Читайте также в нашем блоге:
Информация, использованная для подготовки этого материала, взята из таблицы 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 до сих пор выглядел так:
Но мир не стоит на месте, а уж cloud native-мир со всеми его контейнерами, механизмами взаимодействия с ними и стандартами — подавно. Поэтому длинная цепочка упрощается до следующей:
Подробнее останавливаться на этом событии не будем, поскольку уже переводили для своего блога официальное заявление проекта Kubernetes по этому поводу: «Не паникуйте: Kubernetes и Docker». Кроме того, в интернете легко найти другие многочисленные материалы по теме. Среди них:
- развёрнутый комментарий от Tim Hockin (одного из самых известных разработчиков Kubernetes) на Reddit;
- лаконичное пояснение от Benjamin Elder (другого разработчика Kubernetes) на GitHub;
- заявление самой Docker Inc;
- анонс от Mirantis, которая год назад купила бизнес Docker Enterprise, а теперь собирается продолжить развитие dockershim в Kubernetes своими силами.
Узлы 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):
- ресурс RuntimeClass с параметрами исполняемой среды для контейнеров;
- поддержка в kubelet сторонних плагинов для мониторинга устройств;
- изоляция PID'ов от узла к pod'ам;
- проба startupProbe.
Но и это ещё не всё:
- 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.
Фрагмент итогов аудита 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'ом, как было раньше.Среди других сетевых новшеств:
- возможность определять имя хоста pod'а как FQDN (KEP-1797, поле
setHostnameAsFQDN
) переведена в бета-версию; - поддержка протокола SCTP объявлена стабильной (GA) — см. документацию на сайте;
- поддержка поля AppProtocol (KEP-1507) как унифицированного способа определять протокол у приложения объявлена стабильной (документация на сайте).
Хранилища
Функция создания/восстановления снапшотов томов для 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 и т.п.) для последнего релиза выглядит следующим образом:
- Google (32284);
- VMware (17598);
- Red Hat (10935);
- Microsoft (7062);
- IBM (5857);
- The Scale Factory (2151);
- Samsung SDS (1471);
- Glassdoor (1406);
- SUSE (1319);
- Kubermatic (1300).
P.S.
Разработчики Kubernetes присвоили релизу v1.20 имя «raddest» (английский сленг, который переводится как «отличный, замечательный, классный»). Потому что, несмотря на сложный для всех год, сообществу удалось привнести рекордное число значимых изменений в этот релиз.
А такой кот стал официальным логотипом релиза Kubernetes v1.20:
P.P.S.
Читайте также в нашем блоге: