Привет, Хабр!

Мы представляем команду платформы компании Exness. Ранее наши коллеги уже писали статью про Production-ready images for k8s. Сегодня мы хотим поделиться опытом миграции сервисов в Kubernetes.



Для начала предлагаем вам немного цифр для большего понимания того, о чем будет идти речь:

  • Наш отдел разработки это 100+ человек, среди которых более 10 различных команд с самодостаточными процессами QA, DevOps и Scrum. Стек разработки — Python, PHP, C++, Java и Golang. 
  • Размер тестовой и продуктовой среды— около 2000 контейнеров в каждой. Находятся они под управлением Rancher v1.6 на своей виртуализации и под VMware. 

Мотивация


Как говорится, ничто не вечно под луной, и Rancher уже достаточно давно объявил о прекращении поддержки версии 1.6. Да, мы более чем за три года научились его готовить и решать возникающие проблемы, но все чаще мы сталкивались с проблемами, которые никогда не будут исправлены. Также Rancher 1.6 имеет закостенелую систему выдачи прав, где ты либо можешь почти все, либо ничего.

Собственная виртуализация хоть и предоставляла больший контроль над хранением данных и их безопасностью, но накладывала операционные расходы, с которыми трудно было мириться при постоянном росте компании, количестве проектов и требований к ним.

Нам хотелось следовать стандартам IaC и при необходимости получить мощности быстро, в любой географической локации и без вендор лока, а также иметь возможность быстро от них отказаться.

Первые шаги


Прежде всего мы хотели опираться на современные технологии и решения, которые бы позволили командам иметь более быстрый цикл разработки и снижать к минимуму операционные расходы на взаимодействие с платформой, предоставляющей мощности. 
 
Конечно же, первое, что пришло нам в голову — это Kubernetes, но мы не стали горячиться и провели небольшое исследование на предмет верности выбора. Мы оценивали только opensource решения, и в нечестной схватке безоговорочно победил Kubernetes.  

Далее стал вопрос выбора инструмента для создания кластеров. Мы сравнили самые популярные решения: kops, kubespray, kubeadm.

Для старта kubeadm показался нам слишком сложным путем, скорее, неким изобретателем «велосипеда», а у kops не хватало гибкости.

И победителем вышел:



Мы начали ставить эксперименты на собственной виртуализации и AWS, пытаясь воссоздать примерное подобие нашего предыдущего паттерна управления ресурсами, где все используют один и тот же «кластер». И вот у нас появился первый кластер размером в 10 небольших виртуальных машин, пара из которых находится в AWS. Мы начали пробовать мигрировать туда команды, вроде бы все стало «хорошо», и рассказ можно было бы закончить, но…

Первые Проблемы


Ansible — то, на чем построен kubespray, это не тот инструмент который позволяет следовать IaC: при вводе/выводе нод из эксплуатации постоянно что-то шло не так, и требовалось какое-либо вмешательство, а при использовании разных ОС плейбук вел себя по-разному. С ростом количества команд и нод в кластере мы стали замечать, что плейбук выполнялся все дольше и дольше, в итоге, наш рекорд 3,5 часа, а ваш? :)

И вроде как kubespray это просто Ansible, и все понятно на первый взгляд, но:



В начале пути стояла задача запускать мощности только в AWS и на виртуализации, но потом, как это часто бывает, требования изменились.
 


В свете этого стало понятно, что наш старый паттерн объединения ресурсов в одну систему оркестрации не подходил — в случае, когда кластеры сильно удалены и находятся под управлением разных провайдеров. 

Дальше — больше. Когда все команды работают в пределах одного кластера, различные сервисы с неправильно установленными NodeSelector могли прилететь на «чужой» хост другой команды и там утилизировать ресурсы, а в случае выставления taint  — появлялись постоянные обращения о том, что тот или иной сервис не работает, не распределяется правильно из-за человеческого фактора. Еще одной проблемой оказался расчет стоимости, особенно учитывая проблемы при распределении сервисов по нодам.

Отдельной историей шла выдача прав сотрудникам: каждая команда хотела быть «во главе» кластера и полностью им управлять, что могло вызвать полный коллапс, так как команды в основном друг от друга независимы.

Как быть?


Учитывая вышеописанное и пожелания команд быть более независимыми, мы сделали простой вывод: одна команда — один кластер. 

Так у нас появился второй:



А потом и третий кластер: 



Тут мы начали думать: допустим, через год у наших команд будет не один кластер? В разных географических зонах, например, или под управлением разных провайдеров?  А кто-то из них захочет иметь возможность быстро развернуть временный кластер для каких-либо тестов. 



Наступил бы полный Кубернетес! Это какой-то MultiKubernetes, получается. 

При этом, всем нам надо будет каким-то образом поддерживать все эти кластеры, иметь возможность легко управлять доступом к ним, а также создавать новые и выводить старые из эксплуатации без ручного вмешательства.

С момента начала нашего пути в мире Кубернетеса прошло некоторое время, и мы решили сделать повторное изучение доступных решений. Оказалось, что на рынке оно уже есть — Rancher 2.2.



На первом этапе наших исследований Rancher Labs уже сделали первый релиз версии 2, но хоть его и можно было очень быстро поднять, запустив контейнер без внешних зависимостей с парой параметров или используя официальный HELM Chart, она нам показалось сырой, и мы не знали, можем ли положиться на это решение, будут ли его развивать или быстро забросят. Сама парадигма кластер = клики в UI нам также не подходила, и мы не хотели привязываться к RKE, так как это достаточно узконаправленный инструмент. 

Версия Rancher 2.2 уже имела более работоспособный вид и вкупе с предыдущими обладала кучей интересных возможностей из коробки таких, как интеграция со многими внешними провайдерами, единая точка дистрибуции прав и kubeconfig файлов, запуск образа kubectl с твоими правами в UI, вложенные неймспейсы aka проекты. 

Также вокруг Rancher 2 уже сформировалось комьюнити, и был создан провайдер HashiCorp Terraform для управления им, который помог нам собрать все воедино.

Что получилось


В итоге у нас получился один маленький кластер, в котором запущен Rancher, доступный всем остальным кластерам, а также много кластеров с ним связанных, доступ к любому из которых можно выдать также просто, как добавить пользователя в ldap каталог вне зависимости от того, где он находится и ресурсы какого провайдера использует.

С помощью gitlab-ci и Terraform была создана система, позволяющая создать кластер любой конфигурации в облачных провайдерах или нашей собственной инфраструктуре и подключить их к Rancher. Все это выполнено в стиле IaC, где каждый кластер описан репозиторием, а его состояние версионируется. При этом большинство модулей подключаются из внешних репозиториев так, что остается только передать переменные или описать свою кастомную конфигурацию для инстансов, что помогает уменьшить процент повторяемости кода.



Конечно, наше путешествие далеко не закончено и впереди еще много интересных задач таких, как единая точка работы с логами и метриками любых кластеров, service mesh, gitops для управления нагрузками в мультикластере и многое другое. Надеемся, вам будет интересен наш опыт! 

Статью писали А. Антипов, А. Гануш, Platform Engineers.