Лучшие практики микросервисов .NET Core и Azure Cloud
Меня зовут Иван Барчук, я Senior разработчик в компании Intellias и эксперт в Centers of Excellence — подразделении, которое занимается повышением квалификации разработчиков и разработки в целом. В этой статье мы рассмотрим основные сервисы стека Microsoft и .NET:
- Azure App Configuration;
- Azure Active Directory B2C;
- Azure Kubernetes Service;
- Pipeline для деплоя и Continuous Delivery на базе Azure DevOps.
Также поговорим о CLI для .NET Core и Health check. Я расскажу, на какие сервисы и инструменты проверки состояния и контроля приложений стоит обратить внимание.
Исходные данные
Основой для этой статьи послужил командный опыт работы на текущим проекте. Мы разрабатываем микросервисную архитектуру нового банка на основе .NET и Azure, в которую входят:
- внутренние Azure инструменты (Logic Apps, Azure Functions, Service Bus, etc.);
- не Microsoft стек (Oracle, Fircosoft, etc.) — поставщик дополнительных ресурсов у нашего клиента.
Этот стек еще будет расширяться, так как наш заказчик планирует добавлять новые функции.
Начав работу над проектом, мы столкнулись с рядом решений, которые предложил предыдущий вендор и которые требовали доработки.
Мы выделили основные болевые точки.
Сложность расширения. Каждая фанка (Azure Functions) была на отдельной машине, что усложняло возможность добавления дополнительной функциональности и повышало стоимость содержания.
Поддержка. Azure фанки не были идеально отработаны в самом Azure. Изначально планировалось запускать их только во время запросов для экономии бюджета. Но, к сожалению, они не всегда запускались и тогда, по рекомендации Microsoft, мы были вынуждены запустить их на постоянной основе. В итоге, затраты выросли.
Logic apps. Эти решения хороши тем, что они несложные и довольно быстро создаются. Но создавать на их основе логирование ошибок и проблем практически невозможно. Мы могли только узнать, какие данные входили или выходили, а также посмотреть, где что происходило и как запустилось.
Версионность. Каждый раз, добавляя новые версии продукта и функционала, приходилось создавать много дополнительных значений, настраивать конфигурации, то есть, фактически делать новую версию.
Цена содержание инфраструктуры Azure. Цена была неприемлемая для клиента, поэтому нашей задачей было снизить стоимости инфраструктуры.
Мы предложили клиенту три основных решения, с которыми он согласился:
- использование Azure App Configuration, которое бы позволяло решить проблему версионности (контроль версий), получить одну точку доступа ко всем конфигурациям и возможность включать/выключать фичи;
- переход на .NET Core API, что значительно упрощало поддержку, давало возможность вставлять логи, где нужно, логировать их и все записывать;
- использование Azure Kubernetes Service — основное нововведение на проекте, которое значительно снизило стоимость, упростило деплой и расширяемость проекта в целом.
Рассмотрим каждое из трех решений подробнее.
Azure App Configuration
Для начала, мы начали переводить наши конфигурации, которые хранились в Azure Key-Vault, в App Configuration. Недостатки Azure Key-Vault состоят в том, что это просто словарь с ключом и значением. Соответственно, там невозможно добавлять дополнительный функционал или контроль. С другой стороны, App Configuration позволяет раздавать конфигурации для всех ресурсов (Logic Apps, Azure Functions, etc.), которые уже существуют, и тех, которые будут добавляться или расширяться.
Как это выглядит в коде:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => webBuilder.ConfigureAppConfiguration(config => { var settings = config.Build(); var connection = settings.GetConnectionString("AppConfig"); config.AddAzureAppConfiguration(connection); }).UseStartup<Startup>());
Добавить сам проект в .NET Core достаточно просто. Для этого нужно:
— Добавить nuget package Azure App Configuration;
— Cоздать конфигуратор в HostBuilder;
— Выбрать WebHost — AddConfiguration (Connection);
-> Получаем доступ к нашим конфигурациям по существующим настройкам.
Пример
Использование Azure App Configuration дает возможность легко соблюдать namespaces.
Пример

