Managed Kubernetes в Яндекс.Облаке: первый продакшн-проект, Terraform и CI/CD из GitLab
Запускаем первый проект на Managed Kubernetes в Яндекс.Облаке: node groups, autoscaling, балансировщики - и сравниваем с self-hosted кластером по реальным ops-затратам.
Яндекс.Облако расширяет Managed Kubernetes: поддержка node groups, autoscaling, интеграция с балансировщиками нагрузки
Яндекс.Облако на этой неделе объявило о расширении Managed Kubernetes - node groups с настраиваемым autoscaling, нормальная интеграция с облачными балансировщиками. Для нас это совпало с конкретным поводом: мы как раз завершаем первый продакшн-проект на этой платформе. Есть что рассказать.
Почему managed, а не self-hosted
Исходная ситуация у клиента была стандартная: несколько VM в Яндекс.Облаке, приложения в Docker Compose, ручные деплойменты. Задача - перейти на Kubernetes с нормальным CI/CD. Кластер в облаке можно было поднять двумя путями: самостоятельно через kubeadm на VM или взять Managed Kubernetes от провайдера.
Мы выбрали managed - и не потому что «облако это хорошо», а по конкретному расчёту операционных затрат. Control plane в self-hosted кластере - это минимум три master-ноды для отказоустойчивости, etcd с резервным копированием, ручные обновления версий Kubernetes, мониторинг самого кластерного слоя. В рамках нашего managed-сопровождения это всё ложится на нас. В случае Яндекс.Облака control plane скрыт за managed-слоем: ноды etcd, апгрейды мастеров, сертификаты - это чужая головная боль. Мы управляем только worker-нодами и тем, что на них запускается.
Экономия по времени реальная, но с оговоркой: управляемая плоскость - это чёрный ящик. Если что-то пошло не так внутри - наблюдаемость ограничена тем, что провайдер считает нужным показать.
Terraform как единственный источник истины
Инфраструктуру полностью описали в Terraform с lock-файлом - про это писали недавно. Провайдер yandex для Terraform достаточно зрелый: ресурсы для кластера, node group, сервисных аккаунтов, статических IP и балансировщиков там есть.
Структура получилась примерно такая:
resource "yandex_kubernetes_cluster" "main" {
name = "prod"
network_id = yandex_vpc_network.main.id
master {
version = "1.19"
zonal {
zone = "ru-central1-a"
subnet_id = yandex_vpc_subnet.main.id
}
public_ip = true
}
service_account_id = yandex_iam_service_account.k8s.id
node_service_account_id = yandex_iam_service_account.nodes.id
}
resource "yandex_kubernetes_node_group" "workers" {
cluster_id = yandex_kubernetes_cluster.main.id
version = "1.19"
instance_template {
platform_id = "standard-v2"
resources {
memory = 8
cores = 4
}
boot_disk {
type = "network-ssd"
size = 64
}
}
scale_policy {
auto_scale {
min = 2
max = 6
initial = 2
}
}
}
Autoscaling через auto_scale - это как раз из нового в Яндекс.Облаке. До этого расширения node group приходилось трогать вручную или через скрипты. Теперь кластер сам добавляет ноды при нагрузке и убирает их при простое - в рамках заданного диапазона.
Один нюанс с сервисными аккаунтами: нужны два отдельных - один для управления кластером, другой для нод (чтобы они могли пуллить образы из Container Registry). Это не очевидно из документации с первого раза, но после того как разобрались - в Terraform это фиксируется раз и навсегда.
CI/CD из GitLab
Деплой настроен через GitLab CI с runner'ом на отдельной VM вне кластера. Схема намеренно простая:
- Сборка образа и push в Яндекс Container Registry
kubectl applyс обновлённым тегом образа черезenvsubstв манифестах- Раскатка через rolling update, без Helm на первом этапе
GitLab runner получает доступ к кластеру через kubeconfig - его генерируем Terraform'ом и кладём в переменные CI как protected secret. Версия Kubernetes в кластере фиксирована в Terraform, значит неожиданных сюрпризов при kubectl быть не должно.
На практике сборка + деплой укладываются в приемлемое время. Основной bottleneck оказался не Kubernetes, а Docker build без кеша в чистом runner-окружении - это решается отдельно, но пока не критично.
Балансировщик и ingress
Яндекс.Облако интегрирует свои сетевые балансировщики с Kubernetes через Service типа LoadBalancer. Создаёшь сервис - облако поднимает L4-балансировщик и выдаёт внешний IP. Для большинства сценариев этого достаточно.
Для HTTP-трафика с routing по хостам поставили nginx ingress controller. Он создаёт один LoadBalancer-сервис для всего ingress, а дальше маршрутизация уже внутри nginx. Сертификаты через cert-manager с Let's Encrypt - стандартная схема.
На момент запуска L7 Application Load Balancer от Яндекса для Kubernetes был в preview и мы его не трогали - предпочли проверенный nginx ingress с понятным поведением.
Чем managed отличается на практике
Честный список наблюдений:
Обновления версий Kubernetes. В managed-кластере обновление мастера - кнопка в консоли (или ресурс в Terraform). Ноды обновляются rolling'ом через node group. Никакого kubeadm upgrade apply, никакого ручного drain/uncordon мастеров. Это реально удобно. Обратная сторона - расписание доступных версий диктует провайдер, не мы.
Логи и метрики. Control plane logs можно направить в Yandex Cloud Logging. Для метрик нод работает стандартный prometheus-стек - ничего экзотического. Но метрики самого etcd или API-сервера через managed-слой не достать.
Сеть. Под капотом - Calico. Это хорошо: предсказуемое поведение Network Policy, знакомые инструменты отладки. Но настроить параметры Calico напрямую нельзя - только то, что выставляет облако.
Цена. Control plane тарифицируется отдельно, worker-ноды - по стоимости VM. Итоговая сумма сопоставима с self-hosted на аналогичном железе, но без затрат времени на поддержку мастеров. Для клиента это выгодно: платит деньгами, не нашим временем на инфраструктурные рутины.
Где сейчас
Кластер работает первую неделю в продакшне. Autoscaling ещё не проверили под реальной пиковой нагрузкой - будем смотреть. Следующий шаг - добавить Helm для управления chart'ами приложений и настроить нормальный мониторинг через Prometheus + Grafana в кластере.
Self-hosted Kubernetes никуда не денется - у части клиентов железо вне облака и там managed не вариант. Но для проектов полностью в Яндекс.Облаке managed-кластер снимает достаточно операционного шума, чтобы выбор в его пользу был оправдан.