От переводчика: продолжаем делиться переводом истории технологической эволюции Mercado Libre. Сегодня вы узнаете о том, как компания внедряла Kubernetes в качестве ядра своей внутренней платформы Fury. Дальше идёт текст оригинала.
Мы в Mercado Libre управляем более чем 30 000 микросервисов и обеспечиваем работу 16 000 разработчиков, поэтому нам требуется надёжное и масштабируемое решение. Чтобы решить эти проблемы, мы использовали Kubernetes в качестве основного движка внутренней платформы Fury. В этой статье рассказывается о том, как Kubernetes оптимизировал управление инфраструктурой, ускорил доставку программного обеспечения и повысил эффективность затрат, позволив разработчикам сосредоточиться на инновациях и создании продуктов.

Структура Fury
Поскольку в этой статье речь идёт о внедрении Kubernetes в платформу Fury, важно получить базовое представление о Fury, чтобы разобраться в рассматриваемых темах. Рекомендуем предварительно ознакомиться с этой статьёй.
Если коротко, Fury — это внутренняя платформа разработчика (IDP), состоящая из облачных приложений и сервисов. Она предоставляет веб-интерфейс и командную строку (CLI), позволяя разработчикам создавать ресурсы и управлять ими. Кроме того, команды Cloud и Platform используют бэк-офис для администрирования и мониторинга платформы и управления её работой.

Fury и её абстракции
Если говорить упрощённо, Fury — это слой абстракции, разработанный в Mercado Libre. Он выступает связующим звеном между сторонними сервисами (вроде Amazon Web Services (AWS), Google Cloud Platform (GCP), Datadog и др.) и пользовательскими приложениями. Независимо от используемого провайдера или партнёра разработчики обычно взаимодействуют с сервисами через SDK, а связь с провайдерами осуществляется через API Fury.
То есть приложения не взаимодействуют с облачными сервисами напрямую. Существует защитный слой, который предотвращает привязку (lock-in), облегчает обновление версий и позволяет переходить на аналогичные сервисы, не меняя код. Такая абстракция важна для мультиоблачной стратегии компании. Она обеспечивает гибкость и более эффективное управление затратами и безопасностью.

Генезис: вычислительный движок
Вычислительный движок — компонент Fury, отвечающий за управление рабочими нагрузками пользователей. Fury появилась в 2015 году. Тогда Kubernetes ещё только начинал своё развитие и не мог справиться с объёмом рабочих нагрузок и техническими потребностями в Mercado Libre. Поэтому наиболее естественным выбором стало использование вычислительных сервисов на базе инстансов от таких облачных провайдеров, как AWS EC2 и Google Compute Engine.
Первая разработанная вычислительная модель называлась Standard. Она служит интерфейсом между платформой и поставщиками облачных услуг. Модель получает команды от платформы, например создать или отмасштабировать инстансы, и выполняет эти операции на провайдерах.
Упрощённая диаграмма ниже даёт общее представление о модели (на самом деле она намного сложнее). Один из примеров — компонент под названием Little Monster (LM), входящий в состав модуля Standard. Он управляет атомарностью распределённых транзакций. LM запрашивает инстансы у облачного провайдера и обеспечивает их готовность к использованию, обрабатывая необходимые ожидания и объединения в пулы в процессе создания и инициализации.

На схеме видно, что эта модель уже работает в нескольких регионах и с разными облачными провайдерами. С самого начала она создавалась именно для этой цели, поэтому всё управление автомасштабированием разрабатывалось внутри модуля вычислений независимо от AWS Auto Scaling Groups (ASGs) или аналогичных функций других облаков. Такое решение было продиктовано необходимостью создания мультивендорного инструмента (отсюда и создание отдельного уровня абстракции).
Модуль Standard надёжно работает в составе Fury на протяжении многих лет. Он позволил Mercado Libre расти и решать серьёзные бизнес-задачи. Однако со временем возникли две проблемы, требующие решения:
Низкая эффективность. Каждая реплика приложения запускается на отдельном вычислительном инстансе (например, EC2). Даже со стратегиями вроде резервирования, экономичными тарифами, спот- и ARM-инстансами на Graviton всё ещё оставались возможности для снижения затрат.
Ограниченное использование собственных ресурсов облачных провайдеров. Вследствие использования разработанных абстракций модуль не мог оптимально использовать ресурсы и функциональные возможности, предлагаемые самими облачными провайдерами. Это ограничивало его потенциал и возможности.
Изучаем альтернативы