Для этого создаем:
- название аппликации, две точки;
- названия объекта, две точки;
- название класса, две точки;
- название property;
-> получаем MyApp:CircuitBreaker:DurationOfBreakingSecond.
Так получаем key-value значения, которые нам нужны. Мы можем создать instance или интернал класс и хранить в нем нужные нам конфигурации по всему проекту. Кроме того, они будут работать не только у настроившего их разработчика, но и у всех остальных. Для этого не нужно будет передавать secret.json или рассказывать, как подключиться.
Следующая особенность Azure App Configuration — Label.
Пример

Конфигурации могут отличаться в зависимости от среды, которая позволяет получить доступ только к проду, к стейджу или к девелоперу. Например, у вас есть зашифрованная база данных. Если вам нужно, чтобы данные оставались зашифрованными, вы ставите true. На Dev вам нужно просто понимать, как приходят данные, и можете продолжать ими делиться.
Import-Export. Инструмент, которым мы пока ещё не пользовались, но он предназначен для переноса (импорта/экспорта) данных.
Пример

Еще одна особенность приложения Azure — Feature management, который позволяет нам настраивать включение/выключение каких-либо функционалов.
Пример

Можно прописать внутри кода, как использовать фичу, должна она работать или нет. К примеру, функционал не должен работать на праздники или в нерабочее время. В этом случае вы можете настраивать временные рамки. Возможно, что фича перестала быть актуальной, либо оказалась вредной, потому что ломает данные или работает некорректно уже на самом проде. Тогда вы можете остановить ее работу.
В App Configuration есть возможность добавлять Events.
При изменении конфигураций можно добавить события или действия, которые надо совершить.
Blob Storage, Event Hubs, Logic Apps позволяют подписаться на события и изменения в Azure App Configuration.
Одна из функций, которая помогла нам быстро перейти в .Net Core, не потеряв конфигурации, хранившиеся в Key Vault, — это возможность создавать ссылку в App Сonfiguration на Key-Vault Reference. Можно продолжать пользоваться конфигурациями либо, при необходимости, ограничить доступ к ним и распределить доступы для ключей значений.
Azure Active Directory B2C
Мы используем на проекте и внешние источники данных, и внешние дополнительные аппликации от третьих поставщиков. Кроме того, наши клиенты имеют свою систему внутренней безопасности, а также внутренние клиентские и пользовательские базы. Чтобы упростить процесс, мы применяем Azure Active Directory B2C, который позволяет создавать клиентов внутри базы без потери конфиденциальности и ключей.
Мы настраивали Service principal доступы, доступ приложений и доступ конкретных клиентов и пользователей.
Active directory B2C — это директория, где хранятся все данные о пользователях, системные регистрации, кастомные политики идентификации и пользовательские пути, которые можно добавить. Также там находятся провайдеры идентификации:
- Directory. В каталоге (directory) Azure AD B2C хранит учетные данные, а также данные профиля ваших пользователей и регистрации ваших приложений.
- Application registrations. Вы регистрируете свои веб- и мобильные приложения в Azure AD B2C, чтобы включить управление удостоверениями. Кроме того, можете зарегистрировать любые API-интерфейсы, которые нужно защитить с помощью Azure AD B2C.
- User flows и custom policies. Встроенные (user flows) и полностью настраиваемые (custom policies) возможности идентификации для ваших приложений. Используйте user flows для быстрой настройки и включения общих задач идентификации, таких как регистрация, вход в систему и редактирование профиля. Используйте custom policies чтобы предоставить пользователям возможности не только решать общие задачи идентификации, но и создавать поддержки сложных рабочих процессов, уникальных для вашей организации, клиентов, сотрудников и партнеров.
- Identity providers:
- Social identity провайдеры, такие как Facebook, LinkedIn или Twitter, которые вы хотите поддерживать в своих приложенияx.
- External identity провайдеры, поддерживающие стандартные протоколы идентификации, такие как OAuth 2.0, OpenID Connect и другие.
- Local accounts записи, которые позволяют пользователям регистрироваться и входить в систему, используя имя пользователя (или адрес электронной почты) и пароль.
- Keys. Добавление и управление ключами шифрования для подписи и проверки токенов, клиентских секретов, сертификатов и паролей.
Social identity мы не используем, но используем Local accounts и External identity, которые позволяют подключить клиентов, в том числе и корпоративных. У некоторых из них есть Active directory доступы, у кого-то есть локальные хранилища пользователей, которые они хотят ограничить и получать в то же время доступ к нашему банку. Также пользуемся ключами. Доступы разбиваются по трем основным уровням:
- Work account — это пользователи самого банка или разработчики.
- Guest account — это внешние пользователи, которые получили доступ по настройкам, например, из локального хранилища, либо из другого Azure Active каталога, но требуют дополнительного подтверждения от администратора и того, кто отвечает за доступ.
- Consumer account — это покупатели либо пользователи данного ресурса, которым необходимо подтверждение.
Docker. Для чего он нужен и как он работает
Разработчиком контейнера можно назвать Малькольма Маклина, он первый, кто его придумал. Разработчиком Docker-а является Соломон Хайкс. Сложно сказать наверняка, вдохновлялся ли создатель Docker Соломон Хайкс идеей контейнера, которая принадлежит Малкольму Маклину, или же придумал все самостоятельно, но аналогии с морскими перевозками очевидны.
Если говорить просто, то Docker — это очень упрощенный образ виртуальной машины. Он не создает саму виртуальную машину, только операции, в которых запускаются контейнеры. Иначе говоря, в контейнерах находятся .Net, JavaScript, Java приложения и другие. Внутри статических images, в которых установлены либо linux, либо node, помещается сам контейнер. Дальше он перемещается в регистр и запускается уже тем или иным docker-ом, который позволяет фактически на одной машине иметь несколько images, распределять доступы и обеспечивать деплой. Внутри контейнера есть своя инфраструктура.
Я бы не рекомендовал помещать в контейнере SQL Server, потому что они становятся слишком громоздкими. Лучше оставить его в качестве стороннего сервиса или поместить в отдельный контейнер. Очень важно следить за контейнерами и контролировать их состояние. Для этого используется Kubernetes.
Azure Kubernetes Service
Kubernetes — это опенсорсное приложение, которое позволяет оркестрировать контейнеры, распределять их и управлять нагрузкой. Kubernetes был создан для внутренних пользователей в Google inc., но со временем его передали на опенсорс комюнити, где он сейчас хранится и расширяется. Это приложение сильно упрощает работу с деплойментом, с расширением, менеджментом, декларацией сервисов и доступами. Кроме того, у него большая инфраструктура для поддержания health-check и self-heal. То есть, он перезапускает контейнеры и следит за тем, чтобы они работали в нужных последовательностях.
Kubernetes состоит из Master Node и Work Nodes, через который идет настройка основных сервисов: их работа, распределение, создание Node-ов и открытие данных. В каждом Nod-е может находиться по несколько контейнеров, то есть, это можно представить как виртуальную сеть на одном компьютере с несколькими сервисами.
Продолжая морскую аналогию, Kubernetes — это контейнеровоз с кранами, который может сам сдвинуть контейнер, настроить, подключить и проверить его состояние.
Теперь разберем, для чего нам отдельный и к тому же дорогой сервис на базе Azure, если есть Kubernetes, который все делает сам.
Если вернуться к аналогии с морскими перевозками, где Docker — это контейнер, в который мы можем всё сложить, Kubernetes — это контейнеровоз, который может их у себя разместить и поплыть дальше, то Azure Kubernetes Service — это логистическая компания. Мы передаем все вопросы по поддержке, апдейту, синхронизации и обслуживание самого Kubernetes-а на Azure.
Что это нам дает? Во-первых, это упрощает работу. Для того, чтобы создать новый кластер или обновить существующий, достаточно попросить об этом Azure Kubernetes.
Загрузка и управление Kubernetes
Task | The Old Way | With Azure |
Create a cluster | Provision Network an VMs Install dozens of system components includings etcd Create and install certificates Register agent nodes with control plane | az aks create |
Upgrade a cluster | Upgrade your master nodes Cordon/drain and upgrade worker nodes individually | az aks upgrade |
Scale a cluster | Provision new VMs Install system components Register nodes with API Server | az aks scale |
В обычном Kubernetes для этого нужно создать сеть виртуальных машин, инициализировать компоненты, инсталлировать сертификации, зарегистрировать агент node, новую node, control plane. Azure же все делает сам.
Во-вторых, это возможность скомпоновать контейнерную аппликацию и деплой в Kubernetes. Нужно просто инициализировать в Azure новую конфигурацию кластера, создать Docker файл и задеплоить его на Kubernetes.
Ускорение разработки контейнерных приложений
Task | The Old Way | With Azure |
Build a containerized and deploy to Kubernetes | Build the app resource Define a Dockerfile/Helm chart Build the container image Push the container to a registry With Kubernetes manifest/Helm chart Deploy to Kubernetes | draft init to configure your environment draft create to auto-create Docker/Helm chart draft up to deploy to Kubernetes |
Build and test individual services in a microservices architecture | Set up a local dev environment using Minikube Determine the transitive closure of dependencies Identity behavior of dependencies for key test case Stub out dependent services with expected behavior Make local changes, check-in, and hope things work Validate with application logs | Use DevSpace to iterate, test and debug Fo breakpoint debugging in your IDE |
Expose web apps to internet with a DNS entry | Deploy an ingress controller Create a load-balanced IP for it Add an ingress resource to your deployment Acquire a custom domain Create DNS A-record for your service | Turn HTTP Application routing on in your cluster Add an ingress resource to your deployment |
В обычном Kubernetes надо было бы билдить проект, добавлять Docker файл, билдить контейнер, запушить этот контейнер в регистр, написать Kubernetes Manifests и задеплоить это в Kubernetes. Этим можно заниматься, если в команде есть девопс, который это обслуживает, но можно просто передать все в работу Azure Kubernetes.
Самое интересное — это упрощение Continuous integration и continuous deployment. Очень рекомендую Azure DevOps — многофункциональный инструмент, который позволяет создавать, управлять и следить за проектом. По большому счету, это смесь Jirа, Git, Jenkins и Azure. Он есть в бесплатной версии — можно посмотреть, попробовать и даже создать готовый проект.
Настройка CI/CD в несколько кликов
Task | The Old Way | With Azure |
Set up CI/CD pipeline and deploy to Kubernetes | Create git repo Create a buildpipeline Create a container registry Create a Kubernetes cluster Configure build pipeline to push to container registry Configure build pipeline to deploy to Kubernetes | Create an Azure DevOps project with AKS as a target |
Make container image available for deployment worldwide | Create a container registry in every in region Configure build pipeline with multiple endpoints Loop through all regions and push followings build | Create an Azure Container Registry with geo-replication Push your image to a single endpoint |
Track health with consolidated cluster and application logs | Choose a logging solution Deploy log stack in your cluster or provision a service Configure and deploy a logging agent onto all nodes | Checkbox «container monitoring» in the Azure portal |
Чтобы задеплоить новую версию проекта, вам нужно создать проект в Azure Active Directory с AKS и указать в таргете. Этот процесс можно автоматизировать — настроить webhook на новые изменения и просто следить за ним.
Контейнеры точно так же регистрируются в гео-репликации. Пушится новый image и новый endpoint, то есть, значительно упрощается задача по созданию любых Node-ов. Мы этого не делаем, так как создаем только код и бизнес-логику. Но нужно прописать минимум настроек в самом Kubernetes для того, чтобы он начал работать.
В каких случаях я бы не рекомендовал использовать Kubernetes и докеризацию:
- Если вы работаете с монолитной системой.
- Если вы используете CRM или CMS с внешними установленными модулями.
В первом случае, имея монолит с внутренними настройками, вы каждый раз будете сбрасывать все до начальных настроек, разворачивая новый проект. То есть вам нужно будет выносить конфигурации на внешний источник, а это может быть и Azure Application Active Directory. Также вы получаете неэффективное управление — содержите сервис-оркестрацию ради одного сервиса, в то время, как это можно сделать локальными инструментами.
Во втором случае, не рекомендую использовать Kubernetes ни для CRM и CMS, ни для Umbraco CMS, ни для Wordpress, ни для Drupal. При большом желании вы можете попробовать, но тогда вам нужно изучить, куда вынести настройки и куда сохранять плагины, которые задеплоит или установит для себя пользователь. Если, к примеру, у вас есть интернет-магазин, а ваш пользователь установит плагин, который добавляет дополнительные поля к товарным сущностям, может лечь вся база.
Pipeline в Azure DevOps
Azure DevOps позволяет создавать Pipeline — прописанный путь, по которому ваш код проходит от репозитория до деплоя. Будет то веб- или мобильное приложение, вы можете все прописать в файле настройки YAML.
Путь настройки пайплайна
Происходит это следующим образом: вы пишите код в Visual Studio, после этого добавляете в Git репозиторий. Кстати, не обязательно использовать DevOps — это может быть любой Git репозиторий, в том числе и GitHub, GitLab, Bitbucket и другие. После проведения всех тестов, ваши репозитории и контейнер регистрируются и деплоятся в Azure Kubernetes. Главное — пропишите в YAML файле шаги.
Путь развертывания проекта
Файл пайплайна YAML
Темплейт | Пример | |
•PipelineStage A •Job 1 •Step 1.1 •Step 1.2 •... •Job 2 •Step 2.1 •Step 2.2 •... •Stage B •... | name: string # build numbering format resources: pipelines: [ pipelineResource ] containers: [ containerResource ] repositories: [ repositoryResource ] variables: # several syntaxes, see specific section trigger: trigger pr: pr stages: [ stage | templateReference ] | stages: — stage: Build jobs: — job: BuildJob steps: — script: echo Building! — stage: Test jobs: — job: TestOnWindows steps: — script: echo Testing on Windows! — job: TestOnLinux steps: — script: echo Testing on Linux! — stage: Deploy jobs: — job: Deploy steps: — script: echo Deploying the code! |
Например, слева прописываем основные stages и jobs, посередине описывается значение, а справа — билд и билд jobs. Также проведите скрипт тест. Можно добавить любое количество дополнительных тестов (тесты на форматирование, юнит интеграционные тесты и другие). Кроме того, можно распределить деплой на несколько сред.
На своих рабочих машинах мы прописали путь, по которому код должен обязательно двигаться. Dev среда у нас срабатывает и останавливается, никаких дальнейших действий нет. Но, если мы деплоим на uat, что перед деплоем на prod, то нам нужно пойти по другому пути. Код должен пройти через деплой на uat, а после этого — дополнительные тесты, а также интеграционные тесты для деплоя на prod.
CLI for . net core services
Необходимо создать свой кастомной темплейт для сервисов .NET Core Command-Line Interface (CLI):
— dotnet new —install «Your.Template.Here»;
— dotnet new —install «Microsoft.AspNetCore.Blazor.Templates»;
— dotnet new blazor -o TestBlazor.
В результате, когда мы создаем новые сервисы, структуры получаются одинаковые. Я рекомендую потратить время на то, чтобы создавать макет сервиса и наполнить его структурой. Довольно легко создавать свои кастомные сервисы, особенно, если они однотипные по функционалу. Это можно делать через create new project. Создаете project template и распространяете его в вашей команде. Также вы можете использовать CLI. Добавьте новую папку template.config и запишите в нее template.json с такими настройками:
{ "author": "Your Name", "name": "Test Web Template", "identity": "MyTest.WebTemplate", "shortName": "testWeb", "classifications": [ "Web" ], "tags": { "language": "C#" }, "sourceName": "TestProject" } | • identity — уникальное имя, которое используют при вводе команды dotnet new —install. • shortName — ключевое слово, которое пользователи будут применять при создании проекта с использованием шаблона. • classifications — позволяет вам указать, к какому типу проекта (например, Интернет) принадлежит шаблон. • tags — область позволяет классифицировать дополнительные метаданные для шаблона. • sourceName — позволяет указать имя проекта текущего шаблона. Затем CLI может заменить это значение тем, которое указано в name |
Azure Monitor как Health check на Azure
Мониторинг — один из самых важных инструментов, который в Azure называетесь Azure Monitor.
AM (Azure Monitor) состоит из нескольких аналитик и визуализаций, которые можно передать, — это метрики и логи. Некоторые логи Azure собирает сам, какие-то метрики мы можем добавлять и расширять.
В метриках можно настраивать просмотр. Это значит, что у вас есть возможность отслеживать работу приложения (либо Azure Func, либо сервиса), и видеть, нет ли там утечки памяти или критических ошибок. В итоге, вы можете отследить работу самого приложения со стороны «боевой» среды. Также можно прописать критические точки, которые нам понадобятся для того, чтобы подключить специалиста. Если нагрузка будет значительно больше, чем ожидалось, тогда вы сможете либо расширить кластер, либо оптимизировать код.
Мы можем отслеживать и контролировать работу разных логов — на отказ, на доступ, на просмотр, на ошибки
Azure Application Insights
Application Insights — еще один инструмент, который чаще всего используется в веб-приложениях. Он позволяет следить за состоянием самого приложения, контролировать его работу и функционал. Через него проходят все запросы на приложение. Даже если у вас не прописаны какие-то внутренние логи, вы все равно сможете узнать, в какой момент приложение перестало работать. Также есть возможность создавать предупреждения.
Основные метрики, которые есть по умолчанию и за которыми следит Application Insights — это время ответов, как часто происходит та или иная ошибка, время загрузки страницы, AJAX запросы, количество сессий, диагностика и отслеживание логи для ваших приложений. Вы можете добавлять кастомные события и метрики, которые можно отслеживать в самом приложении.
Результаты
Используя эти инструменты нам удалось достичь таких результатов:
- Цена содержание инфраструктуры снизилась в три раза и продолжает снижаться, несмотря на разработку новой функциональности.
- Улучшилась расширяемость любой части приложения. Теперь каждая часть находится в кластере под управлением Kubernetes.
- Появилась возможность добавлять новый функционал и управлять старыми функциями.
- Увеличилась скорость разработки и вовлечение новых разработчиков. Не нужно вникать в длинный стек технологий и их взаимодействия между собой, так как наш новые сервис — это чистый .NET Core.
Мы еще не до конца перенесли старые части проекта в Kubernetes, но основное требование от клиента мы выполнили — снизили в три раза стоимость среды и упростили себе жизнь. Также, мы смогли добавить проекту гибкости благодаря Azure App Configuration. Есть возможность добавлять нужный новый функционал, проверять его, интегрировать, включать, подключать, настраивать. Очень помогли темплейты. Введение нового специалиста в команду ускорился буквально до одного дня. Специалист, создав несколько сервисов и пройдя по базовой структуре, быстро понимает, как работает проект.
11 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів