ADG Оставить заявку
Блог DevOps 4 мин чтения

Kubernetes 1.16 удалил extensions/v1beta1 - и наши Helm-чарты упали

Kubernetes 1.16 убрал устаревшие API extensions/v1beta1 - Deployment, DaemonSet, Ingress сломались. Пришлось срочно переписывать Helm-чарты перед обновлением.

Контекст момента

Kubernetes 1.16 вышел 18 сентября 2019: удалены устаревшие API extensions/v1beta1, CRD достигли GA в apiextensions.k8s.io/v1, улучшен kubectl

Kubernetes 1.16 вышел 18 сентября. Мы читали release notes заранее, видели, что там deprecation removal - и всё равно обновление прилетело болезненнее, чем ожидали. Не потому что мы не знали. А потому что оказалось, что «знать» и «проверить все чарты» - это два разных дела.

Расскажем как это было на одном из клиентских кластеров в managed-инфраструктуре.

Что именно убрали

В 1.16 из Kubernetes вырезали группу API, которую помечали deprecated ещё с 1.9. Это не предупреждение - это удаление. Конкретно перестали работать:

  • extensions/v1beta1 - Deployment, DaemonSet, ReplicaSet, NetworkPolicy, PodSecurityPolicy, Ingress
  • apps/v1beta1 и apps/v1beta2 - Deployment, DaemonSet, ReplicaSet, StatefulSet

Правильные замены существуют давно: apps/v1 для Deployment/DaemonSet/StatefulSet, networking.k8s.io/v1beta1 для Ingress. Но если ваши манифесты или Helm-чарты написаны год-два назад и с тех пор не трогались - там, скорее всего, стоит extensions/v1beta1. Потому что так было в примерах из документации до 1.9.

Параллельно CRD перешли в GA - apiextensions.k8s.io/v1 вместо v1beta1. CRD-манифесты операторов тоже надо обновлять, хотя там пока действует более мягкий режим совместимости.

Как мы в это влетели

Кластер на 1.15, плановое обновление до 1.16 в тестовой среде. После обновления запустили helm upgrade для нескольких чартов - получили пачку ошибок вида:

Error: unable to build kubernetes objects from release manifest:
[unable to recognize "": no matches for kind "Deployment"
in version "extensions/v1beta1"]

Интересный момент: Helm 2 с Tiller берёт манифесты из хранилища релизов и применяет их. Если чарт написан с extensions/v1beta1 - именно это и попадёт в кластер. Когда API-группы нет - всё, upgrade не проходит.

Подсчитали: у нас в production-кластерах несколько десятков Helm-релизов. Не все сломанные, но проверить нужно каждый - потому что заранее не очевидно, в каких именно чартах написан старый apiVersion.

Как проверяли

Первым делом прогнали kubectl api-versions на обновлённом тестовом кластере - убедились, что extensions/v1beta1 действительно исчез. Потом написали простой скрипт, который рендерит каждый чарт через helm template и грепает на extensions/v1beta1|apps/v1beta1|apps/v1beta2:

for release in $(helm list --short); do
  helm get manifest $release | grep -l "extensions/v1beta1\|apps/v1beta"
done

Нашли проблемные. Оказалось, что больше всего старых apiVersion - в чартах, которые давно работают и давно не обновлялись. Nginx Ingress Controller, несколько внутренних деплойментов, один DaemonSet с node-экспортером.

Что переписывали

По каждому проблемному чарту замена в целом прямолинейная:

  • Deployment, DaemonSet, ReplicaSet, StatefulSet - extensions/v1beta1 меняем на apps/v1. Но здесь есть нюанс: в apps/v1 у Deployment и DaemonSet поле selector обязательное и immutable. Если оно не было прописано в старом манифесте явно - нужно добавить и убедиться что оно совпадает с template.metadata.labels. Иначе Kubernetes откажет с ошибкой при применении.
  • Ingress - меняем на networking.k8s.io/v1beta1. Здесь в 1.16 это ещё beta, не GA - но deprecated Ingress из extensions убрали.
  • CRD - apiextensions.k8s.io/v1beta1 пока работает в 1.16, но поля схемы стали структурированными. Операторские чарты с CRD лучше обновить до v1 и добавить spec.versions вместо spec.version.

На внешние чарты (от вендоров) смотрели что пришло в обновлённых версиях. nginx-ingress, например, уже выпустил обновлённые версии chart с правильными apiVersion - просто обновили зависимость.

Чего не хватало при диагностике

kubectl apply с новыми ресурсами на 1.16 кластере даёт понятные ошибки. Но helm upgrade - менее информативен: он сначала рендерит манифесты из chart, потом применяет через Tiller, и ошибка иногда теряется в стектрейсе. Пришлось добавить промежуточный шаг: helm template | kubectl apply --dry-run -f -. Dry-run на 1.16 кластере сразу показывает что именно не принимает API.

Ещё момент: kubectl deprecations как отдельной команды нет. Есть kubectl api-resources и kubectl explain чтобы смотреть что актуально. Отдельного инструмента для сканирования манифестов на deprecated API под рукой не было - kubectl api-resources и kubectl explain делают это вручную, но не в пакетном режиме.

Что из этого следует

Обновление прошло, кластер работает на 1.16. Но общий вывод неприятный: мы были в курсе про deprecation removal, но не систематизировали проверку заранее. Посмотрели release notes, отметили что надо, и занялись другими делами.

Правильный ритм выглядит так - при каждом minor-обновлении Kubernetes, за 2-4 недели до применения, прогонять все чарты через helm template и проверять apiVersion на соответствие тому что в новой версии. Не полагаться на то что «эти чарты работают уже год, значит всё в порядке». Год назад apiVersion был нормальный - сейчас его нет.

Команда Kubernetes предупреждала об этих удалениях начиная с 1.9. Семь версий. Тем обиднее было разбираться в авральном режиме - это была чисто наша недоработка по процессу.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.