Недавно мы помогли нашему клиенту Adapty перенести инфраструктуру с managed-сервисов AWS. Теперь она размещена в Kubernetes-кластере на обычных инстансах другого облачного провайдера, но ее можно легко мигрировать в другой ЦОД в случае необходимости. Этот бизнес-кейс во многом показательный: Adapty удалось минимизировать зависимость от поставщика, снизить инфраструктурные затраты на 50%, а также снять некоторые технические ограничения по масштабированию и оптимизации своих приложений. Расскажем, что позволило добиться экономии, какие сложности возникли во время переезда, какую роль сыграл в проекте «Флант», а также о плюсах кубернетизации сервиса. 1. Это не техническое руководство к действию, а именно бизнес-кейс. Упоминаемые в нём технические детали помогают увидеть общую картину с точки зрения бизнеса.  2. Хотя мы и приводим некоторые цифры по кейсу, NDA не позволяет называть конкретные бюджетные показатели Adapty. Поэтому, когда речь идет об экономике, приводятся относительные величины. Adapty помогает разработчикам приложений увеличивать доход с внутренних подписок. Сервис включает набор разных инструментов: A/B-тесты пейволлов для лучшей конверсии пользователей в платных подписчиков, дашборд с нужными метриками, SDK для подключения покупок внутри приложения (in-app) и т. д. Клиенты Adapty — мобильные приложения. Количество подписчиков у некоторых приложений может доходить до миллионов; в общей сложности система Adapty обслуживает 120 млн пользователей приложений. С ростом клиентов пропорционально растет и трафик. Как известно, трафик не бесплатный, а его стоимость в облачных окружениях может зависеть не только от числа конечных пользователей, но и ряда других факторов (взаимодействие сервисов между собой и т.п.). У Adapty ценник на него рос так стремительно, что это и стало основным мотивом для переосмысления архитектуры. Рост стоимости трафика. Adapty изначально решили разместить всю свою инфраструктуру в AWS. Предварительный расчет ежемесячного платежа в калькуляторе Amazon команду устроил. Однако этот расчет учитывал стоимость только фиксированных платежей за виртуальные машины (ВМ) и managed-сервисы. Нефиксированные платежи — в том числе за трафик — Adapty не считали.  Главной проблемой стал исходящий трафик — данные, которые передают серверы Adapty на мобильные приложения клиентов (Data Transfer Out From Amazon EC2 To Internet). Из-за роста клиентской базы общий объем трафика вырос до сотен ТБ в месяц. В итоге к моменту миграции более 60% всего чека за услуги AWS составляли как раз платежи за трафик. Высокая стоимость IOPS. Вторая серьезная статья расходов — IOPS. Для работы базы данных Adapty важна высокая пропускная способность дисков, а за дополнительные IOPS’ы нужно платить. Vendor lock-in. Вся инфраструктура Adapty состояла из managed-сервисов Amazon. В качестве оркестратора контейнеров использовался Elastic Container Service (ECS), базы PostgreSQL — Relational Database Service (RDS), балансировщика нагрузки — Application Load Balancer, логирования — CloudWatch, Redis — ElastiCache, для аналитики подключили связку Kinesis-Lambda-S3. Все эти сервисы работают только в облаке Amazon, никуда не переносятся и не реплицируются. Фактически Adapty стали зависимы от одной платформы. Если бы что-то пошло не так, оперативно мигрировать на другую инфраструктуру не получилось бы. Функциональные ограничения managed-сервисов. Многие управляемые сервисы AWS удобны с точки зрения простоты их настройки и обслуживания. Обратная сторона удобства — ограниченная функциональность. Это касается, например, оркестратора контейнеров ECS: сравнивать его возможности с возможностями Kubernetes было бы некорректно. То же самое — с базой данных RDS (Relational Database Service), облачной версией PostgreSQL собственной сборки AWS: streaming-репликой здесь может быть только другая RDS. Чтобы решить эти проблемы, инфраструктура была перевезена на обычный Kubernetes (не managed) и известные Open Source-аналоги облачных сервисов. Одновременно с этим произошла и смена провайдера, которым стал Google. Однако важно отметить, что не новый провайдер, а именно переход на K8s и другие self-hosted-решения стал ключевым фактором, благодаря которому удалось добиться экономии (подробности будут ниже). Наша SRE/DevOps-команда помогла Adapty перенести инфраструктуру, после чего взяла ее на поддержку. В процессе миграции не всё пошло по плану, и не в те сроки, на которые изначально рассчитывали. Основные работы были выполнены примерно за 3 недели. Но с учетом подготовки и стабилизации некоторых сервисов после переезда весь этот проект в общем занял около полутора месяцев. Что мы сделали для подготовки к миграции: Собрали кластер Kubernetes на инстансах GCP. Спланировали, как и когда переносить базу данных. Проработали перенос балансировщика нагрузки и переключение трафика. Организовали CI/CD (сборку и деплой) для приложений. Спланировали перенос приложений. А теперь — об основных трудностях, которые возникли в процессе переезда. Одно из критических ограничений Amazon RDS — в том, что нельзя сделать физическую репликацию базы в другое облако или на собственную ВМ. То есть фактически БД пришлось собирать заново.  Сама база довольно «тяжелая»: в AWS она занимала около 1,3 ТБ. База часто обновляется, причем активно: всего за час может обновиться до 1 ТБ данных. Не облегчило задачу и то, что переезжали с 12-й версии PostgreSQL на 13. В итоге перенос базы проходил в несколько этапов и стал самой трудоемкой частью проекта. Работы заняли больше 2 недель. Для блокировки и отдачи HTTP-кода 429 в AWS использовался Application Load Balancer. Балансировщик в Google — Cloud Load Balancing (CLB) — устроен по-другому, у него другая функциональность. После переезда в CLB настроили терминирование HTTPS и такую же фильтрацию, как в AWS, но потратили уйму времени на настройку CLB, потому что он гораздо сложнее ALB. В какой-то момент пришлось даже привлекать инженеров Google. В качестве альтернативы CloudWatch использовали систему на базе проверенного Open Source-стека: Elasticsearch, Logstash, Kibana (ELK). Чтобы реализовать в ELK ту же функциональность, что была у Adapty в CloudWatch, систему пришлось сильно кастомизировать. Работы по донастройке продолжались еще некоторое время и после переезда. После переезда из AWS в нем остался только сервис аналитики (Kinesis + Lambda + S3). Остальные сервисы, которые работают в production, теперь развернуты на инстансах в облаке GCP, в основном как Open Source-решения. Здесь важно подчеркнуть: Adapty переехали на обычные виртуалки, которые хостятся в Google. Поверх виртуалок стоит Kubernetes, который не завязан на конкретные сервисы провайдера, — наша Open Source-платформа Deckhouse; это сертифицированный в CNCF дистрибутив K8s, который работает на любой инфраструктуре. Вместо ВМ Google можно с равным успехом использовать инстансы от другого провайдера, в том числе свою инсталляцию OpenStack или bare metal-серверы. Единственная оставшаяся привязка к поставщику — managed-сервис Google в виде балансировщика нагрузки Cloud Load Balancing, который принимает клиентский трафик и направляет его на Ingress в Kubernetes. Однако сейчас он не видится большой проблемой, и в перспективе его тоже можно отвязать от vendor lock-in: с балансировкой справится nginx, развернутый на ВМ или на выделенном сервере. За виртуальные машины, IOPS и трафик по-прежнему приходится платить, но общая сумма теперь заметно дешевле. На чем удалось существенно сэкономить: трафик — 60%; база данных — 50%; логи — 40%; кэш — 30%. В случае трафика снижение стоимости произошло не из-за разницы в его стоимости у провайдеров, а благодаря оптимизации архитектуры и переходу в Kubernetes. В частности, удалось избавиться от «внутреннего» трафика между регионами AWS — убрали излишний full mesh между API, PgBouncer и БД. По IOPS — удалось отказаться от provisioned IOPS благодаря использованию больших SSD-дисков для СУБД (на каждый гигабайт выделяется около 30 IOPS — производительность получилась аналогичной). Другая экономия была достигнута из-за миграции на Open Source-альтернативы. Что примечательно, стоимость обслуживания инфраструктуры при этом не изменилась. В итоге общий ценник за облачную инфраструктуру снизился на 50%. Почему эту миграцию поручили нам как подрядчикам? CTO в Adapty, Кирилл Потехин, не относит администрирование серверов к ключевой экспертизе компании, не видит в этом бизнес-преимущество. Для Adapty выгоднее отдать вопросы по DevOps тем, кто в этом хорошо разбирается, чтобы самим сфокусироваться на продукте. «Если бы мы сами попытались переехать в Kubernetes, мы бы потратили значительно больше времени, чтобы разобраться в том, как он устроен, как с ним правильно работать. Еще у нас, например, нет экспертизы в том, как самостоятельно настраивать мониторинг, а у “Фланта” была уже готовая система мониторинга на замену CloudWatch. С ее помощью мы быстро нашли несколько неэффективных запросов, которые сильно грузили базу, и переписали их, снизив нагрузку. Про какие-то метрики мы даже и не думали, что их нужно смотреть. Но, как оказалось, в разрезе Kubernetes это важно». CTO Adapty Переехав в GCP, Adapty избавились от привязки ключевых сервисов к поставщику. С учетом миграции в self-hosted Kubernetes это дало независимость от IaaS-провайдера: кластер можно перенести в другое облако, в том числе на выделенные серверы, или на собственное «железо». Новая инфраструктура принесла и другие плюсы. В случае с Adapty очень актуальным оказалось реализованное в Deckhouse динамическое автомасштабирование. У клиента бывают резкие всплески трафика: например, показатель RPS со среднего значения в 2000 может быстро подняться до 30000 — и так же быстро понизиться. Для таких ситуаций приложения были подняты на виртуальных машинах AWS в десятках экземплярах, «про запас». Половину времени эти ВМ простаивали. Сейчас в K8s настроено динамическое автомасштабирование узлов и Pod’ов. Это работает благодаря модулю node-manager, в котором machine-controller-manager заказывает узлы в облаке (поддерживаются AWS, GCP, Yandex.Cloud и другие). Как только возникает необходимость, на этих узлах разворачиваются дополнительные Pod’ы. Для более быстрого запуска Pod’ов дозаказанные узлы можно держать в standby-режиме. Оптимизировать автомасштабирование помогла и наша утилита для деплоя werf. В случае Adapty используется HPA (Horizontal Pod Autoscaler). Например, в Deployment’е количество реплик могло быть ограничено 25-ю Pod’ами, а на сервис приходит много трафика. Тогда HPA увеличивает количество Pod’ов, скажем, до 100. Если в этот момент разработчики выкатывали обновление, количество Pod’ов сбрасывалось до 25 и сервис начинал тормозить. Эту проблему решили с помощью использования аннотации ​​replicas-on-creation в процессе выката приложения через werf и обнуления параметра replicas: N в Deployment. В Deckhouse есть похожая автоматизация и для дисков: платформа сама дозаказывает их. Например, в кластере нужно развернуть базу данных, и для нее требуется persistent-диск. Его можно заказывать через storage-классы Deckhouse, т. е. достаточно указать нужный размер и тип диска в YAML-манифесте. К слову, другой удобный момент с дисками — это возможность простого расширения объема PVC (PersistentVolumeClaim) в кластере или YAML с последующим перевыкатом. Амазоновские ECS-таски (аналоги Pod’ов) нередко вылетали по памяти и не перезапускались. Если причину первой проблемы обычно можно было выявить, второй — уже нет. Adapty пришлось написать скрипт-«костыль», который раз в 30 секунд проверял, что ничего не вылетело и, если были проблемы, перезапускал таски. После переезда в K8s таких проблем больше нет. Если какой-то Pod вылетает, он сам перезапускается, а причины произошедшего можно выявить стандартными инструментами. В обычном Kubernetes с CI/CD может быть проще, чем в ECS, поскольку доступны стандартные для индустрии инструменты. В нашем случае таковым, конечно, стала уже упомянутая werf, но ничто не мешает воспользоваться и чем-то другим, что будет более привычным и/или удобным для инженеров, задействованных в проекте. Следующим шагом оптимизации инфраструктуры и затрат на нее Adapty планируют перенос некоторых сервисов на собственное «железо» в один из локальных дата-центров. Например, машины, которые отвечают за API и на которые идет почти весь трафик, — stateless: они не хранят данные, а просто выполняют код, поэтому их можно будет перенести в дешевый ЦОД. Тем самым вообще не придется платить за трафик. А критичную инфраструктуру — например, базу данных, — Adapty оставят в GCP, поскольку Google предоставляет достаточный уровень отказоустойчивости и доступности. Читайте также в нашем блоге: «Опыт миграции инфраструктуры клиента из AWS в Яндекс.Облако»; «Выводы Grofers после двух лет Kubernetes в production».