Мы провели масштабное исследование в поисках более эффективного решения, оценивая различные технологии и подходы. Сначала попробовали активировать ресурсы по требованию с помощью AWS Batch, но этот сервис не отвечал всем нашим потребностям. Думали об AWS Lambda, но для долгих (long-running) задач она не подходит из-за своих ограничений. Ещё мы смотрели решения на базе контейнеров, такие как ECS и Cloud Run, — они оказались слишком сложными и без нужных функций. Опробовав Kubernetes (EKS и GKE) и Nomad, мы в итоге отбросили Nomad и решили перейти на Managed Kubernetes (то есть EKS и GKE), поскольку те лучше всего отвечали нашим потребностям.
Текущая реализация: вычислительный сервис с EKS и GKE
После нескольких месяцев планирования и разработки мы пришли к текущей архитектурной модели, получившей название Serverless. В отличие от распространённой концепции бессерверных вычислений, которая обычно относится к Lambda-функциям, мы выбрали это название, чтобы подчеркнуть, что разработчикам совершенно не нужно ничего знать о серверах или управлять ими. Они взаимодействуют исключительно с «бессерверным» слоем абстракции Fury. Платформа, в свою очередь, управляет ресурсами прозрачно, а Serverless выступает уникальным дифференциатором, отражающим эту философию полной автоматизации, облегчая тем самым внедрение.

В ходе эволюции появился модуль Serverless Module, который заменил старый Standard Module, но сохранил компонент Little Monster (LM), обеспечивающий атомарность операций. Главное изменение произошло на уровне связи между платформой и облачными провайдерами: новый вычислительный модуль взаимодействует с решением под названием Cluster API. Стоит отметить, что этот Cluster API отличается от API Kubernetes. У нас он абстрагирует управляющий слой Kubernetes, выступая в качестве уровня трансляции между различными версиями Kubernetes и вычислительным модулем.
Cluster API: эффективный слой абстракции
Cluster API был разработан для решения проблемы растущей сложности одновременного управления несколькими версиями Kubernetes и для работы с API, которые склонны устаревать с течением времени. Он призван минимизировать влияние этих изменений на вычислительный модуль — за всё управление жизненным циклом версий Kubernetes отвечает Cluster API. Такой подход позволяет нам при необходимости легко заменить Kubernetes на другой оркестратор.
Модуль Serverless: управление и масштабируемость
В отличие от Cluster API, который выступает в качестве обёртки для управляющего слоя, модуль Serverless абстрагирует вычислительные «тени», вносимые кластерами. Кластеры разбили то, что раньше было единой региональной плоскостью данных, на несколько частей. Модуль Serverless адаптирует эту новую концепцию к платформе, разбираясь с дополнительными задачами, такими как определение наиболее подходящего кластера для конкретной рабочей нагрузки.
Масштабируемость и контролируемые обновления
Текущая архитектура, насчитывающая более 130 000 инстансов, уже сегментирована по регионам, провайдерам и другим подразделениям в зависимости от степени важности и типа рабочей нагрузки. Такое сегментирование крайне важно для нашего подхода к контролируемым обновлениям, особенно при обновлении данных и компонентов управляющего слоя. Когда требуется обновление, процесс начинается с кластеров меньшей критичности и тестовых сред для проверки стабильности. Только после тщательной проверки изменения постепенно переносятся в более критичные кластеры. Эта стратегия минимизирует риски и гарантирует, что непрерывность обслуживания не будет нарушена.
Процесс развёртывания
Мы изучили архитектуру нашего движка. Теперь рассмотрим процесс развёртывания приложений на платформе Fury. Для развёртывания внутренних компонентов нашего движка мы воспользовались подходом, известным как GitOps, однако эта тема заслуживает отдельного обсуждения.
В Fury существуют различные стратегии развёртывания, такие как all-in, blue-green и canary, каждая из которых отвечает конкретным сценариям разработчиков. Но есть и две стратегии, уникальные для платформы: safe deployment (безопасное развёртывание) и migration (миграция):
Безопасное развертывание — эта стратегия похожа на сине-зелёное развёртывание, но использует более постепенный и осторожный подход. Она постоянно отслеживает метрики и принимает автоматизированные решения об откате или даёт рекомендации по корректировке, обеспечивая безопасный и контролируемый процесс.
Миграция — более широкая стратегия, позволяющая перемещать рабочие нагрузки между вендорами, регионами и даже между различными вычислительными средами (от Standard к Serverless и наоборот) в зависимости от требований к отказоустойчивости и стоимости.
Подробности о процессе развёртывания
В архитектуре развёртывания Fury запускает модуль Serverless, который инициирует процесс, запрашивая создание рабочих нагрузок. Этот запрос передаётся в Cluster API через балансировщик нагрузки приложений (Ingress ALB), который распределяет трафик и создаёт всё необходимое для правильной маршрутизации приложений.
Далее Cluster API настраивает необходимые компоненты Kubernetes, такие как ReplicaSet'ы и горизонтальное масштабирование (Horizontal Pod Autoscalers, HPA). Мы решили использовать ReplicaSet'ы вместо Deployment'ов Kubernetes, потому что наша цель — обеспечить нужное количество реплик, а дополнительные возможности, предоставляемые Deployment'ами, нам не нужны, поскольку они уже реализованы в платформе.
Мониторинг и асинхронное управление
После создания рабочих нагрузок модуль Serverless — в частности его компонент Little Monster (LM) — осуществляет непрерывный мониторинг и обрабатывает асинхронные запросы, отправляемые в кластер. Serverless API Controller (контроллер Kubernetes) расширяет возможности K8s, наблюдая за поведением подов и узлов непосредственно в кластере, в реальном времени информируя платформу о любых изменениях. Этот контроллер реконсилирует состояние кластера с внешним состоянием через «наблюдателей» (watchers) этих объектов, уведомляя модуль Serverless, чтобы платформа могла реагировать и динамически адаптироваться.
Такая структура позволяет Fury эффективно и надёжно выполнять развёртывания, отслеживать состояние кластеров и рабочих нагрузок и реагировать на изменения в реальном времени, обеспечивая устойчивость и безопасность.
Процесс развёртывания — blue-green
С сине-зелёным развёртыванием в Fury всё происходит по той же схеме, которая была описана ранее, но с некоторыми важными особенностями.

В этом сценарии параллельно со «старым» набором рабочих нагрузок в production (синяя версия) создаётся «новый» набор рабочих нагрузок (зелёная версия). Этот новый набор может быть развёрнут в том же кластере или, в зависимости от стратегии балансировки шардов, в другом кластере.
Процесс создания такой же, как и при стандартном развёртывании: платформа активирует модуль Serverless, который затем обращается к Cluster API через Ingress ALB. На этом шаге создаются все необходимые компоненты Kubernetes, такие как ReplicaSet'ы и HPA, которые копируют текущую инфраструктуру под новый набор рабочих нагрузок.
После завершения сине-зелёного развёртывания платформа автоматически обновляет своё внутреннее состояние, фиксируя все изменения. Так мы сохраняем постоянный и детальный контроль над обеими версиями рабочих нагрузок (синей и зелёной), что позволяет безопасно и организованно переходить на новую версию после завершения необходимых проверок.
Переключение сети и трафика
Критический момент при сине-зелёном развёртывании — постепенное перенаправление трафика со старой версии на новую. Для этого мы используем особый подход, который обеспечивает полную прозрачность сети и быструю синхронизацию между компонентами.

У каждого пода внутри наших кластеров есть уникальные и маршрутизируемые IP из VPC вместо VIP (Virtual IP). В результате каждый под получает прямую сетевую видимость. Это облегчает взаимодействие с другими сервисами и снижает потребность в точках входа на кластер.
Поскольку мы не используем сторонние сетевые продукты для маршрутизации, был разработан внутренний компонент под названием Mesh Controller. Он играет важнейшую роль в процессе подмены трафика, реагируя на изменения, генерируемые управляющим слоем. Как только событие обнаружено, Mesh Controller синхронизирует состояние и уведомляет API управляющего слоя платформы, то есть наш Service Mesh.
Это уведомление автоматически обновляет все сайдкары Envoy, развёрнутые с приложениями. В результате маршруты корректируются таким образом, чтобы трафик через Envoys перенаправлялся на новую версию, что завершает переключение трафика и гарантирует, что платформа и приложения всегда знают об обновлённом маршруте.
Заключение
История Fury в Mercado Libre — пример того, как технологическая эволюция и постоянные инновации определяют способность преодолевать трудности и повышать эффективность в глобальном масштабе. Построенная на прочном фундаменте Kubernetes, Fury преодолевает эксплуатационные сложности, предлагая разработчикам интуитивно понятную, безопасную и масштабируемую среду. Fury убирает заботы об управлении инфраструктурой и упрощает развёртывание, позволяя инженерам сосредоточиться на создании полезного кода. Это помогает компаниям быстро принимать стратегические решения и эффективно использовать мультиоблачные технологии для быстрого финансового результата. Такой подход позволяет нам удовлетворять текущие потребности, предвидеть и преодолевать будущие проблемы, подтверждая приверженность исключительному опыту разработки и постоянному развитию.
Благодарности
Эта статья была написана в сотрудничестве с Маркосом Антонио Соузой Пиньейро (Marcos Antonio Souza Pinheiro) и Марсело Кордейро Де Квадросом (Marcelo Cordeiro De Quadros).
P. S.
Читайте также в нашем блоге: