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

Kubernetes 1.9: Workloads API в GA - планируем миграцию stateful-сервисов

Kubernetes 1.9 переводит Workloads API в GA: DaemonSet, Deployment, StatefulSet - стабильные контракты. Разбираем что это значит для production-миграции.

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

Релиз Kubernetes 1.9 - Workloads API (Deployment, DaemonSet, StatefulSet, ReplicaSet) переведён в General Availability в группе apps/v1

Kubernetes 1.9 вышел в конце декабря, и главная новость для нас - Workloads API официально в General Availability. Deployment, DaemonSet, StatefulSet, ReplicaSet переезжают из apps/v1beta2 в apps/v1. Это не просто смена строчки apiVersion в YAML: фиксируется контракт, гарантируется обратная совместимость, бета-оговорки снимаются. И для нас это момент серьёзно поговорить о том, что мы раньше откладывали - миграции stateful-сервисов в кластер.

Что изменилось в Workloads API

В 1.7 в GA вышел RBAC, мы тогда перерабатывали сервисные аккаунты. Теперь GA получает другой слой - объекты управления нагрузкой. Ключевые изменения в apps/v1:

  • Deployment. В beta spec.selector был необязателен и мог меняться. В GA spec.selector - иммутабельное поле после создания объекта. Это ломающее изменение для тех кто пишет контроллеры или пересоздаёт деплойменты через манипуляцию полями.
  • DaemonSet. Та же история с spec.selector. Плюс spec.templateGeneration убрано - оно было в beta, в GA его нет.
  • StatefulSet. spec.selector иммутабелен, добавлены поля для управления updateStrategy.rollingUpdate.partition в стабильном виде.
  • ReplicaSet. Аналогично Deployment, но большинство работает с ним через Deployment, так что на практике заметно меньше.

Если у вас CI/CD pipeline строит манифесты на лету и ставит selector из каких-то переменных - проверьте логику. В нашем случае несколько Helm chart-ов писали selector через шаблон который вычислялся из лейблов - пришлось убедиться что логика идемпотентна.

Почему StatefulSet в GA важен именно сейчас

Статика в Kubernetes мы щупали ещё в 1.5, тогда StatefulSet был в beta и воспринимался как эксперимент. Механика работала, но производственного доверия не было: API мог поменяться, поведение хранения томов - тоже.

Сейчас ситуация другая. apps/v1 StatefulSet с гарантированным контрактом - это аргумент для разговора с командами которые держат stateful-сервисы на голых виртуалках «потому что Kubernetes для stateful нестабилен». Нестабильность была обоснованной в 1.5. В 1.9 - уже нет.

Конкретно на наших managed-кластерах это открывает разговор о нескольких группах сервисов:

  • Zookeeper и Kafka - на двух проектах они живут рядом с кластером но не в нём. С StatefulSet в GA + PersistentVolumeClaim с правильным StorageClass это технически обоснованно переносить внутрь.
  • Redis в sentinel-режиме - StatefulSet даёт стабильные имена подов (pod-0, pod-1...), что критично для sentinel-конфигурации где реплики должны знать адреса друг друга.
  • PostgreSQL-реплики для чтения - primary пока вне кластера, но read-реплика внутри с репликацией через стандартный streaming - технически вполне рабочая схема.

Мы не говорим «перенести всё немедленно». Мы говорим «теперь есть основание составить план», а не откладывать до следующей беты.

Storage: что принесла 1.9

Отдельного внимания заслуживает работа с хранилищем. В 1.9 LocalPersistentVolume переведён в alpha - это возможность использовать локальные диски ноды как PersistentVolume с учётом топологии. Планировщик будет учитывать где физически находится том при выборе ноды для пода. Пока alpha, но вектор понятен.

Что стабильно и уже работает на production в 1.9:

  • StorageClass с volumeBindingMode: WaitForFirstConsumer - задержка биндинга тома до момента планирования пода, а не сразу при создании PVC. Для мультизональных кластеров это критично: том создаётся в той же зоне где под.
  • Расширение PVC остаётся в beta (ExpandPersistentVolumes), но на ряде плагинов уже работает. Мы пробовали на gp2 в AWS - resize тома без пересоздания PVC работает, хотя требует перезапуска пода.

Что мы делаем с legacy-манифестами

После перехода на 1.9 beta-apiVersion начинают возвращать предупреждения, а не тихо работать. К выходу следующих версий старые apps/v1beta1 и apps/v1beta2 будут deprecated. Значит сейчас самое время пройтись по манифестам.

На наших кластерах мы написали небольшой скрипт который через kubectl get deployments,daemonsets,statefulsets --all-namespaces -o json выгружает все объекты и проверяет apiVersion. Результат предсказуемый: mix из extensions/v1beta1, apps/v1beta1, apps/v1beta2 в зависимости от того когда что писалось.

Конвертация механически простая - меняется apiVersion и добавляется явный spec.selector. Содержательно - надо проверить что selector соответствует реальным лейблам подов, иначе после kubectl apply контроллер потеряет управление своими подами.

Алгоритм который используем:

  1. Выгрузить текущий объект через kubectl get -o yaml
  2. Проверить spec.selector.matchLabels - должен однозначно совпадать с spec.template.metadata.labels
  3. Поменять apiVersion на apps/v1
  4. Применить через kubectl apply - если selector не изменился, объект обновится без пересоздания

Деплоить всё разом не стали - идём namespace за namespace на тестовом кластере сначала.

Итог

GA-статус Workloads API снимает последнюю содержательную причину держаться за «stateful - не в Kubernetes». Не значит что миграция лёгкая или что надо делать это прямо сейчас - но отговорка «API нестабильный» закрыта. Что остаётся: операционная готовность, резервное копирование томов, runbook для восстановления. Это работа, но она конечна.

По кластерам под нашим управлением начинаем систематически конвертировать манифесты в apps/v1. По stateful-миграциям - разговариваем с командами, составляем план. Торопиться некуда, но и откладывать больше нечем.

Контакт

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

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