От легаси к Service Fabric за 360 часов. История одной миграции
Статья посвящена бесконечной борьбе с legacy. Это история о том, что можно сделать, если взять двух разработчиков (второй — для код-ревью) и 360 часов. А также о том, как перенести легаси-код в модный и молодежный клауд-сервис. Код с пошаговой инструкцией тут. Это репозиторий с примером переноса .NET Core Web API как stateless-сервиса Azure Service Fabric c секьюрити, API versioning и т. п.
Начало
Customer: We need to add a new feature to the legacy system, can you give an estimate?
Developer: It depends on when the legacy system will be replaced?
Customer: In five months.
Developer: Then the new feature will take six :)
Иногда кажется, что поработать с новыми технологиями на проекте не представляется возможным, но это не так. Если знать о планах, процессах и проблемах клиента, то в результате можно предложить новый функционал, основанный на технологиях, для которых нужен fancy tech.
У меня процесс стартовал с обсуждения возможности масштабирования части платформы и уменьшения latency-запросов. Проблемная часть системы была построена на старых сервисах Windows Communication Foundation с классической трехслойной архитектурой. WCF-фреймворк — это SOAP-монстр, но надежный и с широким функционалом, в 2010 году он был основой для Enterprise-решений. На этом же этапе поддержка сервисов и DevOps-задачи забирали приличный объем времени.
Оптимальным считается подход Lift and Shift, который подразумевает перенос сервисов в облако на виртуальные машины с дальнейшим постепенным разделением и рефакторингом на отдельные компоненты. Но такой подход не входил в мои планы, хотя на первый взгляд физически и экономически он выглядел вполне разумно. С другой стороны, перенос кода на .NET Core Web API было достаточно сложно оценить. В результате я сделал PoC за несколько выходных, чтобы оценить возможные риски. Конечно же, оценку рисков стоит начать с проверки качества текущего кода, проверить, живы ли Unit-тесты и т. п. Важно также не планировать отпуск, пока миграция не завершилась успешным развертыванием :)
Почему Service Fabric, а не Kubernetes
Focus on development, not on the infrastructure
Одной из проблем при переходе на новые фреймворки и технологии является повышение сложности систем. Связка Kubernetes + Docker буквально означала, что в результате я получу такой объем DevOps-задач, как и при работе с WCF-сервисами, развернутыми на VMware-фермах.
Эффект IKEA — это когнитивное искажение, которое появляется, когда покупатели непропорционально высоко оценивают значимость (ценность) товаров, которые они создают отчасти сами (Wikipedia).
Простой совет: если сложно сформировать мысль о том, зачем нужна оркестрация контейнеров, то и думать о ней не стоит. Если получилось понять зачем, тогда следует уточнить, нельзя ли сделать это с помощью Serverless-архитектуры. Когда преимущества ясны, тогда дальше статью можно не читать :)
Одной из моих задач было сокращение объема maintenance и DevOps-активностей, чтобы освободить время на разработку нового функционала. Azure Service Fabric после небольшого PoC полностью удовлетворил этим требованиям, плюс кривая обучения гораздо более пологая в сравнении с Kubernetes.
Почему Azure Service Fabric?
- Сокращение цикла разработки.
- Почти полное отсутствие DevOps-задач.
- Простой деливери с помощью Azure DevOps CI/CD pipelines.
- Надежный scale-out and scale-in и отказоустойчивость.
- Простая разработка, кластер ASF запускается на ПК разработчика.
Оценка
Перед оценкой времени на миграцию сначала нужно оценить нагрузку, понять, какие сервисы используются чаще и где наибольшие проблемы с latency и производительностью. Стоит помнить, что легко перенести можно код stateless-приложения, перенос же хранилища данных зависит от многих факторов; но если это MS SQL, то эта задача достаточно тривиальная.
Главное, с чего стоит начать, это с проверки зависимостей и NuGet-пакетов на совместимость с .NET Standard 2.0. Мне повезло, и тут проблем не оказалось.
Что было сделано во время PoC?
- Проверка зависимостей на совместимость с .NET Standard 2.0.
- Создание кластера Azure Service Fabric с подходящей конфигурацией VM.
- Проект с stateless-сервисом Azure Service Fabric.
- Публикация сервиса в облако и создание нескольких простых нагрузочных тестов с помощью Postman и Loader.io.
Пример создания кластера с помощью CLI из воркшопа для Azure Bootcamp Lviv
Что нужно не забыть при оценке проекта?
- Использовать данные, полученные на этапе PoC.
- Добавить время на Infrastructure as Code и настройку CI/CD через Azure DevOps.
- Об установке дополнительных сертификатов и о работе с Azure Key Vault.
- Определиться с секьюрити и выбрать Identity-провайдера.
- Учесть в оценке стоимость работы Dev, Test and Stage энвайронментов.
- Не забыть о мониторинге (и начать с него).
Если взять за основу месяц, два спринта и количество часов в районе 300, то все получится. Нужно подготовить список преимуществ и проблем, которые будут решены в результате завершения проекта. Упомянуть уменьшение времени (стоимости) будущих изменений и указать на пользу в ближайшем будущем.
Security — это просто и сложно одновременно. Если сервисы используются внутри сети, то необходимо развернуть Azure VNet и Network Security Group для ограничения доступа к сервисам из интернета. Если же подразумевается открытый доступ, то, имхо, оптимальный вариант — это Identity as a Service в виде Azure AD B2C, OAuth 2.0 или самописного решения на Identity Server 4.
Что нужно знать перед работой с сервис-фабрикой
Начать стоит, как всегда, с документации и терминологии, а конкретно — со страницы, посвященной планированию кластера. Сервис-фабрика — мощная штука, но дело в том, что для начала работы нужно совсем немного, а копнуть глубже можно по мере роста нагрузки (или нет). Для начала важно понимать терминологию и две вещи.
Во-первых, нужно знать разницу между The durability tier и The reliability tier и для чего они нужны.
А во-вторых, понимать, что кластеры Azure Service Fabric работают на тех же Virtual Machine Scale Sets (VMSS), которые используются в Azure App Service. Если с VMSS уже опыт был, тогда переход будет легким. Стоит помнить, что выполнять манипуляции с VMSS в Service Fabric надо только после полного уяснения терминов выше.
Кластер ASF
Cluster: A network-connected set of virtual or physical machines into which your microservices are deployed and managed. Clusters can scale to thousands of machines.
Node: A machine or VM that’s part of a cluster is called a node. Each node is assigned a node name (a string). Nodes have characteristics, such as placement properties. Each machine or VM has an auto-start Windows service, FabricHost.exe
, that starts running upon boot and then starts two executables: Fabric.exe
and FabricGateway.exe
. These two executables make up the node.
Сколько нужно нод и машин в VMSS? Для старта я бы использовал 3 ноды. После первых нагрузочных тестов конфигурацию и количество машин в VMSS можно изменить в любую сторону. Протестируйте нагрузку, и если при нужном вам количестве запросов в минуту (например, 1000) задержки ниже 200 мс, то можно оставить как есть.
Primary-нода в Service Fabric кластере выполняет задачи, связанные с оркестрацией кластера, и делит ресурсы вашего приложения с системными сервисами. Поэтому не стоит удалять и делать эксперименты на ней, а также производить операции scale-up и scale-in без предварительных тестов.
Обязательно нужно различать кластеры durability и reliability tiers. Знать ограничения, касающиеся понижения уровня с золотого до серебряного и т. п. Если вы оценили нагрузку на старые WCF-сервисы и выполнили нагрузочное тестирование API, то после настройки VMSS scale-out можно спать спокойно.
Перенос кода
План был достаточно простым.
- Перенести код из WCF в Web API.
- Добавить API в stateless ASF-проект.
- Добавить все секреты и сертификаты в Azure Key Vault.
- Распределить функционал по нескольким сервисам.
- Протестировать результат.
Переносим код. Это несложная операция, требующая внимания и покрытия тестами :) Этап начался с переноса WCF-сервисов в контроллеры Web API, используя правило: 1 сервис => 1 контроллер. Компоненты 3-tier-архитектуры легко переносятся в Onion-архитектуру с composition root в Startup.cs (детали вне контекста этой статьи).
После того как перенос кода выполнен, стоит протестировать результат: сделать набор запросов к API и прогнать с помощью Postman. Если HTTP 200, то можно приступать к рефакторингу старых Unit- и Integration-тестов.
Устанавливаем Azure Service Fabric SDK. К сожалению, компоненты локального кластера не работают нормально с Visual Studio 2019, по-прежнему необходима установленная Visual Studio 2017. Перегружаемся и получаем информационное сообщение о запуске локального кластера ASF. После перезагрузки и автоматического запуска кластера стоит сразу уменьшить capacity до 1 ноды, чтобы не тратить ресурсы VM впустую.
Создаем проект Service Fabric с stateless-сервисом для Web, запускаем и переходим по URL созданного контроллера для проверки. Затем заменяем созданное веб-приложение Web API и изменяем GUID проекта в sln-файле. Собираем проект, запускаем и затем проверяем контроллеры с помощью набора запросов в Postman. Вуаля!
Разбиваем сервис на несколько логических частей. Руководствоваться стоит данными по нагрузке, собранными на этапе эстимирования, и здравым (!) смыслом. В описанном выше случае 10 WCF-сервисов поместились в 3 Web-сервиса. Нагрузка при этом оказалась неравномерной, и много ресурсов VMSS (Standard_D1_v2) попросту простаивали. К сожалению, серебряной пули нет и придется проверять нагрузку с помощью нагрузочных тестов. В идеале запускать нагрузочные тесты лучше из Azure DevOps, для этого создать нужное число аккаунтов и использовать бесплатный объем тестов из каждого ;)
К сожалению, к моменту запуска не все тесты в солюшене были переписаны под новое .NET Core приложение :(
Конечно же, были и проблемы
Оказалось, что подход Infrastructure as Code подкинул проблем. При попытке создать кластер фабрики через портал с названиями из скрипта Azure CLI названия не проходят валидацию в инпутах :) Видимо, на портале валидация слегка устаревшая, так как инфраструктурные скрипты продолжают выполняться.
Вывод: не используйте GUI, описывайте вашу инфраструктуру в коде и храните ее в Git или хотя бы в проектной Wiki.
Правильная настройка конфигурации environment variables была изначально упущена, и пришлось поиграть, чтобы решить проблему с помощью
Цена кластера из 5 нод будет в районе 500 долларов США в месяц. Чтобы уменьшить цену минимум в 3 раза, нужно использовать Linux-машины с shared compute типа Standard_B2s и контракт на 3 года. Но тут надо трезво оценить свои силы (время), так как проект .NET Core Web API, скорее всего, не запустится сразу под Linux.
Установка сертификатов кластера тоже имеет специфику и лучшим образом выполняется только с помощью PowerShell-скриптов. Внимательно отнеситесь к эстимированию задач по деплойменту ;) И храните секреты (сертификаты) в Azure Key Vault. Но если надо, то ниже скрипт для установки сертификатов в кластере.
Полезно разобраться в том, как работает Load Balancer, каковы принципы работы Reverse Proxy, что такое VNet и почему нужна Network Security Group. Но, строго говоря, для старта достаточно двух действий: добавления Load Balancer порта 443 и health probe для этого порта. И не забыть удалить порт 80 :)
Для администрирования кластера я использую PowerShell и Azure CLI
Заключение
Как показал опыт, инвестиция своего времени окупается в будущем. Миграция прошла практически без проблем, но дальнейшего роста кластера не последовало. Ответом на рост нагрузки стал перенос кода в Serverless-решения.
Что я бы сделал сейчас по-другому? В принципе, многое. Как минимум перенес бы часть нагруженных сервисов на FaaS в виде Azure Functions с увеличением эстимейта. Но это уже совсем другая история. С учетом требований этот проект оправдал себя. Cheers!
Полезные ссылки:
- Layers, Onions, Ports, Adapters: it’s all the same
- Service Fabric cluster capacity planning considerations
- Azure Service Fabric vs Kubernates
Если будут вопросы, пишите мне в Twitter.