Вы находитесь на странице: 1из 371

Contents

Микрослужбы .NET: Архитектура контейнерных приложений .NET


Общие сведения о контейнерах и Docker
Что такое Docker?
Терминология Docker
Контейнеры, образы и реестры Docker
Выбор между .NET 5 и .NET Framework для контейнеров Docker
Общее руководство
Выбор .NET для контейнеров Docker
Выбор .NET Framework для контейнеров Docker
Таблица для принятия решений. Использование платформ .NET для Docker
Для какой ОС использовать контейнеры .NET
Официальные .NET-образы Docker
Проектирование архитектуры приложений на основе контейнеров и
микрослужб
Контейнеризация монолитных приложений
Управление состоянием и данными в приложениях Docker
Сервисноориентированная архитектура
Архитектура микрослужб
Владение данными в каждой микрослужбе
Логическая и физическая архитектура
Распределенное управление данными: проблемы и решения
Определение границ модели предметной области для каждой микрослужбы
Прямое взаимодействие клиента и микрослужбы по сравнению с
использованием шаблона службы API
Взаимодействие в архитектуре микрослужб
Асинхронное взаимодействие на основе сообщений
Создание, развитие и управление версиями API-интерфейсов и контрактов
микрослужб
Возможность адресации микрослужб и реестр служб
Создание составного пользовательского интерфейса на основе микрослужб,
включая создание его визуальной формы и структуры с помощью нескольких
микрослужб
Устойчивость и высокий уровень доступности в микрослужбах
Управление микрослужбами и многоконтейнерными приложениями для
обеспечения высокого уровня масштабируемости и доступности
Процесс разработки для приложений на основе Docker
Рабочий процесс разработки для приложений Docker
Проектирование и разработка приложений .NET на основе множества
контейнеров и микрослужб
Разработка приложения на основе микрослужб
Создание простой микрослужбы CRUD на основе данных
Определение многоконтейнерного приложения с помощью docker-
compose.yml
Использование сервера баз данных, работающего в качестве контейнера
Реализация взаимодействия между микрослужбами на основе событий
(события интеграции)
Реализация шины событий с помощью RabbitMQ для среды разработки или
тестирования
Подписка на события
Тестирование служб и веб-приложений ASP.NET Core
Реализация фоновых задач в микрослужбах с помощью IHostedService и
класса BackgroundService
Реализация шлюзов API с помощью Ocelot
Использование микрослужб с шаблонами DDD и CQRS для решения сложных
бизнес-задач
Применение упрощенных шаблонов CQRS и DDD в микрослужбах
Применение подходов CQRS и CQS в микрослужбе DDD в eShopOnContainers
Реализация операций чтения и запросов в микрослужбе CQRS
Проектирование микрослужбы, ориентированной на DDD
Проектирование модели предметной области микрослужбы
Реализация модели предметной области микрослужбы с помощью .NET
Seedwork (многократно используемые базовые классы и интерфейсы для
модели предметной области)
Реализация объектов значений
Использование классов перечисления вместо типов перечисления
Проектирование проверок на уровне модели предметной области
Проверка на стороне клиента (проверка на уровнях представления)
События предметной области: проектирование и реализация
Проектирование уровня сохраняемости инфраструктуры
Реализация уровня сохраняемости инфраструктуры с помощью Entity
Framework Core
Использование баз данных NoSQL в качестве инфраструктуры сохраняемости
Разработка веб-API и уровня приложений для микрослужб
Реализация прикладного уровня микрослужб с помощью веб-интерфейсов
API
Реализация устойчивых приложений
Обработка частичного сбоя
Стратегии для обработки частичного сбоя
Реализация повторных попыток с экспоненциальной выдержкой
Реализация устойчивых SQL-подключений Entity Framework Core
Использование IHttpClientFactory для реализации устойчивых HTTP-запросов
Реализация повторных попыток вызова HTTP с экспоненциальной выдержкой
с помощью библиотеки Polly
Реализация шаблона размыкателя цепи
Мониторинг работоспособности
Обеспечение безопасности веб-приложений и микрослужб .NET
Об авторизации в веб-приложениях и микрослужбах .NET
Безопасное хранение секретов приложения во время разработки
Использование Azure Key Vault для защиты секретов в рабочей среде
Главные выводы
Микрослужбы .NET: Архитектура контейнерных
приложений .NET
02.11.2021 • 6 minutes to read

Выпуск 5.0 — обновлен до ASP.NET Core 5.0

Обновления книги и вклад сообщества см. в журнале изменений.


В этом руководстве приводятся общие сведения о разработке приложений на основе микрослужб и
управлении ими с помощью контейнеров. В нем рассматриваются подходы к проектированию и
реализации архитектуры с использованием .NET и контейнеров Docker.

Чтобы вам было проще приступить к работе, в руководстве подробно изучается пример контейнерного
приложения на основе микрослужб. Образец приложения доступен в репозитории GitHub
eShopOnContainers.

Ссылки действий
Эта электронная книга также доступна в формате PDF (только на английском языке) Скачать

Клонировать эталонное приложение eShopOnContainers на GitHub или создать для него вилку

Просмотреть вводный видеоролик на канале Channel 9

Быстрое знакомство с архитектурой микрослужб

Вступление
Предприятия все шире применяют контейнеры с целью сэкономить средства, решить проблемы,
возникающие при разработке решений, и оптимизировать процессы разработки и рабочие операции.
Корпорация Майкрософт развивает технологии в области контейнеров для Windows и Linux, создавая
такие продукты, как Служба Azure Kubernetes и Azure Service Fabric, и сотрудничая с ведущими в отрасли
компаниями, такими как Docker, Mesosphere и Kubernetes. С помощью этих решений для работы с
контейнерами организации могут создавать и развертывать приложения с той же скоростью и
масштабируемостью, что и в облачной среде, на основе любых платформ и средств.

Docker становится стандартом де-факто в области контейнеризации приложений. Это решение


поддерживается большинством поставщиков в экосистеме Windows и Linux. (Корпорация Майкрософт —
один из основных поставщиков облачных решений, поддерживающих Docker.) В будущем Docker,
вероятно, можно будет встретить в любом центре обработки данных как в облаке, так и в локальной
среде.

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

Об этом руководстве
В этом руководстве приводятся общие сведения о разработке приложений на основе микрослужб и
управлении ими с помощью контейнеров. В нем рассматриваются подходы к проектированию и
реализации архитектуры с использованием .NET и контейнеров Docker. Чтобы вам было проще
приступить к работе с контейнерами и микрослужбами, в руководстве подробно изучается пример
контейнерного приложения на основе микрослужб. Пример приложения доступен в репозитории GitHub
eShopOnContainers.
В этом руководстве приведены базовые принципы разработки и архитектуры, в первую очередь — на
уровне среды разработки. Основное внимание уделяется двум технологиям: Docker и .NET. Мы ставили
себе целью, чтобы при чтении этого руководства вы могли сосредоточиться на проектировании
приложения, не задумываясь об инфраструктуре рабочей среды (облачной или локальной). Принимать
решения, связанные с инфраструктурой, вы будете позднее при создании приложений, готовых к
использованию в рабочей среде. Таким образом, это руководство ориентировано на среду разработки
без учета особенностей инфраструктуры.
После изучения этого руководства вашим следующим шагом будет изучение готовых к использованию
микрослужб в Microsoft Azure.

Version
В новую редакцию руководства включены сведения о версии .NET 5 и множество дополнений, связанных
с тем же "поколением" технологий (т. е. технологий Azure и сторонних производителей), к которому
относится выпуск .NET 5. По этой причине версия книги также была изменена на 5.0 .

Темы, которые выходят за рамки этого руководства


В этом руководстве не рассматриваются такие вопросы, как жизненный цикл приложения, DevOps,
конвейеры непрерывной интеграции и непрерывного развертывания, а также совместная работа. Эти
темы обсуждаются в дополнительном руководстве Жизненный цикл контейнерного приложения Docker
на основе платформы и средств Майкрософт . В настоящем руководстве также не приводятся сведения о
реализации инфраструктуры Azure, например информация о конкретных оркестраторах.

Дополнительные ресурсы
Containerized Docker Application Lifecycle with Microsoft Platform and Tools (Жизненный цикл
контейнерного приложения Docker на основе платформы и средств Майкрософт ) (электронная книга,
доступная для скачивания)
https://aka.ms/dockerlifecycleebook

Кому необходимо это руководство


Мы создали это руководство для разработчиков и архитекторов решений, которые не имеют опыта
разработки приложений на основе Docker и работы с архитектурой микрослужб. Воспользуйтесь этим
руководством, чтобы узнать, как спроектировать архитектуру и реализовать приложение для проверки
концепции с помощью технологий разработки Майкрософт (особое внимание уделяется .NET) и
контейнеров Docker.

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

Как пользоваться руководством


В первой части этого руководства приводятся общие сведения о контейнерах Docker, описываются
критерии выбора .NET 5 или .NET Framework в качестве платформы разработки и дается обзор
микрослужб. Это содержимое предназначено для архитекторов и лиц, принимающих технические
решения, которым требуется получить общее представление, не вдаваясь в подробности реализации на
уровне кода.

Вторая часть руководства начинается с раздела Процесс разработки для приложений на основе Docker.
Он посвящен разработке и шаблонам микрослужб для реализации приложений с помощью .NET и Docker.
Этот раздел будет особенно интересен разработчикам и архитекторам, которым нужны подробные
сведения о реализации на уровне кода и шаблона.

Пример приложения на основе микрослужб и контейнеров:


eShopOnContainers
Приложение eShopOnContainers — это образец приложения с открытым кодом для .NET и микрослужб,
который предназначен для развертывания с помощью контейнеров Docker. Это приложение состоит из
нескольких подсистем, включая ряд пользовательских интерфейсов для электронного магазина (веб-
приложение MVC, SPA и собственное мобильное приложение). В его состав также входят внутренние
микрослужбы и контейнеры для всех необходимых операций на стороне сервера.

Это приложение предназначено для демонстрации архитектурных шаблонов. ЭТОТ ШАБЛОН НЕЛЬЗЯ
РАССМАТРИВАТЬ КАК ГОТОВУЮ К ЗАПУСКУ ОСНОВУ для реальных приложений. По сути это
приложение постоянно находится в состоянии бета-версии и используется для тестирования новых
интересных технологий по мере их появления.

Отправьте нам свой отзыв.


Мы создали это руководство, чтобы помочь вам разобраться в архитектуре контейнерных приложений и
микрослужб в .NET. Руководство и связанный с ним пример приложения будут развиваться, поэтому мы
будем рады вашим отзывам! Если у вас есть замечания касательно того, как можно улучшить это
руководство, направляйте ваши отзывы по адресу https://aka.ms/ebookfeedback.

Благодарности
Соавторы:

Сезар де ла Торре (Cesar de la Torre) , старший руководитель проекта, команда разработки .NET,
корпорация Майкрософт.

Билл Вэгнер (Bill Wagner) , старший разработчик содержимого, отдел C+E, корпорация
Майкрософт.

Майк Роусос (Mike Rousos), главный специалист по разработке программного обеспечения, команда
DevDiv CAT, корпорация Майкрософт

Редакторы:

Майк Поуп (Mike Pope)

Стив Хоуг (Steve Hoag)

Участники и рецензенты:

Джеффри Рихтер (Jeffrey Richter), партнер по разработке программного обеспечения, команда


Azure, корпорация Майкрософт
Джимми Богард (Jimmy Bogard), главный архитектор Headspring

Уди Дахан (Udi Dahan), основатель и генеральный директор компании Particular Software

Джимми Нилссон (Jimmy Nilsson), сооснователь и генеральный директор компании Factor10

Гленн Кондрон (Glenn Condron) , старший менеджер программ, команда ASP.NET.

Марк Фасселл (Mark Fussell), ведущий руководитель проектов, команда Azure Service Fabric,
корпорация Майкрософт

Диего Вега (Diego Vega), руководитель проектов, команда Entity Framework, корпорация
Майкрософт

Барри Дорранс (Barr y Dorrans) , старший менеджер программ безопасности.

Роуэн Миллер (Rowan Miller) , старший менеджер программ, Майкрософт.

Анкит Астана (Ankit Asthana), ведущий руководитель проектов, команда .NET, корпорация
Майкрософт
Скотт Хантер (Scott Hunter), помощник главного руководителя проектов, команда .NET, корпорация
Майкрософт

Ниш Анил (Nish Anil) , старший менеджер программ, команда .NET, корпорация Майкрософт

Дилан Райзенбергер (Dylan Reisenberger), архитектор и руководитель разработки, компания Polly

Стив Смит (Steve Smith) , преподаватель и разработчик программного обеспечения, Ardalis.com

Ян Купер (Ian Cooper), архитектор кода, компания Brighter

Унаи Зоррилла (Unai Zorrilla), архитектор и руководитель разработки, компания Plain Concepts

Эдуард Томас (Eduard Tomas), руководитель разработки, компания Plain Concepts

Рамон Томас (Ramon Tomas), разработчик, компания Plain Concepts

Дэвид Санс (David Sanz), разработчик, компания Plain Concepts

Хавьер Валеро (Javier Valero) , исполнительный директор Grupo Solutio

Пьер Милле (Pierre Millet) , старший консультант , Майкрософт.

Михаэль Фриис (Michael Friis), менеджер по продукции, компания Docker Inc

Чарльз Лоуэлл (Charles Lowell), специалист по разработке программного обеспечения, команда VS


CAT, корпорация Майкрософт
Мигель Велосо (Miguel Veloso), инженер по разработке программного обеспечения в Plain Concepts

Самит Гош (Sumit Ghosh) , главный консультант в Neudesic

Copyright
ИЗДАТЕЛЬ

Подразделение Microsoft Developer Division, команды разработки .NET и Visual Studio

Подразделение корпорации Майкрософт

One Microsoft Way


Redmond, Washington 98052-6399
© Корпорация Майкрософт (Microsoft Corporation), 2021.
Все права защищены. Запрещается полное или частичное воспроизведение или передача настоящей
книги в любом виде или любыми средствами без письменного разрешения издателя.

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

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

Microsoft и товарные знаки, перечисленные на странице "Товарные знаки" на сайте


https://www.microsoft.com, являются товарными знаками группы компаний Майкрософт.
Mac и macOS являются товарными знаками Apple Inc.
Логотип Docker с изображением кита является зарегистрированным товарным знаком Docker, Inc.
Используется с разрешения.

Все другие наименования и логотипы являются собственностью своих законных владельцев.

ВПЕРЕД
Общие сведения о контейнерах и Docker
02.11.2021 • 2 minutes to read

Контейнеризация — это подход к разработке программного обеспечения, при котором приложение или
служба, их зависимости и конфигурация (абстрактные файлы манифеста развертывания) упаковываются
вместе в образ контейнера. Контейнерное приложение может тестироваться как единое целое и
развертываться как экземпляр образа контейнера в операционной системе (ОС ) узла.

Так же как обычные контейнеры позволяют перевозить любые грузы на корабле, поезде или грузовике,
программные контейнеры выступают в качестве стандартных модулей для развертывания программного
обеспечения, которые могут содержать различный код и зависимости. Контейнеризация программного
обеспечения позволяет разработчикам и ИТ -специалистам развертывать его в разных средах без каких-
либо изменений или с минимальными изменениями.

Контейнеры также изолируют приложения друг от друга в общей операционной системе. Контейнерные
приложения выполняются на основе узла контейнеров, который в свою очередь работает в
операционной системе (Linux или Windows). Поэтому контейнеры требуют гораздо меньше ресурсов, чем
образы виртуальных машин.

Каждый контейнер может вмещать целое веб-приложение или службу, как показано на рис. 2-1. В этом
примере узел Docker — это узел контейнеров, а App1, App2, Svc 1 и Svc 2 — контейнерные приложения
или службы.

Рис. 2-1 . Несколько контейнеров на одном узле

Еще одним преимуществом контейнеризации является масштабируемость. Вы можете быстро


осуществлять горизонтальное масштабирование, создавая контейнеры для краткосрочных задач. С
точки зрения приложения, создание экземпляра образа (создание контейнера) аналогично созданию
экземпляра процесса, например, для службы или веб-приложения. Но для обеспечения надежности при
запуске нескольких экземпляров одного образа на нескольких серверах обычно желательно, чтобы
контейнеры (экземпляры образа) выполнялись на разных серверах или виртуальных машинах в разных
доменах сбоя.

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

НА ЗА Д ВПЕРЕД
Что такое Docker?
02.11.2021 • 4 minutes to read

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

Рис. 2-2 . Docker развертывает контейнеры на всех уровнях гибридного облака.

Контейнеры Docker могут работать в любой среде, например в локальном центре обработки данных, в
службе стороннего поставщика или в облаке Azure. Контейнеры образов Docker работают в исходном
формате в Linux и Windows. Но образы Windows будут выполняться только на узлах Windows, тогда как
образы Linux — на узлах Linux или Windows (на данный момент с помощью виртуальной машины Linux
Hyper-V). Термин "узлы" здесь означает физические серверы и виртуальные машины.
Разработчики могут использовать среды разработки на базе Windows, Linux или macOS. На компьютере
разработчика выполняется узел Docker, где развернуты образы Docker с создаваемым приложением и
всеми его зависимостями. Разработчики, работающие в Linux или macOS, могут использовать узел Docker
на базе Linux и создавать образы только для контейнеров Linux. (В macOS разработчики могут изменять
код приложения и запускать Docker CLI в macOS, но на момент написания этой статьи они не могут
запускать контейнеры непосредственно в macOS.) В Windows разработчики могут создавать образы для
контейнеров Linux или Windows.

Docker предоставляет Docker Desktop для Windows и macOS, позволяя размещать контейнеры в среде
разработки и использовать дополнительные средства разработки. Оба продукта устанавливают
необходимую виртуальную машину (узел Docker) для размещения контейнеров.

Для выполнения контейнеров Windows есть среды выполнения двух типов:

Контейнеры Windows Server изолируют приложение с помощью технологии изоляции процесса и


пространства имен. Контейнер Windows Server использует ядро совместно с узлом контейнеров и
всеми остальными контейнерами на узле.

Контейнеры Hyper-V увеличивают изоляцию, обеспеченную контейнерами Windows Server,


запуская каждый контейнер в оптимизированной виртуальной машине. В этой конфигурации ядро
узла контейнера не используется совместно с контейнерами Hyper-V, что улучшает изоляцию.

Образы для этих контейнеров создаются и работают одинаково. Различие заключается лишь в том, что
для создания контейнера из образа с контейнером Hyper-V нужен дополнительный параметр.
Дополнительные сведения см. в разделе Контейнеры Hyper-V.

Сравнение контейнеров Docker с виртуальными машинами


На рисунке 2-3 показано сравнение между виртуальными машинами и контейнерами Docker.

ВИРТУАЛЬНЫЕ МАШИНЫ КОНТЕЙНЕРЫ DO C K ER

Виртуальные машины содержат приложение, Контейнеры включают в себя приложение и все его
необходимые библиотеки или двоичные файлы и всю зависимости. Но они используют ядро ОС совместно с
операционную систему. Полная виртуализация требует другими контейнерами, которые выполняются в
больше ресурсов, чем создание контейнеров. изолированных процессах в пользовательском
пространстве операционной системы узла. (Это не
относится к контейнерам Hyper-V, где каждый
контейнер запускается на отдельной виртуальной
машине.)

Рис. 2-3 . Сравнение традиционных виртуальных машин с контейнерами Docker

Для виртуальных машин на сервере узла создается три базовых уровня: самый нижний
инфраструктурный слой; затем операционная система узла и низкоуровневая оболочка; и поверх этого
каждая виртуальная машина использует собственную ОС и все необходимые библиотеки. Для Docker
сервер узла предоставляет только инфраструктуру и операционную систему, а также ядро контейнеров,
которое изолирует контейнер с использованием базовых служб операционной системы.

Так как контейнеры требуют гораздо меньше ресурсов (например, им не нужна полная ОС ), их проще
развертывать и они быстрее запускаются. Это позволяет повысить плотность развертываний, то есть
запустить на одной единице оборудования больше служб и сократить затраты на них.

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

Основная цель образа — привести среду (зависимости) к единообразию в различных развертываниях.


Это означает , что вы можете отладить образ на одном компьютере, а затем развернуть его на другом
компьютере и получить ту же среду.

Образ контейнера — это способ упаковки приложения или службы для надежного и воспроизводимого
развертывания. Можно сказать, что Docker является не только технологией, но еще философией и
процессом.
При работе с Docker разработчики никогда не жалуются, что приложение работает только на локальном
компьютере, но не в рабочей среде. Им достаточно сказать "Выполняется в Docker", так как упакованное
приложение Docker будет выполняться в любой поддерживаемой среде Docker. Оно будет работать
одинаково во всех сценариях развертывания (разработка, контроль качества, промежуточное
размещение и рабочая среда).

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

Вернемся ненадолго назад во времени, в 1950-е годы. Тогда еще не было текстовых редакторов, и
повсеместно использовались фотокопировальные устройства (то есть то, что тогда так называлось).

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

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

Вы создали простую систему со следующим алгоритмом:

1. У вас есть пачка прозрачных листов, каждый из которых содержит один абзац.
2. Чтобы подготовить комплект писем, вы отбираете листы с нужными абзацами, собираете их в
стопку и выравниваете так, чтобы все правильно читалось.

3. Теперь вы помещаете готовый набор в фотокопировальное устройство и нажмите кнопку запуска,


чтобы изготовить нужное количество копий.

Это и есть основная концепция Docker в упрощенной форме.

В Docker каждый слой представляет некоторый набор изменений, которые применяются к файловой
системе после выполнения команды, такой как установка программы.

Если вы "посмотрите" на файловую систему после копирования очередного слоя, вы увидите все файлы в
том состоянии, которое они приняли после установки программы.

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

Соответственно, роль "компьютера" здесь выполняет контейнер, в который устанавливается жесткий


диск этого образа. Контейнер, как и обычный компьютер, можно включать и отключать.

НА ЗА Д ВПЕРЕД
Терминология Docker
02.11.2021 • 4 minutes to read

В этом разделе приводятся термины и определения, необходимые при работе с инструментом Docker. С
развернутыми определениями можно ознакомиться в глоссарии инструмента Docker.

Образ контейнера : пакет со всеми зависимостями и сведениями, необходимыми для создания


контейнера. Образ включает в себя все зависимости (например, платформы), а также конфигурацию
развертывания и выполнения для среды выполнения контейнера. Как правило, образ создается на основе
нескольких базовых образов, наслоенных друг на друга в файловой системе контейнера. После создания
образ остается неизменным.

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

Сборка : действие по созданию образа контейнера на основе сведений и контекста, предоставленных


файлом Dockerfile, а также дополнительных файлов в папке, где создается образ. Сборка образов
выполняется с помощью следующей команды Docker:

docker build

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

Тома : предложите файловую систему с возможностью записи, которую может использовать этот
контейнер. Поскольку образы доступны только для чтения, а большинству программ требуется
возможность записи в файловую систему, тома добавляют слой с поддержкой записи поверх образа
контейнера, который программы смогут использовать как файловую систему с возможностью записи.
Программа не знает , что она обращается к многоуровневой файловой системе. Для нее это обычный
вызов файловой системы. Тома размещаются в системе узла под управлением Docker.

Тег: метка для образа, которая позволяет различать разные образы или версии одного образа (в
зависимости от номера версии или целевой среды).

Многоэтапная сборка : этот компонент входит в Docker, начиная с версии 17.05, и позволяет сократить
итоговый размер образов. Если попытаться кратко описать эту функцию, многоэтапная сборка
позволяет использовать крупный базовый образ с пакетом SDK для компиляции и публикации
приложения, а затем создать итоговый образ намного меньшего размера с помощью небольшого
базового образа для среды выполнения, размещенного в папке публикации.

Репозиторий: коллекция связанных образов Docker, помеченная тегом, указывающим на версию образа.
Некоторые репозитории содержат несколько вариантов одного образа, например образ с пакетом
средств разработки (больший объем), образ только со средой выполнения (меньший объем) и т. д. Эти
варианты можно пометить тегами. Один репозиторий может содержать варианты платформ, например
образ Linux и образ Windows.

Реестр: служба, предоставляющая доступ к репозиториям. Реестр по умолчанию для большинства


общедоступных образов — Центр Docker (принадлежащий Docker как организации). Реестр обычно
содержит репозитории нескольких команд. Компании часто используют частные реестры для хранения
своих образов и управления ими. Еще один пример — реестр контейнеров Azure.

Мультиархитектурный образ: Для нескольких архитектур это функция, которая упрощает выбор
соответствующего образа в соответствии с платформой, в которой работает Docker. Например, когда
Dockerfile запрашивает базовый образ mcr.microsoft.com/dotnet/sdk :5.0 из реестра, фактически
возвращается 5.0-nanoser ver-1909 , 5.0-nanoser ver-1809 или 5.0-buster-slim (в зависимости от ОС и
версии среды, в которой работает Docker).

Центр Docker : общедоступный реестр для загрузки образов и работы с ними. Центр Docker
обеспечивает размещение образов Docker и интеграцию с GitHub и Bitbucket, предоставляет
общедоступные или частные реестры, триггеры сборки и веб-перехватчики.

Реестр контейнеров Azure : общедоступный ресурс для работы с образами Docker и их компонентами
в Azure. Он предоставляет реестр, близкий к вашим развертываниям в Azure, так что вы можете
контролировать доступ и использовать группы и разрешения в Azure Active Directory.

Доверенный реестр Docker (DTR) : служба реестра Docker (из Docker), которую можно установить
локально, чтобы она находилась в центре данных и сети организации. Его удобно использовать для
частных образов, которыми необходимо управлять внутри предприятия. Доверенный реестр Docker
входит в Центр данных Docker. Дополнительные сведения см. в разделе Доверенный реестр Docker (DTR).

Docker Community Edition (CE) : инструменты разработки в среде Windows и macOS для локальной
сборки, выполнения и тестирования контейнеров. Docker CE для Windows предоставляет среды
разработки для контейнеров Linux и Windows. Узел Linux Docker на Windows базируется на виртуальной
машине Hyper-V. Узел для контейнеров Windows базируется непосредственно на Windows. Docker CE для
Mac базируется на платформе Apple Hypervisor и гипервизоре xhyve, который предоставляет узлу Linux
Docker виртуальную машину в macOS X. Docker CE для Windows и для Mac заменил Docker Toolbox на базе
Oracle VirtualBox.
Docker Enterprise Edition (EE) : корпоративная версия инструментов Docker для разработки в среде
Windows и Linux.
Compose : программа командной строки и формат файлов YAML с метаданными для определения и
выполнения многоконтейнерных приложений. Вы определяете одно приложение на основе нескольких
образов с помощью одного или нескольких файлов .yml, которые могут изменять значения в зависимости
от среды. Создав определения, вы можете развернуть все многоконтейнерное приложение с помощью
одной команды (docker-compose up), которая создает один контейнер на образ на узле Docker.

Кластер: коллекция узлов Docker, представленная в виде единого виртуального узла Docker, чтобы
можно было масштабировать приложение в нескольких экземплярах служб, распределенных по
нескольким узлам кластера. Кластеры Docker можно создавать с помощью Kubernetes, Azure Service
Fabric, Docker Swarm и (или) Mesosphere DC/OS.
Оркестратор: инструмент , упрощающий управление кластерами и узлами Docker. С помощью
оркестраторов можно управлять образами, контейнерами и узлами через интерфейс командной строки
(CLI) или графический интерфейс. Вы можете управлять соединениями контейнеров, конфигурациями,
балансировкой нагрузки, обнаружением служб, высоким уровнем доступности, конфигурацией узлов
Docker и многим другим. Оркестратор используется для выполнения, распределения, масштабирования и
восстановления рабочих нагрузок в коллекции узлов. В качестве оркестраторов обычно используются те
же продукты, которые обеспечивают кластерную инфраструктуру, например Kubernetes и Azure Service
Fabric (на рынке доступны и другие предложения).
НА ЗА Д ВПЕРЕД
Контейнеры, образы и реестры Docker
02.11.2021 • 2 minutes to read

При использовании Docker разработчик создает приложение или службу и упаковывает приложение или
службу и их зависимости в образ контейнера. Образ — это статическое представление приложения или
службы, а также их конфигурации и зависимостей.

Для запуска приложения или службы создается экземпляр образа приложения, чтобы создать контейнер,
который будет запущен на узле Docker. Контейнеры изначально проверяются в среде разработки или на
ПК.

Разработчикам следует хранить образы в реестре, который выступает в качестве библиотеки образов и
необходим при развертывании на оркестраторы в рабочей среде. Docker поддерживает общедоступный
реестр с помощью Docker Hub. Другие поставщики предлагают реестры для различных коллекций
образов, включая Реестр контейнеров Azure. Кроме того, организации могут развернуть локальные
частные реестры для своих образов Docker.

На рисунке 2-4 показано, как образы и реестры в Docker связаны с другими компонентами. На нем также
показано несколько вариантов реестра от поставщиков.

Рис. 2-4 . Классификация основных понятий и терминов Docker

Реестр напоминает книжную полку. В нем хранятся образы, которые можно извлекать для создания
контейнеров, необходимых для запуска служб или веб-приложений. Частные реестры Docker могут
храниться в локальной среде или в общедоступном облаке. Docker Hub — это общедоступный реестр,
поддерживаемый Docker. Помимо решения Docker Trusted Registry корпоративного уровня можно
использовать Реестр контейнеров Azure, предлагаемый Azure. AWS, Google и другие компании также
предлагают свои реестры контейнеров.

Размещение образов в реестре позволяет хранить статические и неизменяемые фрагменты приложений,


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

Ваши образы не могут быть открыты для общего доступа по соображениям конфиденциальности.

Вам необходимо обеспечить минимальную сетевую задержку между образами и выбранной средой
развертывания. Например, если рабочая среда представляет собой облако Azure, вы, вероятно,
захотите разместить образы в Реестре контейнеров Azure, чтобы сетевая задержка была
минимальной. Точно так же, если рабочая среда является локальной, вы можете развернуть
локальный доверенный реестр Docker в той же локальной сети.

НА ЗА Д ВПЕРЕД
Выбор между .NET 5 и .NET Framework для
контейнеров Docker
02.11.2021 • 2 minutes to read

Серверные контейнерные приложения Docker можно разрабатывать на двух платформах .NET: .NET
Framework и .NET 5. В них используется множество одинаковых компонентов платформы .NET, а код
можно использовать как в одной среде, так и в другой. Но между этими двумя платформами также
существуют и фундаментальные различия. Поэтому ваш выбор будет зависеть от поставленной задачи.
В этом разделе приводятся рекомендации по выбору каждой из платформ.

НА ЗА Д ВПЕРЕД
Общие рекомендации
02.11.2021 • 2 minutes to read

В этом разделе представлена сводка относительно выбора .NET 5 или .NET Framework. Дополнительные
сведения об этих вариантах представлены в последующих разделах.

Используйте .NET 5 с контейнерами Windows или Linux для контейнерного серверного приложения
Docker в следующих случаях:
для создания кроссплатформенных решений; Например, вы хотите использовать контейнеры и
Windows, и Linux.
Архитектура приложения основана на микрослужбах.

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

Вкратце, при создании новых контейнерных приложений .NET следует рассматривать .NET 5 как вариант
по умолчанию. Он имеет множество преимуществ и лучше соответствует концепции и стилю работы с
контейнерами.

Дополнительное преимущество использования .NET 5 заключается в том, что можно параллельно


запускать версии .NET для приложений на одной и той же машине. Данное преимущество более важно
для серверов или виртуальных машин, которые не используют контейнеры, так как контейнеры
изолируют версии .NET, нужные приложению. (При условии, что они совместимы с базовой ОС.)

Используйте .NET Framework для серверных приложений в контейнерах Docker в следующих случаях.

В настоящее время приложение использует .NET Framework и имеет строгие зависимости от


Windows.
Необходимо использовать API Windows, которые не поддерживаются .NET 5.

Требуются сторонние библиотеки .NET или пакеты NuGet, недоступные для .NET 5.

Использование .NET Framework в Docker может улучшить качество развертывания, сводя к минимуму
проблемы развертывания. Данный сценарий "подъема и смены" важен для контейнеризации приложений
прежних версий, которые изначально были разработаны с использованием классической платформы
.NET Framework, например ASP.NET WebForms, веб-приложений MVC или служб WCF (Windows
Communication Foundation).
Дополнительные ресурсы
Электронная книга. модернизация существующих приложений .NET Framework с
помощью Azure и контейнеров Windows
https://aka.ms/liftandshiftwithcontainersebook
Примеры приложений: модернизация устаревших веб- приложений ASP.NET с
помощью контейнеров Windows
https://aka.ms/eshopmodernizing

НА ЗА Д ВПЕРЕД
Выбор .NET для контейнеров Docker
02.11.2021 • 3 minutes to read

Благодаря модульности и упрощенному характеру .NET 5 идеально подходит для контейнеров. При
развертывании и запуске контейнера размер его образа гораздо меньше в среде .NET 5. Напротив, при
использовании .NET Framework для контейнера необходимо использовать Windows Server Core в
качестве базового образа, который занимает гораздо больше места, чем образ Nano Windows Server или
Linux, которые используются для .NET 5.
Кроме того, платформа .NET 5 является кроссплатформенной, поэтому вы можете разворачивать
серверные приложения в Linux и Windows контейнерах. Однако при использовании традиционной
.NET Framework можно развернуть только образ, основанный на Windows Server Core.
Ниже более подробно описаны преимущества .NET 5.

Разработка и развертывание на различных платформах


Очевидно, что если ваша цель — приложение (веб-приложение или служба), которое можно запускать
на нескольких платформах, поддерживаемых в Docker (Linux и Windows), целесообразно выбрать .NET 5,
так как платформа .NET Framework поддерживает только Windows.

.NET 5 также поддерживает macOS в качестве платформы разработки. Тем не менее при развертывании
контейнеров на узле Docker этот узел должен (в настоящее время) базироваться на Windows или Linux.
Например, в среде разработки можно использовать виртуальную машину с Linux, запущенную на
компьютере с Mac.

Visual Studio предоставляет интегрированную среду разработки (IDE) для Windows и поддерживает
разработку с использованием Docker.

Visual Studio для Mac — это интегрированная среда разработки, которая является эволюцией Xamarin
Studio, выполняется в macOS и поддерживает разработку приложений на основе Docker. Этот инструмент
должен быть предпочтительным вариантом для разработчиков, которые работают на компьютерах с
Mac и хотят использовать мощную интегрированную среду разработки.
Редактор Visual Studio Code можно также использовать в macOS, Linux и Windows. Visual Studio Code
полностью поддерживает .NET 5, включая технологию IntelliSense и отладку. Так как VS Code является
упрощенным редактором, для разработки контейнерных приложений на компьютере его можно
использовать в сочетании с Docker CLI и .NET CLI. Для разработки на платформе .NET 5 также можно
использовать большинство сторонних редакторов, например Sublime, Emacs, vi и проект с открытым
кодом OmniSharp, который также поддерживает технологию IntelliSense.

Наряду с интегрированными средами разработки и редакторами для всех поддерживаемых платформ вы


можете использовать .NET CLI.

Использование контейнеров для новых ("с нуля") проектов


Контейнеры обычно используются в сочетании с архитектурой микрослужб, хотя их также можно
использовать для упаковки веб-приложений или служб, созданных на базе любого архитектурного
шаблона. Среду .NET Framework можно использовать для контейнеров Windows, но упрощенный
характер и модульный принцип среды .NET 5 делают ее оптимальной для контейнеров и архитектуры
микрослужб. При создании и развертывании контейнера размер его образа гораздо меньше в среде
.NET 5, чем в .NET Framework.
Создание и развертывание микрослужб в контейнерах
Традиционный .NET Framework можно использовать для создания приложений на основе микрослужб
(без контейнеров) с помощью простых процессов. Платформа .NET Framework уже установлена и
совместно используется процессами, поэтому в этом случае процессы небольшие по размеру и быстро
выполняются. Но при использовании контейнеров образы для традиционного .NET Framework основаны
на Windows Server Core, что делает их слишком большими для подхода "микрослужбы в контейнерах".
При этом командам требуются возможности сделать .NET Framework удобнее для пользователей.
Недавно размер образов контейнеров Windows Server Core уменьшился более чем на 40 %.

С другой стороны, .NET 5 благодаря упрощенному характеру является наилучшим выбором, если вы
используете ориентированную на микрослужбы систему, которая основана на контейнерах. Кроме того,
связанные с NET Core образы, как для Linux, так и для Windows Nano Server, являются компактными и
небольшими по размеру, что обеспечивает их быстрый запуск.

Термин "микрослужба" означает , что она должна быть настолько маленькой, насколько это возможно,
чтобы обеспечивать быстрое развертывание, занимать мало места в памяти (см. статью о проблемно-
ориентированном проектировании), решать небольшую часть задачи и быть способной к быстрому
запуску и остановке. Для выполнения этих требований необходимо использовать небольшой и быстро
создаваемый образ контейнера, такой как образ контейнера .NET 5.

Архитектура микрослужб также позволяет использовать сочетание технологий за пределами службы.


Благодаря этому возможна постепенная миграция на технологию .NET 5 новых служб, которые работают
совместно с другими микрослужбами или со службами, разработанными с помощью Node.js, Python, Java,
GoLang и других технологий.

Развертывание с высокой плотностью в масштабируемых


системах
Если для вашей системы, основанной на контейнерах, требуется максимально возможная плотность,
детализация и производительность, то мы рекомендуем использовать .NET и ASP.NET Core. Среда ASP.NET
Core в 10 раз быстрее, чем ASP.NET в традиционном .NET Framework, и поддерживает другие популярные
отраслевые технологии микрослужб, такие как сервлеты Java, Go и Node.js.

Это особенно важно для архитектур микрослужб, где могут выполняться сотни
микрослужб (контейнеров). Образы ASP.NET Core (основанные на среде выполнения .NET) на Windows
Nano или Linux позволяют запустить систему с гораздо меньшим количеством серверов или виртуальных
машин и, в конечном счете, снизить затраты на инфраструктуру и размещение.

НА ЗА Д ВПЕРЕД
Выбор .NET Framework для контейнеров Docker
02.11.2021 • 3 minutes to read

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

Перенос существующих приложений непосредственно в


контейнер Windows Server
Даже если вы не создаете микрослужбы, контейнеры Docker можно использовать для упрощения
развертывания. Например, вы хотите улучшить функционирование рабочего процесса DevOps с
помощью Docker. Использование контейнеров позволит вам получить хорошо изолированную тестовую
среду и устранить проблемы с развертыванием, вызванные отсутствием зависимостей при перемещении в
рабочую среду. В таких случаях даже при развертывании монолитных приложений имеет смысл
использовать Docker и контейнеры Windows для текущего приложения .NET Framework.

В большинстве случаев при таком сценарии перенос существующих приложений на .NET 5 не требуется.
Можно использовать контейнеры Docker, в которые включена традиционная платформа .NET Framework.
Тем не менее для расширения готовых приложений, например для разработки новой службы в ASP.NET
Core рекомендуется использовать .NET 5.

Использование сторонних библиотек .NET и пакетов NuGet,


недоступных для .NET 5
Сторонние библиотеки .NET Standard позволяют совместно использовать код в различных вариантах
приложения .NET, в том числе в .NET 5. С появлением .NET Standard 2.0 и более поздних версий,
совместимость области API с различными платформами стала значительно больше. Кроме того, .NET
Core 2.x и более новые приложения также могут ссылаться непосредственно на существующие
библиотеки .NET Framework (см. .NET Framework 4.6.1 supporting .NET Standard 2.0 (.NET Framework 4.6.1,
поддерживающие .NET Standard 2.0)).

Кроме того, пакет обеспечения совместимости Windows расширяет доступную для .NET Standard 2.0
область API-интерфейсов в Windows. Этот пакет позволяет почти без изменений перекомпилировать
существующий код под платформу .NET Standard версии 2.x, чтобы выполнять его в Windows.

Несмотря на значительный прогресс, достигнутый после выхода .NET Standard 2.0 и .NET Core 2.1 и более
поздних версий, некоторые пакеты NuGet пока запускаются только в ОС Windows и не поддерживают
.NET Core и более поздних версий. Если эти пакеты имеют важное значение для вашего приложения,
необходимо использовать .NET Framework в контейнерах Windows.

Использование технологий .NET, недоступных для .NET 5


Некоторые технологии .NET Framework отсутствуют в текущей версии .NET (версии 5.0 на момент
написания этой статьи). Поддержка некоторых из них может быть доступна в последующих выпусках,
однако остальные технологии не соответствуют новым шаблонам приложений, используемым в среде
.NET Core, и могут быть недоступными всегда.
В следующем списке указано большинство технологий, недоступных в .NET 5.

Веб-формы ASP.NET. Эта технология доступна только в .NET Framework. В настоящее время
добавление веб-форм ASP.NET в среду .NET и более поздних версий не планируется.

Службы WCF. Даже с клиентской библиотекой WCF, которая позволяет использовать службы WCF
из среды .NET 5, по состоянию на январь 2021 г. реализация сервера WCF доступна только для .NET
Framework.
Службы, связанные с рабочим процессом. Службы Windows Workflow Foundation (WF), Workflow
Services (WCF и WF в одной службе) и WCF Data Services (известные как службы данных ADO.NET)
доступны только в среде .NET Framework. В настоящий момент не планируется их перенос в .NET 5.

В дополнение к технологиям, перечисленным в официальном Плане по .NET, в новую унифицированную


платформу могут быть перенесены и другие функции. Вы можете принять участие в обсуждениях на
сайте GitHub и выразить свое мнение. Если вы думаете, что чего-то не хватает , отправьте новый вопрос
dotnet/runtime в репозитории GitHub.

Использование платформы или API, которые не поддерживают


.NET 5
Некоторые платформы Майкрософт и платформы сторонних поставщиков не поддерживают среду
.NET 5. Например, некоторые другие службы Azure предоставляют пакеты SDK, которые пока невозможно
использовать в среде .NET 5. В конечном итоге, большинство пакетов SDK Azure будут перенесены в
.NET 5 или Standard, но некоторые из них могут не перенестись по разным причинам. Доступные пакеты
SDK для Azure можно просмотреть на странице Azure SDK Latest Releases (Последние выпуски пакета SDK
Azure).
В течение этого переходного периода, если окажется, что какая-либо платформа или служба в Azure
пока еще не поддерживает среду .NET 5 с ее клиентским API, вы можете использовать аналогичный
интерфейс REST API службы Azure или пакет SDK для клиента на платформе .NET Framework.

Дополнительные ресурсы
Документация по .NET
https://docs.microsoft.com/dotnet/fundamentals
Перенос проектов в .NET 5
https://channel9.msdn.com/Events/dotnetConf/2020/Porting-Projects-to-NET-5
Инструкции по использованию .NET в Docker
https://docs.microsoft.com/dotnet/core/docker/introduction
Общие сведения о компонентах .NET
https://docs.microsoft.com/dotnet/standard/components

НА ЗА Д ВПЕРЕД
Таблица для принятия решений. Использование
платформ .NET для Docker
02.11.2021 • 2 minutes to read

В таблице ниже для принятия решений приводятся сводные сведения о том, когда следует использовать
.NET Framework или .NET 5. Помните, что для контейнеров Linux требуются узлы Docker на основе Linux
(виртуальные машины или серверы), а для контейнеров Windows — узлы Docker на основе Windows
Server (виртуальные машины или серверы).

IMPORTANT
На компьютерах разработки выполняется один узел Docker: Linux или Windows. Все связанные микрослужбы,
которые должны запускаться и тестироваться вместе в рамках одного решения, должны выполняться на одной
платформе контейнеров.

АРХИТЕКТУРА И ТИП ПРИЛОЖЕНИЯ КОНТЕЙНЕРЫ L IN UX КОНТЕЙНЕРЫ W IN DO W S

Микрослужбы в контейнерах .NET 5 .NET 5

Монолитные приложения .NET 5 .NET Framework


.NET 5

Достижение высочайшей .NET 5 .NET 5


производительности и
масштабируемости

Перенос имеющихся (устаревших ) -- .NET Framework


приложений Windows Server в
контейнеры

Разработка новых приложений на .NET 5 .NET 5


основе контейнеров (с нуля)

ASP.NET Core .NET 5 .NET 5 (рекомендуется)


.NET Framework

ASP.NET 4 (MVC 5, веб-API 2 и веб- -- .NET Framework


формы)

Службы SignalR .NET Core 2.1 или более поздней .NET Framework
версии .NET Core 2.1 или более поздней
версии

WCF, WF и другие устаревшие WCF в .NET Core (только клиентская .NET Framework
платформы библиотека) WCF в .NET 5 (только клиентская
библиотека)
АРХИТЕКТУРА И ТИП ПРИЛОЖЕНИЯ КОНТЕЙНЕРЫ L IN UX КОНТЕЙНЕРЫ W IN DO W S

Использование служб Azure .NET 5 .NET Framework


(в конечном итоге большинство .NET 5
служб Azure будет предоставлять (в конечном итоге большинство
клиентские пакеты SDK для .NET 5) служб Azure будет предоставлять
клиентские пакеты SDK для .NET 5)

НА ЗА Д ВПЕРЕД
Для какой ОС использовать контейнеры .NET
02.11.2021 • 2 minutes to read

Учитывая разнообразие операционных систем, поддерживаемых Docker, и различия между .NET


Framework и .NET 5, следует выбирать определенные ОС и определенные версии в зависимости от
платформы, которую вы используете.

Для Windows можно использовать Windows Server Core или Windows Nano Server. Эти версии Windows
предоставляют разные особенности (IIS в Windows Server Core или резидентный веб-сервер, такой как
Kestrel, в Nano Server), которые могут быть необходимы в .NET Framework или .NET 5 соответственно.
Для Linux доступно и поддерживается множество дистрибутивов в официальных образах Docker .NET
(например, Debian).
На рисунке 3-1 представлены возможные версии операционной системы в зависимости от используемой
платформы .NET.

Рис. 3-1 . Выбираемые операционные системы в зависимости от версии платформы .NET

При развертывании устаревших приложений .NET Framework выберите в качестве целевой ОС Windows
Server Core, которая совместима с устаревшими приложениями и службами IIS, но образ которой имеет
больший размер. При развертывании приложений .NET 5 в качестве целевой ОС можно выбрать Windows
Nano Server, которая оптимизирована для облака, использует Kestrel, имеет образ меньшого размера и
запускается быстрее. В качестве целевой среды можно выбрать ОС Linux, которая поддерживает Debian,
Alpine и другие дистрибутивы. Можете также использовать образ Kestrel, который имеет меньший размер
и запускается быстрее.

В том случае, если требуется использовать другой дистрибутив Linux или если нужен образ с версиями,
не предоставляемыми Майкрософт , можно также создать собственный образ Docker. Например, можно
создать образ с ASP.NET Core для работы на классической платформе .NET Framework и в Windows Server
Core, что для Docker является довольно редко используемым сценарием.
При добавлении имени образа в файл Dockerfile можно выбрать операционную систему и версию в
зависимости от используемого тега, как показано в следующих примерах:

ИЗОБРАЖЕНИЕ КОММЕНТАРИИ

mcr.microsoft.com/dotnet/runtime:5.0 .NET 5 (несколько архитектур): поддерживает Linux и


Windows Nano Server в зависимости от узла Docker.

mcr.microsoft.com/dotnet/aspnet:5.0 ASP.NET Core 5.0 (несколько архитектур): поддерживает


Linux и Windows Nano Server в зависимости от узла
Docker.
Образ aspnetcore имеет несколько оптимизаций для
ASP.NET Core.

mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim .NET 5(только для среды выполнения) на основе


дистрибутива Linux Debian

mcr.microsoft.com/dotnet/aspnet:5.0-nanoserver-1809 .NET 5 (только для среды выполнения) на основе


Windows Nano Server (Windows Server версии 1809)

НА ЗА Д ВПЕРЕД
Официальные .NET-образы Docker
02.11.2021 • 2 minutes to read

Официальные .NET-образы Docker — это образы Docker, оптимизированные Майкрософт. Они доступны
для всех в репозиториях Майкрософт в Центре Docker. Каждый репозиторий может содержать несколько
образов, в зависимости от версии платформы .NET и операционной системы (Linux Debian, Linux Alpine,
Windows Nano Server, Windows Server Core и т. д.).
Начиная с версии .NET Core 2.1, все образы .NET Core или более поздней версии, в том числе для ASP.NET
Core, можно найти в репозитории образов .NET на сайте Docker Hub: https://hub.docker.com/_/microsoft-
dotnet/.
Начиная с мая 2018 г., образы Майкрософт объединяются в реестре контейнеров Майкрософт .
Официальный каталог по-прежнему доступен только в центре Docker, и здесь можно найти обновленный
адрес для извлечения образа.

Большинство репозиториев образов предоставляют широкие возможности по использованию тегов,


чтобы облегчить выбор не только конкретной версии платформы, но и ОС (дистрибутива Linux или
версии Windows).

Оптимизация образов .NET и Docker для разработки и рабочей


среды
При создании образов Docker для разработчиков Майкрософт сосредотачивается на следующих
основных сценариях:

образы, используемые для разработки и сборки приложений .NET;

образы, используемые для запуска приложений .NET.

Зачем использовать несколько образов? При разработке, сборке и выполнении приложений в


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

Во время разработки и сборки


Во время разработки важна скорость выполнения итераций для изменений и возможность отлаживать
изменения. Размер образа не так важен, как возможность быстро вносить изменения в код и
просматривать их. Некоторые средства и "контейнеры агентов сборки" на стадии разработки и сборки
используют образ .NET для разработки (mcr.microsoft.com/dotnet/sdk:5.0). При сборке внутри контейнера
Docker надо учитывать, какие элементы необходимы для компиляции приложения. Сюда входят
зависимости компилятора и другие зависимости .NET.

Почему так важен этот тип образа сборки? Этот образ не развертывается в рабочую среду. Это образ,
который вы используете для сборки содержимого, помещаемого в рабочий образ. Если вы используете
многоэтапную сборку Docker, этот образ будет применяться в среде непрерывной интеграции (CI) или в
среде сборки.

Производство
При производстве важно быстро развернуть и запустить контейнеры на основе рабочего образа .NET.
Поэтому образ только для среды выполнения на базе mcr.microsoft.com/dotnet/aspnet:5.0 имеет малый
размер и может быстро перемещаться по сети из реестра Docker к узлам Docker. Содержимое готово к
запуску, поэтому период времени от запуска контейнера до обработки результатов минимален. В модели
Docker не нужна компиляция кода C#, поскольку вы выполняете команду dotnet build или dotnet publish
при использовании контейнера сборки.

В этот оптимизированный образ вы помещаете только двоичные файлы и другое содержимое,


необходимое для выполнения приложения. Например, в содержимое, создаваемое командой
dotnet publish , входят только скомпилированные двоичные файлы .NET, образы, файлы .js и .css. Со
временем появятся образы, которые содержат пакеты, предварительно скомпилированные JIT-
компилятором (компиляция из промежуточного языка в машинный код во время выполнения).

Хотя существует несколько версий образов .NET и ASP.NET Core, они все имеют один или несколько
общих уровней, включая базовый уровень. Поэтому образ занимает мало места на диске, ведь он
содержит лишь различия между вашим образом и базовым образом. В результате можно быстро
извлекать образы из реестра.

При просмотре репозиториев .NET-образов в центре Docker вы найдете несколько версий,


классифицированных или помеченных тегами. Эти теги помогают определить, какую версию
использовать, как показано в таблице:

ОБРАЗ — КОММЕНТАРИИ

mcr.microsoft.com/dotnet/aspnet:5.0 ASP.NET Core только со средой выполнения и


оптимизацией ASP.NET Core в Linux и Windows (для
разных архитектур)

mcr.microsoft.com/dotnet/sdk:5.0 .NET 5 с пакетами SDK в Linux и Windows (для разных


архитектур)

НА ЗА Д ВПЕРЕД
Проектирование архитектуры приложений на
основе контейнеров и микрослужб
02.11.2021 • 2 minutes to read

Микрослужбы дают большие преимущества, но в то же время создают новые проблемы. Шаблоны


архитектуры микрослужб являются основополагающим элементом при создании приложения на основе
микрослужб.
Ранее в этом руководстве вы ознакомились с основными понятиями, связанными с контейнерами и Docker.
Это минимальная информация, требуемая для начала работы с контейнерами. Даже несмотря на то, что
контейнеры необходимы для использования микрослужб и отлично подходят для них, они не являются
обязательными для архитектуры микрослужб. Многие архитектурные концепции, описанные в этом
разделе, можно применять без контейнеров. Однако в данном руководстве основное внимание уделяется
совместному использованию обоих вариантов из-за уже упоминавшейся важности контейнеров.

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

Принципы проектирования контейнеров


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

Когда вы проектируете образ контейнера, в Dockerfile отображается определение ENTRYPOINT. С его


помощью определяется процесс, время существования которого контролирует время существования
контейнера. По завершении процесса время существования контейнера истекает. Контейнеры могут
представлять как длительные процессы, например веб-серверы, так и кратковременные, например
пакетные задания, которые ранее могли реализовываться как веб-задания Azure.

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

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

НА ЗА Д ВПЕРЕД
Контейнеризация монолитных приложений
02.11.2021 • 4 minutes to read

Вы можете создать одно монолитное веб-приложение или службу и развернуть их как контейнер. Само
приложение может не иметь монолитную внутреннюю структуру и состоять из нескольких библиотек,
компонентов или даже уровней (прикладной уровень, уровень домена, уровень доступа к данным и т. д.).
Но внешне оно будет представлять собой единый контейнер — единый процесс, единое веб-приложение
или единую службу.

Для управления этой моделью вы развертываете один контейнер, представляющий собой приложение.
Чтобы увеличить емкость, вы используете горизонтальное масштабирование, то есть просто добавляете
больше копий с подсистемой балансировки нагрузки спереди. Управлять одним развертыванием в одном
контейнере или виртуальной машине гораздо проще.

Рис. 4-1 . Пример архитектуры монолитного приложения в контейнере

Вы можете включить в один контейнер несколько компонентов, библиотек или внутренних уровней, как
показано на рисунке 4-1. Монолитное контейнерное приложение содержит большую часть
функциональности в одном контейнере с внутренними слоями или библиотеками и горизонтально
масштабируется путем клонирования контейнера на нескольких серверах или виртуальных машинах.
Такой монолитный шаблон может конфликтовать с принципом контейнера: "контейнер выполняет одно
дело и в одном процессе", — но в некоторых случаях это не проблема.

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

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

Существует несколько способов масштабирования приложения — горизонтальное копирование,


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

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


такое приложение проще, чем использовать микрослужбы. Поэтому такой архитектурный подход
используется во многих организациях. И хотя некоторым удалось достичь достаточно хороших
результатов, другие сталкиваются с серьезными ограничениями. Во многих организациях приложения
строились по такой модели, поскольку несколько лет назад с помощью существующих инструментов и
инфраструктуры слишком сложно было создавать архитектуры, ориентированные на службы (SOA), и
проблем не возникало, пока приложение не начинало разрастаться.

С точки зрения инфраструктуры, каждый сервер может выполнять множество приложений в одном узле
и применять допустимое соотношение эффективности использования ресурсов, как показано на рисунке
4-2.

Рис. 4-2 . Монолитная конструкция: узел выполняет несколько приложений, каждое приложение
выполняется как контейнер

Монолитные приложения в Microsoft Azure можно развертывать с использованием выделенных


виртуальных машин для каждого экземпляра. Кроме того, с помощью масштабируемых наборов
виртуальных машин Azure можно легко масштабировать виртуальные машины. Служба приложений
Azure также может выполнять монолитные приложения и легко масштабировать экземпляры, и вам не
придется управлять виртуальными машинами. С 2016 года службы приложений Azure также могут
выполнять отдельные экземпляры контейнеров Docker, упрощая развертывание.

В качестве среды контроля качества или ограниченной рабочей среды можно развертывать несколько
виртуальных машин с Docker и распределять нагрузку с помощью средства балансировки Azure, как
показано на рисунке 4-3. Так вы сможете управлять масштабированием, не используя крупные элементы,
поскольку все приложение размещено в одном контейнере.

Рис. 4-3 . Пример масштабирования приложения в одном контейнере с помощью нескольких узлов

Развертыванием на различных узлах можно управлять с помощью традиционных методов


развертывания. Узлами Docker можно управлять с помощью вводимых вручную команд docker run или
docker-compose или автоматизированно , например с помощью конвейеров непрерывной поставки (CD).

Развертывание монолитного приложения в контейнере


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

Развертывание обновлений в виде образов Docker выполняется гораздо быстрее и эффективнее с точки
зрения использования сети. Образы Docker обычно запускаются за считанные секунды, что позволяет
ускорить выпуск. Остановить образ Docker можно с помощью команды docker stop , и обычно это
происходит моментально.

Поскольку контейнеры неизменны по своей природе, вам не придется беспокоиться о поврежденных


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

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

Публикация приложения в одном контейнере в службе


приложений Azure
Когда вы хотите проверить контейнер, развернутый в Azure, или когда приложение содержится в одном
контейнере, вы можете воспользоваться удобными службами масштабирования контейнеров в службе
приложений Azure. Использовать службу приложений Azure очень просто. Она прекрасно интегрируется
с Git, так что вы можете взять свой код, скомпилировать его в Visual Studio и развернуть прямо в Azure.

Рис. 4-4 . Публикация приложения в одном контейнере в Службе приложений Azure из Visual Studio 2019

Если вам понадобятся другие возможности, платформы или зависимости, не поддерживаемые службой
приложений Azure, без Docker пришлось бы ждать, пока команда Azure обновит эти зависимости в
службе приложений. Или пришлось бы переключиться на другие службы, например Облачные службы
Azure, или даже виртуальные машины, где у вас было бы больше возможностей и можно было бы
установить необходимый компонент или платформу для приложения.

Благодаря поддержке контейнеров в Visual Studio 2017 и более поздних версий вы можете включать в
среду приложения любые компоненты, как показано на рисунке 4-4. Поскольку приложение выполняется
в контейнере, при добавлении зависимости можно включить ее в Dockerfile или образ Docker.

На рисунке 4-4 также показано, что поток публикации отправляет образ через реестр контейнеров. Это
может быть реестр контейнеров Azure (реестр, близкий к вашим развертываниям в Azure и защищенный
группами и учетными записями в Azure Active Directory) или другой реестр Docker, например центр Docker
или локальный реестр.

НА ЗА Д ВПЕРЕД
Управление состоянием и данными в
приложениях Docker
02.11.2021 • 4 minutes to read

Представьте себе контейнер как экземпляр процесса. Процесс не находится в неизменном состоянии. И
хотя контейнер может записывать данные в локальное хранилище, предполагать, что экземпляр всегда
будет на месте — это все равно, что надеяться на постоянство одной ячейки памяти. Вы должны
предполагать, что образы контейнеров, как и процессы, имеют несколько экземпляров или конечном
итоге будут удалены. Если для управления ими используется оркестратор контейнеров, следует
предполагать, что они могут перемещаться из одного узла (или виртуальной машины) в другой.

Для управления данными в приложениях Docker используются следующие решения:

Из узла Docker в качестве томов Docker:

Тома хранятся в той части файловой системы узла, которая находится под управлением Docker.

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

Подключения tmpfs аналогичны виртуальным папкам, которые существуют только в памяти


узла и никогда не записываются в файловую систему.

Из удаленного хранилища:

Служба хранилища Azure, предоставляющая геораспределенное хранилище для долгосрочного


хранения данных контейнеров.

Удаленные реляционные базы данных, например базы данных SQL Azure или базы данных NoSQL,
такие как Azure Cosmos DB, или службы кэша, такие как Redis.

Из контейнера Docker:

Оверлейная файловая система . Эта функция Docker выполняет копирование при записи, при
котором обновленная информация сохраняется в корневой файловой системе контейнера. Эта
информация "накладывается" на изначальный образ, на котором базируется контейнер. Если удалить
контейнер из системы, эти изменения будут утеряны. Поэтому, хоть и возможно сохранить состояние
контейнера в его локальном хранилище, создание системы по такой модели будет противоречить
конструкции контейнера, состояние которого по умолчанию не отслеживается.

Тем не менее сейчас тома Docker являются предпочтительным способом обработки локальных данных в
Docker. Если вам требуются дополнительные сведения о хранении в контейнерах, ознакомьтесь с
разделами Docker storage drivers (Драйверы хранилища Docker) и About storage drivers (Основные
сведения о драйверах хранилища).

Ниже подробно описаны эти варианты.

Тома — это каталоги из ОС узла, сопоставленные с каталогами в контейнерах. Если код в контейнере
имеет доступ к каталогу, на самом деле он обращается к каталогу на ОС узла. Этот каталог не привязан к
времени существования самого контейнера, находится под управлением Docker и изолирован от
основных функциональных возможностей хост -компьютера. Поэтому тома данных хранят данные
независимо от контейнера. Если удалить контейнер или образ из узла Docker, данные из томов данных не
будут удалены.

Тома могут быть именованными или анонимными (по умолчанию). Именованные тома — это следующий
этап развития контейнеров томов данных. Они упрощают обмен данными между контейнерами.
Тома также поддерживают драйверы томов, позволяющие хранить данные на удаленных узлах и т. д.

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

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

Как показано на рисунке 4-5, обычные тома Docker могут храниться за пределами самих контейнерами,
но в физических границах сервера узла или виртуальной машины. Тем не менее контейнеры Docker с
одного сервера узла или виртуальной машины не могут обращаться к тому на другом сервере узла или
виртуальной машине. Другими словами, с помощью этих томов невозможно управлять данными
контейнеров, которые выполняются на разных узлах Docker, хотя такой режим работы можно
реализовать с помощью драйвера томов, который поддерживает удаленные узлы.

Рис. 4-5 . Тома и внешние источники данных для приложений на основе контейнера

Тома могут совместно использоваться несколькими контейнерами, но только на одном узле, если вы не
используете удаленный драйвер с поддержкой удаленных узлов. Кроме того, когда контейнеры Docker
управляются оркестратором, контейнеры могут "перемещаться" между узлами в рамках оптимизации,
выполняемой кластером. Поэтому тома данных не рекомендуется использовать для бизнес-данных. Но
это хороший инструмент для работы с файлами трассировки, временными файлами или подобными
элементами, которые не влияют на целостность бизнес-данных.

Удаленные источники данных и инструменты кэширования, такие как база данных Azure SQL,
Azure Cosmos DB или служба кэша, например Redis, можно использовать в упакованных в контейнеры
приложениях так же, как они используются при разработке без контейнеров. Это проверенный способ
хранения данных бизнес-приложений.

Служба хранилища Azure Бизнес-данные, как правило, необходимо хранить во внешних ресурсах или
базах данных, например в службе хранилища Azure. Служба хранилища Azure предоставляет следующие
службы в облаке:

Хранилище BLOB-объектов хранит объекты с неструктурированными данными. Большой двоичный


объект может представлять собой текстовые или двоичные данные любого типа, например
документ или файл мультимедиа (файлы с изображением, аудио и видео). Хранилище BLOB-
объектов иногда также называют хранилищем объектов.

Хранилище файлов обеспечивает хранение приложений прежних версий по стандартному


протоколу SMB. Виртуальные машины Azure и облачные службы могут совместно использовать
данные файлов в компонентах приложений через подключенный общий ресурс. Локальные
приложения могут обращаться к данным файлов в общем ресурсе через файловую службу REST
API.
Табличное хранилище содержит структурированные наборы данных. Хранилище таблиц — это
хранилище данных NoSQL типа "ключ-значение", обеспечивающее быструю разработку и доступ к
большим объемам данных.

Реляционные базы данных и базы данных NoSQL. Существует множество вариантов внешних баз
данных — от реляционных, таких как SQL Server, PostgreSQL и Oracle, до баз данных NoSQL, например
Azure Cosmos DB, MongoDB и т д. Такие базы являются отдельной темой и не рассматриваются в этом
руководстве.

НА ЗА Д ВПЕРЕД
Сервисноориентированная архитектура
02.11.2021 • 2 minutes to read

Термин "сервисноориентированная архитектура" (SOA) перегружен значениями и для разных людей


означает разные понятия. Но в качестве общего знаменателя термин SOA подразумевает
структурирование приложения путем разделения его на несколько служб (наиболее часто HTTP-службы),
которые можно классифицировать различными способами, например как подсистемы или уровни.

Теперь эти службы можно развернуть как контейнеры Docker, которые помогают решать проблемы
развертывания, так как в образ контейнера включены все зависимости. Однако, если вы используете
отдельные узлы Docker, то при необходимости масштабирования приложений SOA вы столкнетесь с
проблемами масштабируемости и доступности. Именно для решения таких проблем предназначено
программное обеспечение для кластеризации Docker, или оркестратор, которое описано в следующих
разделах, где мы расскажем о способах развертывания микрослужб.

Контейнеры Docker являются полезным (но необязательным) элементом как для традиционных
архитектур, ориентированных на службы, так и более сложных архитектур с микрослужбами.

Микрослужбы являются производными от архитектуры SOA, но эти архитектуры отличаются друг от


друга. Для архитектуры SOA являются типичными такие компоненты, как большие центральные брокеры
и центральные оркестраторы на уровне организации, а также сервисная шина предприятия (ESB). Но для
архитектуры микрослужб в большинстве случаев они являются признаком дурного тона. Некоторые
специалисты даже утверждают , что "архитектура микрослужб — это правильно реализованная
архитектура SOA".

Это руководство посвящено описанию микрослужб, поскольку подход SOA менее требователен по
сравнению с требованиями и техниками архитектуры микрослужб. Если вы знаете, как создать
приложение на основе технологии микрослужб, то вы сможете создать и простое
сервисноориентированное приложение.

НА ЗА Д ВПЕРЕД
Архитектура микрослужб
02.11.2021 • 2 minutes to read

Само название предполагает , что архитектура микрослужб является подходом к созданию серверного
приложения как набора малых служб, Это означает , что архитектура микрослужб главным образом
ориентирована на серверную часть, несмотря на то, что этот подход также используется для внешнего
интерфейса. где каждая служба выполняется в своем процессе и взаимодействует с остальными
службами по таким протоколам, как HTTP/HTTPS, WebSockets или AMQP. Каждая микрослужба реализует
специфические возможности в предметной области и свою бизнес-логику в рамках определенного
ограниченного контекста, должна разрабатываться автономно и развертываться независимо. Наконец, у
каждой микрослужбы должны быть соответствующие собственные модель данных и логика предметной
области (владение и децентрализованное управление данными); для каждой микрослужбы могут
применяться разные технологии хранилищ (SQL, NoSQL) и разные языки программирования.

Каково размера должна быть микрослужба? При разработке микрослужбы размер не должен быть
важным фактором. Главным должно быть создание слабо связанных служб, что позволяет добавиться
автономности при разработке, развертывании и масштабировании каждой службы. Конечно же, при
определении и проектировании микрослужб следует стремиться к тому, чтобы они были как можно
меньше, если только они не имеют слишком много прямых зависимостей от других микрослужб.
Внутренняя связанность микрослужбы и ее независимость от других служб важнее ее размера.

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

Дополнительное преимущество в том, что микрослужбы можно масштабировать независимо. Вместо


монолитного приложения, которое нужно масштабировать как единое целое, вы масштабируете
отдельные микрослужбы. Тем самым можно масштабировать только функциональную область,
требующую больше вычислительных или сетевых ресурсов, не затрагивая другие области приложения,
которые на самом деле не нуждаются в масштабировании. Таким образом можно сократить расходы, так
как требуется меньше оборудования.
Рис. 4-6 . Монолитное развертывание в сравнении с подходом на основе микрослужб

Как показано на рис. 4-6, в традиционном монолитном подходе приложение масштабируется путем
клонирования всего приложения на несколько серверов или виртуальных машин. В подходе с
использованием микрослужб функциональные возможности изолируются в небольших службах, и
каждую службу можно масштабировать независимо от других. Подход на основе микрослужб нацелен на
гибкость изменений и ускорение последовательных улучшений каждой микрослужбы, так как вы
получаете возможность изменять небольшие части крупных, комплексных и масштабируемых
приложений.

Архитектура приложений на основе микрослужб позволяет применять принципы непрерывной


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

Ниже перечислены важные аспекты успешного ввода системы на основе микрослужб в эксплуатацию:

мониторинг и проверки работоспособности служб и инфраструктуры;

масштабируемая инфраструктура служб (то есть облако и оркестраторы);

проектирование и реализация безопасности на разных уровнях: проверка подлинности,


авторизация, управление секретами, безопасный обмен данными и т. д.;

быстрая поставка приложения, причем разными микрослужбами обычно занимаются разные


команды;

методики и инфраструктура DevOps и непрерывной интеграции и поставки.

Из этих аспектов только первые три рассматриваются в данном руководстве. Последние два, связанные с
жизненным циклом приложения, описываются в дополнительной электронной книге Жизненный цикл
контейнерного приложения Docker на основе платформы и средств Майкрософт .

Дополнительные ресурсы
Марк Руссинович (Mark Russinovich). Микрослужбы: революция в сфере приложений,
движимая облачными технологиями
https://azure.microsoft.com/blog/microservices-an-application-revolution-powered-by-the-cloud/
Мартин Фоулер (Mar tin Fowler). Микрослужбы
https://www.martinfowler.com/articles/microservices.html
Мартин Фоулер (Mar tin Fowler). Требования для микрослужб
https://martinfowler.com/bliki/MicroservicePrerequisites.html
Джимми Нилссон (Jimmy Nilsson). Фрагментирование облачных вычислений
https://www.infoq.com/articles/CCC-Jimmy-Nilsson
Сезар де ла Торре (Cesar de la Torre). Жизненный цикл контейнерного приложения
Docker на основе платформы и средств Майкрософт (электронная книга, доступная для
скачивания) https://aka.ms/dockerlifecycleebook

НА ЗА Д ВПЕРЕД
Владение данными в каждой микрослужбе
02.11.2021 • 4 minutes to read

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

Это означает , что концептуальная модель предметной области будет различаться для разных подсистем
и микрослужб. Для примера можно взять корпоративное приложение, в котором каждая из подсистем
управления отношениями с клиентами (CRM), финансовых транзакций и поддержки клиентов
обращается к уникальным атрибутам и данным сущностей и использует собственный ограниченный
контекст.

Аналогичный принцип принят в проблемно-ориентированном проектировании (DDD), в котором каждый


ограниченный контекст либо автономная подсистема или служба должны быть владельцем своей
модели предметной области (состоящей из данных и логики или поведения). Каждый ограниченный
контекст DDD сопоставлен с одной бизнес-микрослужбой (одной или несколькими службами). Более
подробно о шаблоне ограниченного контекста мы поговорим в следующем разделе.

С другой стороны, традиционный подход (на основе единых данных), применяемый во многих
приложениях, предполагает наличие одной централизованной базы данных или небольшого количества
баз данных. Часто это нормализованная база данных SQL, которая используется для всего приложения и
всех его внутренних подсистем, как показано на рис. 4-7.

Рис. 4-7 . Сравнение владения данными: единая база данных и микрослужбы

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

Монолитное приложение, обычно с одной реляционной базой данных, имеет два важных преимущества:
транзакции, обладающие свойствами атомарности, согласованности, изолированности и долговечности,
и язык SQL. Оба этих преимущества распространяются на все таблицы и данные, связанные с
приложением. Такой подход позволяет легко писать запросы, объединяющие данные из нескольких
таблиц.

Но при переходе на архитектуру микрослужб получать доступ к данным становится сложнее. Даже при
использовании транзакций ACID в микрослужбах или ограниченном контексте важно учитывать, что
данные, принадлежащие каждой микрослужбе, являются частными для этой микрослужбы и должны
быть доступны только синхронно через соответствующие конечные точки API (gRPC, SOAP и т. д.) или
асинхронно через систему обмена сообщениями (AMQP и т. д.).

Инкапсуляция данных делает микрослужбы слабосвязанными, благодаря чему они могут изменяться
независимо друг от друга. Если бы несколько служб обращались к одним и тем же данным, изменения
схемы требовали бы согласованного изменения всех служб. При этом автономность жизненного цикла
микрослужб нарушалась бы. Однако распределенные структуры данных означают невозможность
выполнения транзакции, обладающей свойствами атомарности, согласованности, изолированности и
долговечности, в рамках нескольких микрослужб. Из этого, в свою очередь, следует , что если бизнес-
процесс охватывает несколько микрослужб, необходимо обеспечивать итоговую согласованность. Это
гораздо сложнее в реализации, чем простые соединения SQL, поскольку невозможно создать
ограничения целостности или использовать распределенные транзакции между отдельными базами
данных, как мы объясним позднее. Аналогичным образом многие другие возможности реляционных баз
данных недоступны в рамках нескольких микрослужб.

Если разбираться дальше, микрослужбы часто используют базы данных разных типов. Современные
приложения хранят и обрабатывают разнообразные типы данных, и реляционная база данных — не
всегда лучший выбор. В некоторых ситуациях база данных NoSQL, например Azure CosmosDB или
MongoDB, может иметь более удобную модель данных и обеспечивать более высокую
производительность и масштабируемость по сравнению с базой данных SQL, например SQL Server или
базой данных SQL Azure. В других случаях реляционная база данных по-прежнему является оптимальным
решением. По этой причине в приложениях на основе микрослужб часто используется сочетание баз
данных SQL и NoSQL. Такой подход иногда называют разнородным хранением данных.

Секционированная архитектура разнородного хранения данных имеет много преимуществ. К ним


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

Связь между микрослужбами и шаблоном ограниченного


контекста
Концепция микрослужбы является производной от шаблона ограниченного контекста в проблемно-
ориентированном проектировании (DDD). В DDD большие модели разделяются на несколько
ограниченных контекстов с явно определенными границами между ними. Каждый ограниченный
контекст должен иметь собственную модель и базу данных, так же как каждая микрослужба является
владельцем связанных с ней данных. Кроме того, каждый ограниченный контекст обычно имеет
собственный единый язык, упрощающий взаимодействие между разработчиками ПО и экспертами в
предметных областях.
Термины единого языка (в основном это сущности предметной области) могут иметь разные имена в
разных ограниченных контекстах, даже если разные сущности предметной области имеют одинаковый
уникальный идентификатор (по которому сущность считывается из хранилища). Например, в
ограниченном контексте профиля пользователя сущность предметной области "Пользователь" может
иметь тот же идентификатор, что и сущность предметной области "Покупатель" в ограниченном
контексте размещения заказов.

Таким образом, микрослужба похожа на ограниченный контекст , но она также определена как
распределенная служба. Она создается как отдельный процесс для каждого ограниченного контекста и
должна использовать упомянутые ранее распределенные протоколы, такие как HTTP/HTTPS, WebSockets
или AMQP. В свою очередь, шаблон ограниченного контекста не указывает , является ли ограниченный
контекст распределенной службой или просто логической границей (например, подсистемой общего
назначения) в пределах монолитного приложения.

Важно отметить, что сначала желательно определить службу для каждого ограниченного контекста.
Однако проектирование необязательно ограничивать этим. Иногда следует спроектировать
ограниченный контекст или бизнес-микрослужбу, которые состоят из нескольких физических служб. Но,
в конечном счете, оба шаблона (ограниченный контекст и микрослужба) тесно связны друг с другом.

В DDD преимущества микрослужб реализуются путем определения реальных границ в форме


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

Дополнительные ресурсы
Крис Ричардсон (Chris Richardson). Шаблон: база данных для каждой службы
https://microservices.io/patterns/data/database-per-service.html
Мартин Фоулер (Mar tin Fowler). BoundedContext
https://martinfowler.com/bliki/BoundedContext.html
Мартин Фоулер (Mar tin Fowler). PolyglotPersistence
https://martinfowler.com/bliki/PolyglotPersistence.html
Альберто Брандолини (Alber to Brandolini). Стратегическое предметно-
ориентированное проектирование с сопоставлением контекста
https://www.infoq.com/articles/ddd-contextmapping

НА ЗА Д ВПЕРЕД
Логическая и физическая архитектура
02.11.2021 • 2 minutes to read

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

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

Кроме того, даже несмотря на то, что микрослужба может быть физически реализована как отдельная
служба, процесс или контейнер (для простоты именно такой подход был выбран в первоначальной
версии приложения eShopOnContainers), подобное соответствие бизнес-микрослужбы и физической
службы или контейнера не всегда является обязательным, особенно при разработке больших и сложных
приложений, состоящих из десятков и даже сотен служб.

Именно в этом проявляется различие между логической и физической архитектурами приложения.


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

Возможно, вы уже выделили определенные микрослужбы или ограниченные контексты, но это не значит ,
что оптимальный способ их реализации всегда состоит в создании отдельной службы (например, веб-API
ASP.NET) или отдельного контейнера Docker для каждой микрослужбы. Правило, гласящее, что каждая
микрослужба должна реализовываться как отдельная служба или контейнер, является слишком строгим.

Таким образом, бизнес-микрослужба или ограниченный контекст — это компонент логической


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

Как показано на рис. 4-8, микрослужба каталога может состоять из нескольких служб или процессов. Это
может быть несколько служб на основе веб-интерфейсов API ASP.NET или любых других служб,
использующих протокол HTTP либо иной протокол. Более того, эти службы могут использовать одни и
те же данные при условии, что они связаны с одной предметной областью.

Рис. 4-8 . Бизнес-микрослужба с несколькими физическими службами

Службы в примере имеют общую модель данных, так как служба на основе веб-интерфейса API
обращается к тем же данным, что и служба поиска. Поэтому в физической реализации микрослужбы вы
разделяете эту функциональность, чтобы каждую из внутренних служб можно было масштабировать по
мере необходимости. Например, для службы на основе веб-интерфейса API обычно может требоваться
больше экземпляров, чем для службы поиска, или наоборот.

Короче говоря, логическая архитектура микрослужб не всегда должна совпадать с архитектурой


физического развертывания. Каждый раз, когда в этом руководстве упоминается микрослужба, имеется в
виду бизнес-микрослужба или логическая микрослужба, которой могут соответствовать одна или
несколько (физических) служб. В большинстве случаев это будет одна служба, но их может быть и
больше.

НА ЗА Д ВПЕРЕД
Распределенное управление данными: проблемы
и решения
02.11.2021 • 8 minutes to read

Проблема #1. Как определить границы каждой микрослужбы


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

Во-первых, необходимо сосредоточиться на логических моделях предметных областей приложения и


связанных данных. Попробуйте выделить группы данных и различные контексты в одном приложении.
Каждый контекст должен иметь свой бизнес-язык (свои бизнес-термины). Контексты должны
определяться и управляться независимо друг от друга. Термины и объекты, используемые в этих
контекстах, могут звучать похоже, но вы увидите, что в одном контексте концепция используется не так,
как в другом, и даже может иметь другое название. Например, пользователь может называться
пользователем в контексте идентификации или членства, клиентом — в контексте управления
клиентами, покупателем — в контексте заказов и т. д.

Как вы определяете границы между контекстами приложения с отдельной предметной областью для
каждого контекста, так же вы определяете границы каждой микрослужбы, ее модель предметной
области и данные. Всегда старайтесь свести к минимуму взаимозависимость между этими
микрослужбами. Далее в главе Определение границ модели предметной области для каждой
микрослужбы будет подробно рассматриваться это разграничение и проектирование модели
предметной области.

Проблема #2. Как создавать запросы для извлечения данных из


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

Шлюз API . Для простого объединения данных из нескольких микрослужб с разными базами данных
рекомендуется использовать микрослужбу агрегирования — шлюз API. Будьте осторожны при
применении этого шаблона, поскольку он может стать слабым местом вашей системы и нарушить
принцип автономности микрослужб. Чтобы смягчить негативные последствия, используйте несколько
мелких шлюзов API для различных вертикальных срезов или областей системы. Шаблон шлюза API более
подробно описан в разделе Использование шлюза API ниже.

CQRS с таблицами запросов/ чтения. Еще одно решение для объединения данных из нескольких
микрослужб — шаблон материализованного представления. При таком подходе вы заранее создаете
(готовите денормализованные данные до фактической отправки запросов) таблицу, доступную только
для чтения, с данными, принадлежащими нескольким микрослужбам. Таблица имеет формат ,
соответствующий потребностям клиентского приложения.
Представьте себе экран мобильного приложения. Если у вас одна база данных, вы можете собрать
данные для этого экрана с помощью SQL-запроса, выполняющего сложное соединение с использованием
нескольких таблиц. Но если у вас несколько баз данных и каждая база данных принадлежит отдельной
микрослужбе, невозможно отправить в них запрос и создать соединение SQL. Такой сложный запрос
становится проблемой. Эту проблему можно решить с помощью подхода CQRS — создайте
денормализованную таблицу в другой базе данных, которая используется только для запросов. Таблица
может предназначаться специально для данных, необходимых в этом сложном запросе, и между полями,
необходимыми для экрана приложения, и столбцами в таблице запроса может существовать отношение
один к одному. Такой метод также можно использовать для составления отчетов.

Этот подход позволяет не только решить изначальную проблему (как отправлять запросы в несколько
микрослужб), но и значительно повысить производительность по сравнению с использованием сложных
соединений, поскольку у вас уже есть все необходимые приложению данные в таблице запроса. Конечно,
если вы используете принцип разделения ответственности на команды и запросы (Command and Query
Responsibility Segregation, CQRS) с таблицами запросов/чтения, придется проделать дополнительную
работу и проследить за итоговой согласованностью. Тем не менее мы рекомендуем применять принцип
CQRS с несколькими базами данных там, где существуют особые требования к производительности и
масштабируемости в ситуации совместной работы (или соперничества, это как посмотреть).

" Холодные данные " в центральных базах данных. Для составления сложных отчетов и
выполнения запросов, не требующих немедленного ответа, рекомендуется экспортировать "горячие
данные" (данные о транзакциях из микрослужб) как "холодные данные" в большие базы данных,
использующиеся только для отчетности. Система центральной базы данных может основываться на
больших данных, например Hadoop, представлять собой хранилище данных, например на базе
хранилища данных Azure SQL, или являться просто базой данных SQL, использующейся только для
отчетов (если размер не имеет значения).

Имейте в виду, что эта централизованная база данных будет использоваться только для запросов и
отчетов, которым не требуются данные в режиме реального времени. Исходные обновления и
транзакции в качестве источника истины должны храниться в данных микрослужб. Синхронизируйте
данные при наступлении событий (как описано в следующих разделах) или через инструменты импорта и
экспорта инфраструктуры другой базы данных. Если вы используете управление событиями, процесс
интеграции будет схож с методом распространения данных, описанным в разделе о таблицах запросов
по принципу CQRS.

Но если в приложении требуется непрерывное агрегирование сведений из нескольких микрослужб для


выполнения сложных запросов, это может быть признаком плохой структуры — микрослужбы должны
быть максимально изолированы друг от друга. (Мы не учитываем отчеты и аналитику, которые всегда
должны использовать центральные базы данных с "холодными данными".) Если такая проблема
возникает , возможно, следует объединить микрослужбы. Попробуйте найти баланс между
автономностью развития и развертывания каждой микрослужбы и прочными зависимостями,
слаженностью и агрегированием данных.

Проблема #3. Как добиться согласованности нескольких


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

Чтобы проанализировать эту проблему, рассмотрим пример из примера приложения eShopOnContainers.


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

В гипотетической монолитной версии этого приложения при изменении цены в таблице "Товары"
подсистема каталога может просто использовать транзакцию ACID, чтобы обновить текущую цену в
таблице "Корзина".

Однако в приложении на базе микрослужб таблицы "Товар" и "Корзина" находятся в соответствующих


микрослужбах. Микрослужбы никогда не должны включать таблицы или хранилища других микрослужб
в свои транзакции, и в том числе в прямые запросы, как показано на рис. 4-9.

Рис. 4-9 . Микрослужба не может обратиться к таблице другой микрослужбы напрямую

Микрослужба каталога не должна напрямую изменять таблицу "Корзина", поскольку эта таблица
принадлежит микрослужбе корзины. Чтобы обновить сведения в микрослужбе корзины, микрослужба
каталога может использовать только итоговую согласованность, возможно на основе асинхронной связи,
например событий интеграции (взаимодействие на основе сообщений и событий). Вот как такая итоговая
согласованность микрослужб выполняется в примере приложения eShopOnContainers.

Как гласит теорема CAP, вы должны выбирать между доступностью и согласованностью данных по
принципу ACID. В большинстве случаев при использовании микрослужб доступность и масштабируемость
имеют приоритет над строгой согласованностью. Критически важные приложения должны непрерывно
работать, и разработчики могут решить проблему строгой согласованности, используя методы работы со
слабой или итоговой согласованностью. Такой подход используется в большинстве архитектур на базе
микрослужб.

Кроме того, транзакции в стиле ACID или с двухфазной фиксацией не просто противоречат принципам
микрослужб — большинство баз данных NoSQL (например, Azure Cosmos DB, MongoDB и т. д.) не
поддерживают транзакции с двухфазной фиксацией, типичные для сценариев распространенных баз
данных. Согласованность данных в разных службах и базах данных все же имеет большое значение. Эта
проблема также связана с вопросом распространения изменений в нескольких микрослужбах, когда
некоторые данные должны быть избыточными — например, когда название или описание товара
должно присутствовать в микрослужбе каталога и в микрослужбе корзины.

Хорошим решением этой проблемы может стать использование итоговой согласованности между
микрослужбами, выраженной в управляемом событиями взаимодействии и системе публикации и
подписки. Эти темы обсуждаются в разделе Асинхронное взаимодействие, управляемое событиями.

Проблема #4. Как создать взаимодействие через границы


микрослужб
Взаимодействие через границы микрослужб является настоящей проблемой. В этом контексте
взаимодействие не подразумевает выбор протокола (HTTP и REST, AMQP, обмен сообщениями и так
далее). Нужно подумать, какой стиль следует использовать и, особенно, насколько микрослужбы должны
зависеть друг от друга. В случае сбоя его последствия для системы будут определяться степенью этой
взаимозависимости.

В распределенной системе, например в приложении на базе микрослужб, где существует множество


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

Чаще всего используются службы на базе HTTP (REST), поскольку они очень простые. Использовать HTTP
можно. Но как именно? Если вы используете запросы и ответы HTTP только для взаимодействия между
микрослужбами и клиентскими приложениями или шлюзами API, это нормально. Но если вы создаете
длинные цепочки синхронных HTTP-вызовов для взаимодействия через границы микрослужб, как если бы
микрослужбы были объектами в монолитном приложении, в конце концов в приложении возникнут
проблемы.

Представьте, что клиентское приложение делает вызов HTTP API к отдельной микрослужбе, например
микрослужбе заказов. Если микрослужба заказов, в свою очередь, вызывает дополнительные
микрослужбы по протоколу HTTP в рамках одного цикла запросов и ответов, вы создадите цепочку HTTP-
вызовов. Поначалу это может казаться разумным. Но при таком подходе следует учитывать несколько
важных аспектов:

Блокировка и низкая производительность. Поскольку HTTP-запросы синхронные по своей природе,


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

Взаимозависимость микрослужб и HTTP. Микрослужбы для бизнеса не следует объединять друг с


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

Сбой в одной микрослужбе. Если вы создали цепочку микрослужб, соединенную HTTP-вызовами,


при сбое одной микрослужбы (а сбой неизбежен) вся цепочка перестанет работать. Система на
базе микрослужб должна максимально сохранять работоспособность в случае частичных сбоев.
Даже если вы применяете логику, которая использует повторные попытки с экспоненциальной
задержкой или механизмы размыкания цепи, чем сложнее цепочки HTTP-вызовов, тем сложнее
применить стратегию обработки сбоев на базе HTTP.

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

Поэтому, чтобы повысить автономность и устойчивость микрослужб, следует как можно реже
использовать цепочки запросов и ответов для взаимодействия между микрослужбами. Рекомендуется
использовать только асинхронное взаимодействие для связи между микрослужбами — асинхронное
взаимодействие, управляемое сообщениями и событиями, или (асинхронные) HTTP-опросы независимо от
изначального цикла HTTP-запросов и ответов.

Более подробно асинхронное взаимодействие описывается в разделах Асинхронная интеграция


микрослужб в целях автономности и Асинхронное взаимодействие на базе сообщений.

Дополнительные ресурсы
Теорема CAP
https://en.wikipedia.org/wiki/CAP_theorem
Итоговая согласованность
https://en.wikipedia.org/wiki/Eventual_consistency
Основные сведения о согласованности данных
https://docs.microsoft.com/previous-versions/msp-n-p/dn589800(v=pandp.10)
Мартин Фоулер (Mar tin Fowler). CQRS ( разделение обязанностей запросов и команд )
https://martinfowler.com/bliki/CQRS.html
Материализованное представление
https://docs.microsoft.com/azure/architecture/patterns/materialized-view
Чарльз Роу (Charles Row). ACID и BASE: изменение pH- показателя обработки
транзакций в базах данных
https://www.dataversity.net/acid-vs-base-the-shifting-ph-of-database-transaction-processing/
Компенсирующие транзакции
https://docs.microsoft.com/azure/architecture/patterns/compensating-transaction
Уди Дахан (Udi Dahan). Объединение на основе служб
https://udidahan.com/2014/07/30/service-oriented-composition-with-video/

НА ЗА Д ВПЕРЕД
Определение границ модели предметной
области для каждой микрослужбы
02.11.2021 • 5 minutes to read

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

Сэм Ньюмен, признанный специалист по микрослужбам и автор книги Создание микросервисов,


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

Модель предметной области с определенными сущностями применяется в рамках конкретного


ограниченного контекста или микрослужбы. Ограниченный контекст разграничивает применение
модели предметной области и дает разработчикам четкое представление о слаженности и возможности
независимой разработки отдельных элементов. Такие же цели преследуются для микрослужб.

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

Для определения ограниченных контекстов можно использовать шаблон DDD под названием Шаблон
сопоставления контекстов. Сопоставляя контексты, вы определяете различные контексты в приложении
и их границы. Как правило, существуют различные контексты и границы для каждой небольшой
подсистемы. При сопоставлении контекстов становятся очевидными границы между предметными
областями. Ограниченный контекст автономен и включает в себя элементы только одной предметной
области, например сущности, а также определяет схему интеграции с другими ограниченными
контекстами. Этим он похож на микрослужбу: она автономна, реализует определенные возможности
предметной области и обеспечивает интерфейсы. Поэтому сопоставление контекстов и ограниченные
контексты помогают определить границы модели предметной области для ваших микрослужб.

При разработке крупного приложения вы увидите, как можно разделить его предметную область.
Например, специалист по области каталога будет называть сущности в каталоге не так, как специалист
по области доставки. Или сущность предметной области пользователя может отличаться по размеру и
количеству атрибутов у специалиста по взаимодействию с клиентами, который хочет хранить все
сведения о клиенте, и у специалиста по заказам, которому нужны лишь некоторые данные о клиенте.
Очень трудно устранить неоднозначность всех терминов предметной области во всех областях в
крупном приложении. Но суть в том, что вам и не следует унифицировать термины. Просто примите
различия и многообразие каждой предметной области. Если вы попытаетесь создать единую базу
данных для всего приложения, это будет непросто, и унифицированный словарь не устроит
специалистов по разным областям. Поэтому ограниченные контексты (реализованные как микрослужбы)
помогут понять, где можно использовать термины определенной предметной области и где следует
разделить систему и создать дополнительные ограниченные контексты с другими предметными
областями.

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

При выборе размера модели предметной области для каждой микрослужбы руководствуйтесь
следующим принципом: у вас должен быть автономный и максимально изолированный ограниченный
контекст , с которым можно работать без постоянного обращения к другим контекстам (другим моделям
микрослужб). На рис. 4-10 показано, как несколько микрослужб (несколько ограниченных контекстов)
могут иметь собственную модель и как их сущности могут быть определены в зависимости от
конкретных требований для каждой предметной области в вашем приложении.

Рис. 4-10 . Определение сущностей и границ модели микрослужбы

На рисунке 4-10 показан пример сценария, относящийся к системе управления сетевыми конференциями.
Та же сущность отображается как "Пользователи", "Покупатели", "Плательщики" и "Клиенты" в
зависимости от ограниченного контекста. Вы определяете несколько ограниченных контекстов, которые
можно реализовать как микрослужбы, опираясь на предметные области, выбранные специалистами по
этим областям. Как видите, некоторые сущности представлены только в одной модели микрослужбы,
например "Платежи" в микрослужбе оплаты. Это будет легко реализовать.

Но некоторые сущности могут иметь разные формы и один идентификатор в различных моделях
предметных областей в различных микрослужбах. Например, сущность "Пользователь" определена в
микрослужбе управления конференциями. Тот же пользователь и с тем же идентификатором называется
"Покупатель" в микрослужбе заказов, "Плательщик" в микрослужбе платежей и "Клиент " в микрослужбе
клиентской службы. Дело в том, что каждый специалист в предметной области использует единый язык,
по-своему воспринимает пользователя и приписывает ему разные атрибуты. Сущность пользователя в
модели микрослужбы для управления конференциями содержит его персональные данные. Но эти
атрибуты могут не понадобиться этому же пользователю в роли плательщика в микрослужбе оплаты
или в роли клиента в микрослужбе клиентской службы.

Подобный подход проиллюстрирован на рис. 4-11.


Рис. 4-11 . Разбиение традиционных моделей данных на несколько моделей предметной области

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

Сущность "Рабочее место" имеет одно название, но разные атрибуты в каждой модели предметной
области. Однако у сущности "Рабочее место" везде одинаковый идентификатор, как у "Пользователя" и
"Покупателя".
По сути, существует общее понятие пользователя в различных службах (предметных областях), где он
имеет один и тот же идентификатор. Но в каждой модели предметной области указаны разные сведения
о сущности пользователя. Поэтому нужен способ сопоставления сущности пользователя в разных
предметных областях (или микрослужбах).

Отказ от использования одной сущности пользователя с одинаковым набором атрибутов в разных


предметных областях имеет свои преимущества. Одно из них — устранение дублирования. Таким
образом, модели микрослужб не будут хранить данные, которые им не нужны. Еще одно
преимущество — наличие главной микрослужбы, которая отвечает за определенный тип данных
сущности, чтобы обновления и запросы по этому типу данных управлялись только этой микрослужбой.

НА ЗА Д ВПЕРЕД
Сравнение шаблона шлюза API с прямым
взаимодействием клиента и микрослужбы
02.11.2021 • 13 minutes to read

В архитектуре микрослужб каждая микрослужба обычно предоставляет набор специализированных


конечных точек. Этот факт может повлиять на взаимодействие между клиентом и микрослужбой, как
описано в этом разделе.

Прямое взаимодействие между клиентом и микрослужбой


Возможный подход — использование архитектуры с прямым взаимодействием между клиентом и
микрослужбой. При таком подходе клиентские приложения могут отправлять запросы к некоторым
микрослужбам напрямую, как показано на рис. 4-12.

Рис. 4-12 . Использование архитектуры с прямым взаимодействием клиента и микрослужбы

При таком подходе у каждой микрослужбы есть общедоступная конечная точка, иногда с отдельным
портом TCP для каждой микрослужбы. Например, определенная служба может иметь следующий URL-
адрес в Azure:

http://eshoponcontainers.westus.cloudapp.azure.com:88/

В рабочей среде на основе кластера этот URL-адрес будет указывать на подсистему балансировки
нагрузки кластера, которая, в свою очередь, распределяет запросы между микрослужбами. В
производственной среде можно использовать контроллер доставки приложений, например шлюз
приложения Azure между вашими микрослужбами и Интернетом. Данный слой выступает как
прозрачный уровень, который не только выполняет балансировку нагрузки, но и защищает службы
благодаря завершению SSL-запросов. Это уменьшает нагрузку на узлах за счет разгрузки завершения
SSL-запросов и других задач, активно использующих ЦП, в шлюз приложений Azure. В любом случае
подсистема балансировки нагрузки и контроллер доставки приложений прозрачны с точки зрения
логической архитектуры приложения.
Архитектура прямого взаимодействия клиента и микрослужбы достаточно хорошо подходит для
небольших приложений на основе микрослужб, особенно если клиентское приложение представляет
собой веб-приложение на стороне сервера, например приложение MVC ASP.NET. Однако при создании
больших и сложных приложений на основе микрослужб (например, при обработке десятков типов
микрослужб) и особенно в том случае, если клиентские приложения представляют собой удаленные
мобильные приложения или одностраничные веб-приложения, этот подход приводит к появлению
нескольких проблем.

При разработке крупного приложения на основе микрослужб ответьте на следующие вопросы:

Как клиентские приложения могут свести к минимуму число запросов к серверной части и уменьшить
частоту обмена данными с несколькими микрослужбами?

Взаимодействие с несколькими микрослужбами для создания одного окна пользовательского


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

Как вы можете обрабатывать сквозную функциональность, например проверку подлинности,


преобразование данных и динамическую диспетчеризацию запросов?

Реализация вопросов безопасности и сквозной функциональности, например реализация безопасности и


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

Как клиентские приложения взаимодействуют со службами, использующими не поддерживаемые в


Интернете протоколы?

Протоколы, используемые на стороне сервера (например, AMQP или двоичные протоколы), не


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

Как создать интерфейс, специально предназначенный для мобильных приложений?

API нескольких микрослужб может быть не слишком хорошо приспособлено для удовлетворения
потребностей различных клиентских приложений. Например, потребности мобильного приложения
могут отличаться от потребностей веб-приложения. Для мобильных приложений может потребоваться
дополнительная оптимизация, чтобы повысить эффективность данных ответов. Это можно сделать,
агрегировав данные из нескольких микрослужб и возвращая один набор данных. Также иногда можно
исключить из ответа все данные, которые не требуются мобильному приложению. И, конечно же, эти
данные можно сжать. Опять же, можно предусмотреть удобный интерфейс или API между
микрослужбами и мобильным приложением для этого сценария.

Преимущества шлюза API над прямым взаимодействием клиента


и микрослужбы
В архитектуре микрослужб клиентские приложения обычно используют функциональные возможности
нескольких микрослужб. Если такое взаимодействие выполняется напрямую, клиенту нужно
обрабатывать несколько вызовов к конечным точкам микрослужб. Чем же это закончится, если развитие
приложения будет сопровождаться добавлением новых микрослужб или обновлением существующих?
Если приложение использует много микрослужб, взаимодействие с большим количеством конечных
точек становится для клиентского приложения сущим кошмаром. Так как клиентское приложение тесно
связано с внутренними конечными точками, любые изменения микрослужб могут существенно повлиять
на клиентские приложения.

Это означает , что промежуточный слой или уровень для косвенного обращения (шлюз) будет полезен в
приложениях на основе микрослужб. Если у вас нет шлюзов API, клиентские приложения должны
отправлять запросы непосредственно к микрослужбам, что может вызывать описанные ниже проблемы.

Взаимозависимость. Без шлюза API клиентские приложения тесно связаны с внутренними


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

Большое количество круговых путей. Для одной страницы (экрана) в клиентском


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

Проблемы безопасности. Без шлюза все микрослужбы будут доступны извне, что значительно
увеличивает уязвимую зону, если не скрыть внутренние микрослужбы, не используемые
клиентскими приложениями напрямую. Чем меньше уязвимая зона, тем надежнее будет ваше
приложение.

Проблемы сквозной функциональности. Каждая общедоступная микрослужба должна


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

Что представляет собой шаблон шлюза API?


При проектировании и разработке крупных или сложных приложений на основе микрослужб с
несколькими клиентскими приложениями рекомендуется использовать шлюз API. Это служба,
предоставляющая единую точку входа для определенных групп микрослужб. Она похожа на шаблон
фасада из объектно-ориентированного проектирования, но в этом случае включается в распределенную
систему. Шаблон шлюза API также иногда называют "серверной частью для клиентской части" (BFF), так
как она создается с учетом потребностей клиентского приложения.

Таким образом, шлюз API располагается между клиентскими приложениями и микрослужбами. Он


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

На рисунке 4-13 показано, как пользовательский шлюз API можно использовать в упрощенной
архитектуре на основе микрослужб, которая включает всего несколько микрослужб.
Рис. 4-13 . Использование шлюза API, реализованного в виде пользовательской службы

Приложения подключаются к одной конечной точке — шлюзу API, который настроен для пересылки
запросов в отдельные микрослужбы. В этом примере шлюз API будет реализован в виде
пользовательской службы ASP.NET Core WebHost, запущенной в виде контейнера.

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

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

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


использовать в качестве единого агрегатора для всех внутренних микрослужб.

При разделении уровня шлюза API на несколько шлюзов API, если приложение включает несколько
клиентских приложений, это разделение можно использовать в качестве основы для описания типов
шлюзов API, то есть разработать индивидуальный фасад для каждого клиентского приложения. Такую
схему иногда называют "Серверная часть для клиентской части" (BFF). Каждый шлюз API может
предоставлять различные API с учетом каждого типа клиентского приложения (а возможно, и форм-
фактора), на основе реализации кода адаптера, который вызывает несколько внутренних микрослужб,
как показано ниже.
Рис. 4-13.1. Использование нескольких пользовательских шлюзов API

На рис. 4-13.1 показаны шлюзы API, разделенные по типу клиента: для мобильных клиентов и для веб-
клиентов. Традиционное веб-приложение подключается к микрослужбе MVC, использующей шлюз веб-
API. В примере показана упрощенная архитектура с несколькими детально настроенными шлюзами API. В
этом примере границы для разделения шлюзов API строго основаны на шаблоне "Серверная часть для
клиентской части" (BFF), то есть шлюзы реализуют только те API, которые нужны конкретному
клиентскому приложению. Но в более крупных приложениях следует пойти немного дальше и
использовать границы бизнес-процессов в качестве второго фактора разделения шлюзов API.

Основные возможности шаблона шлюза API


Шлюз API может предоставлять множество функций. В зависимости от конкретного продукта, его
возможности могут быть простыми или достаточно широкими, но в любом шлюзе API основными следует
считать следующие шаблоны разработки:

Обратный прокси- сервер или маршрутизация шлюза . Шлюз API предоставляет обратный прокси-
сервер для маршрутизации или перенаправления запросов (маршрутизация уровня 7, обычно это HTTP-
запросы) к конечным точкам внутренних микрослужб. Шлюз предоставляет единую конечную точку
(URL-адрес) для клиентских приложений, а внутри сопоставляет запросы от них с конкретными группами
внутренних микрослужб. Эта возможность маршрутизации помогает отделить клиентские приложения
от микрослужб, но она не менее удобна при обновлении монолитного API. Между этим монолитным API и
клиентскими приложениями размещается шлюз API, что позволяет добавлять новые API в формате
микрослужб и продолжать использовать монолитный API вплоть до его разделения на множество
микрослужб. Благодаря шлюзу API для клиентских приложений неважно, как реализованы конкретные
API-интерфейсы: в виде внутренних микрослужб или монолитных API. И что более важно, в процессе
развития, рефакторинга и разделения монолитного API на микрослужбы шлюз API защищает клиентские
приложения от любых изменений URI.

Дополнительные сведения см. в разделе о шаблоне маршрутизации шлюза.

Агрегирование запросов. Шаблон шлюза можно дополнить агрегированием нескольких клиентских


запросов (обычно HTTP-запросов), направленных к разным внутренним микрослужбам, в один
клиентский запрос. Этот шаблон особенно удобен, когда клиенту для отображения страницы или экрана
нужны данные из нескольких микрослужб. При таком подходе клиентское приложение отправляет на
шлюз API один запрос, а шлюз преобразует его в несколько запросов к внутренним микрослужбам, затем
объединяет полученные результаты и отправляет в клиентское приложение. Основное преимущество и
цель этого шаблона разработки заключается в уменьшении объема данных, передаваемых между
клиентскими приложениями и внутренними API. Это особенно важно для удаленных приложений,
размещаемых за пределами центра обработки данных, где расположены микрослужбы, например для
мобильных приложений или запросов от приложений SPA, созданных на JavaScript в браузерах на
удаленном клиентском компьютере. Для обычных веб-приложений, которые выполняют запросы в
серверной среде (например, веб-приложение ASP.NET Core MVC), этот шаблон менее полезен, так как
сетевая задержка и так намного меньше, чем у удаленных клиентских приложений.

В зависимости от того, какой продукт вы используете в качестве шлюза API, он может поддерживать или
не поддерживать агрегирование. Но во многих случаях более гибким подходом будет создание
микрослужб агрегирования в пределах шлюза API, и тогда ее нужно выполнять в отдельном коде (то есть
в коде C#).

Дополнительные сведения см. в разделе о шаблоне агрегирования на шлюзе.

Проблемы сквозной функциональности или разгрузка шлюза . В зависимости от функций,


предоставляемых конкретной реализацией шлюза API, вы можете перенести некоторые функции из
отдельных микрослужб на шлюз, что упростит реализацию каждой микрослужбы за счет объединения
сквозных функций на отдельном уровне. Это особенно удобно для специализированных функций,
которые иногда сложно правильно реализовать в каждой внутренней микрослужбе. К этой категории
относятся следующие функции:

Аутентификация и авторизация
интеграция средства обнаружения служб;
Кэширование откликов
политики повторных попыток, размыкатель цепи и качество обслуживания;
ограничение скорости и регулирование;
балансировка нагрузки;
ведение журнала, трассировка, корреляция;
преобразования заголовков, строк запроса и утверждений;
Добавление IP-адресов в список разрешений

Дополнительные сведения см. в разделе о шаблоне разгрузки шлюза.

Использование продуктов с функциями шлюза API


В зависимости от конкретной реализации шлюз API может поддерживать еще множество сквозных
функций. Здесь рассматриваются следующие темы:

Управление API Azure


Ocelot
Управление API Azure
Служба управления API Azure (как показано на рис. 4-14) не только позволяет удовлетворить
потребности шлюза API, но и предоставляет дополнительные функции, например сбор аналитических
данных от интерфейсов API. Если вы используете решение для управления API, шлюз API является только
компонентом в рамках полного решения по управлению API.
Рис. 4-14 . Использование управления API Azure для шлюза API

Служба управления API Azure удовлетворяет ваши потребности в отношении шлюза API и управления,
такие как ведение журнала, обеспечение безопасности, контроль использования и т. д. В этом случае при
использовании такого продукта, как управление API Azure, наличие одного шлюза API не так рискованно,
так как такие виды шлюзов API "тоньше". Это означает , что вы не сможете реализовать пользовательский
код C#, который сможет развиваться в сторону монолитного компонента.

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

Аналитические сведения, доступные из системы управления API, помогут вам понять, как используются
ваши API и насколько эффективно они работают. Для этого вы можете просматривать отчеты
практически в режиме реального времени и выявлять тенденции, которые могут повлиять на ваш бизнес.
Кроме того, вы можете вести журналы запросов и ответов как для интерактивного, так и для
автономного анализа.

С помощью управления API Azure вы можете защитить свои интерфейсы API с помощью ключей,
маркеров и фильтрации IP-адресов. Эти возможности позволяют обеспечить гибкие и точные квоты и
ограничения скорости, изменить форму и поведение ваших API с помощью политик и улучшить
производительность с помощью кэширования ответов.

В этом руководстве и в примере приложения (eShopOnContainers) архитектура ограничивается простой


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

Ocelot
Ocelot — это упрощенный шлюз API, рекомендуемый для более простых случаев. Шлюз API Ocelot с
открытым кодом на основе .NET Core специально разработан для архитектуры микрослужб, в которой
нужны единые точки входа в систему. Он не требует большого количества ресурсов, быстро работает ,
легко масштабируется, а также наряду с многими другими функциями поддерживает маршрутизацию и
проверку подлинности.

Ocelot используется в примере приложения eShopOnContainers 2.0 в первую очередь потому, что этот
простой шлюз API на основе .NET Core можно развернуть в той же среде развертывания приложений, где
размещаются микрослужбы и контейнеры, такие как узел Docker, Kubernetes и т. д. Так как этот шлюз
основан на .NET Core, он одинаково хорошо работает на платформах Windows или Linux.

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

Кроме него, существует много других продуктов с функциональностью шлюза API, например Apigee,
Kong, MuleSoft, WSO2. Также есть много продуктов, например Linkerd и Istio, реализующих функции
управления входящими данными.

После разделов с описанием базовой архитектуры и шаблонов мы переходим к описанию реализации


шлюза API на примере Ocelot.

Недостатки шаблона шлюза API


Наиболее важный недостаток заключается в том, что при реализации шлюза API вы связываете
этот уровень с внутренними микрослужбами. Такое связывание может привести к серьезным
проблемам для вашего приложения. Клеменс Вастер (Clemens Vaster), архитектор команды по
разработке служебной шины Azure, называет эту потенциальную трудность "новой служебной
шиной предприятия (ESB)" в выступлении Messaging and Microservices (Обмен сообщениями и
микрослужбы) на GOTO 2016.

Использование шлюза API микрослужб создает возможную дополнительную единую точку отказа.

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

При отсутствии должного масштабирования шлюз API может стать узким местом.

Шлюз API требует дополнительных затрат на разработку и последующее обслуживание, если он


включает пользовательскую логику и агрегирование данных. Чтобы предоставить конечные точки
каждой микрослужбы, разработчикам необходимо обновить шлюз API. Кроме того, изменения в
реализации внутренних микрослужб могут вызвать изменения кода на уровне API шлюза. Тем не
менее, если в шлюзе API просто применяется безопасность, ведение журналов и управление
версиями (как при использовании управления API Azure), эти затраты на разработку могут
отсутствовать.

Если шлюз API разрабатывается одной командой, это может быть узким местом разработки. Это
еще одна причина, по которой лучше использовать несколько специализированных шлюзов API,
которые реализуют различные потребности клиента. Также можно внутренне разделить шлюз API
на несколько областей или уровней, которые принадлежат другим командам, работающим над
внутренними микрослужбами.

Дополнительные ресурсы
Крис Ричардсон (Chris Richardson). Шаблон: шлюз API, серверная часть для внешнего
интерфейса
https://microservices.io/patterns/apigateway.html
Шаблон шлюза API
https://docs.microsoft.com/azure/architecture/microservices/gateway
Шаблон агрегирования и компоновки
https://microservices.io/patterns/data/api-composition.html
Управление API Azure
https://azure.microsoft.com/services/api-management/
Уди Дахан (Udi Dahan). Объединение на основе служб
https://udidahan.com/2014/07/30/service-oriented-composition-with-video/
Клеменс Вастерс (Clemens Vasters). Messaging and Microser vices ( Обмен сообщениями
и микрослужбы) на GOTO 2016 ( видео)
https://www.youtube.com/watch?v=rXi5CLjIQ9k
API Gateway в двух словах (серия руководств по API Gateway ASP.NET Core)
https://www.pogsdotnet.com/2018/08/api-gateway-in-nutshell.html

НА ЗА Д ВПЕРЕД
Взаимодействие в архитектуре микрослужб
02.11.2021 • 8 minutes to read

В монолитном приложении, управляемом единым процессом, компоненты вызывают друг друга на


уровне языка или с помощью вызовов функции. Они могут быть тесно связаны, если вы создаете объекты
с кодом (например, new ClassName() ), или могут вызываться несвязанно, если вы используете внедрение
зависимости, ссылаясь на абстракции, а не на конкретные экземпляры объекта. В любом случае объекты
выполняются в одном процессе. Самая сложная задача при переходе от монолитного приложения к
приложению на базе микрослужб заключается в изменении механизма взаимодействия. Прямое
преобразование внутрипроцессных вызовов в вызовы RPC к службам приведет к чрезмерному и
неэффективному взаимодействию, не подходящему для распределенных сред. Трудности разработки
распределенных систем известны так хорошо, что существует свод принципов под названием
Заблуждения о распределенных вычислениях, где перечислены предположения, которые часто делают
разработчики при переходе от монолитных к распределенным конструкциям.

Единого решения не существует. Их несколько. Одно из решений — максимальная изоляция бизнес-


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

Приложение на основе микрослужб представляет собой распределенную систему, работающую на


нескольких процессах или службах, иногда даже не нескольких серверах или узлах. Обычно каждый
экземпляр службы — это процесс. Таким образом, службы должны взаимодействовать по протоколу
внутрипроцессного взаимодействия, например HTTP, AMQP или двоичному протоколу, такому как TCP, в
зависимости от характера каждой службы.

Сообщество микрослужб исповедует философию "умные конечные точки и глупые каналы". Этот слоган
рекомендует создавать структуру, где отдельные микрослужбы будут минимально зависеть друг от
друга и иметь максимальную внутреннюю согласованность. Как уже говорилось, каждая микрослужба
обладает собственными данными и собственной логикой предметной области. Но микрослужбы,
составляющие цельное приложение, обычно организуются с помощью связей по принципу REST, а не
сложных протоколов, таких как WS-*, и гибких, управляемых событиями взаимодействий вместо
централизованных оркестраторов бизнес-процессов.

Обычно используются два протокола — запросы и ответы HTTP с исходными API (в основном для
запросов) и легкие асинхронные сообщения при передаче обновлений в несколько микрослужб. Более
подробно это описано в следующих разделах.

Типы связи
Клиент и службы могут взаимодействовать через различные типы связи в зависимости от сценария и
целей. Эти типы связи можно разделить на два направления.

Первая группа определяет , является протокол синхронным или асинхронным:

Синхронный протокол. HTTP — это синхронный протокол. Клиент отправляет запрос и ожидает
ответа от службы. Это не зависит от выполнения кода клиента, которое может быть синхронным
(поток заблокирован) или асинхронным (поток не заблокирован, ответ в конечном итоге будет
отправлен). Здесь важно, что протокол (HTTP/HTTPS) является синхронным и код клиента сможет
продолжить выполнение задачи только после получения ответа от HTTP-сервера.
Асинхронный протокол. Другие протоколы, например AMQP (протокол, поддерживаемый многими
операционными системами и облачными средами), используют асинхронные сообщения. Код
клиента или отправитель сообщения обычно не ожидает ответа. Он просто отправляет
сообщение, как при отправке сообщения в очередь RabbitMQ или другого брокера сообщений.

Вторая группа определяет , имеет запрос одного или нескольких получателей:

Один получатель. Каждый запрос должен обрабатываться только одним получателем или
службой. Например, шаблон Command.

Несколько получателей. Каждый запрос может обрабатываться разным количеством


получателей — от нуля до нескольких. Такой тип взаимодействия должен быть асинхронным.
Например, механизм publish/subscribe, используемый в таких шаблонах, как архитектура,
управляемая событиями. Он основан на интерфейсе шины событий или брокере сообщений, когда
события обновляют данные в нескольких микрослужбах. Обычно это реализуется через
служебную шину или подобный объект , например служебную шину Azure, с помощью тем и
подписок.

Приложение на базе микрослужб часто использует комбинацию этих стилей взаимодействия. Наиболее
распространенный тип — взаимодействие с одним получателем по синхронному протоколу, например
HTTP или HTTPS, при вызове обычной службы веб-API HTTP. Для асинхронного взаимодействия между
микрослужбами обычно используются протоколы сообщений.

Полезно знать об этих направлениях, чтобы разбираться в доступных механизмах взаимодействия, но


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

Асинхронная интеграция микрослужб способствует их


автономности
Как уже упоминалось, при создании приложения на базе микрослужб важно подумать о способе их
интеграции. В идеале взаимодействие между внутренними микрослужбами необходимо свести к
минимуму. Чем меньше взаимодействия между микрослужбами, тем лучше. Вам часто придется каким-то
образом интегрировать микрослужбы. И когда это необходимо, помните, что взаимодействие между
микрослужбами обязательно должно быть асинхронным. Это не означает , что нужно использовать
конкретный протокол (например, асинхронный обмен сообщениями, а не синхронный HTTP). Просто
взаимодействие между микрослужбами должно происходить только путем асинхронного
распространения данных. Но попытайтесь устранить зависимость от других внутренних микрослужб в
начальной операции запроса-ответа HTTP.

Если это возможно, никогда не используйте синхронное взаимодействие (запрос-ответ ) между


несколькими микрослужбами, даже для запросов. Каждая микрослужба должна быть автономной и
доступной для клиента, даже если другие службы в этом приложении отключены или не работают. Если
вы считаете, что одна микрослужба должна обращаться к другой (например, отправлять HTTP-запрос на
получение данных), чтобы предоставить ответ клиентскому приложению, вы создадите архитектуру,
неустойчивую к сбоям.

Более того, наличие зависимостей HTTP между микрослужбами, как при создании длинных циклов
запрос-ответ с цепочкой HTTP-запросов, как показано в первой части рисунка 4-15, не только нарушит
автономность микрослужб, но и повлияет на их производительность, если одна из служб в цепочке не
будет работать правильно.

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

Рис. 4-15 . Антишаблоны и шаблоны при взаимодействии между микрослужбами

Как показано на схеме выше, при синхронном обмене данными "цепочка" запросов создается между
микрослужбами при обслуживании запроса клиента. Это антишаблон. В асинхронной связи
микрослужбы используют асинхронные сообщения или опрос по HTTP для взаимодействия с другими
микрослужбами, но запрос клиента обрабатывается сразу.

Если микрослужба должна вызвать дополнительное действие в другой микрослужбе, по возможности не


выполняйте это действие синхронно в рамках исходной операции запроса и ответа микрослужбы.
Руководствуйтесь принципом асинхронности (с помощью асинхронного обмена сообщениями или
событий интеграции, очередей и т. д.). Старайтесь не вызывать действие синхронно в рамках исходной
синхронной операции запроса и ответа.

И, наконец (и именно на этом этапе создания микрослужб возникают проблемы), если исходной
микрослужбе нужны данные, принадлежащие другим микрослужбам, не создавайте синхронные запросы
этих данных. Лучше реплицировать или распространять эти данные (только необходимые атрибуты) в
базу данных исходной службы, используя итоговую согласованность (обычно с помощью событий
интеграции, как описано в следующих разделах).

Как уже упоминалось в статье Определение границ модели предметной области для каждой
микрослужбы, дублирование данных в нескольких микрослужбах допускается. Более того, таким
образом вы сможете перевести данные на конкретный язык, используя термины этой области или
ограниченного контекста. Например, в приложении eShopOnContainers есть микрослужба identity-api ,
которая отвечает за большую часть данных пользователя с сущностью, называемой User . Но если вам
нужно хранить данные о пользователе в микрослужбе Ordering , вы используете отдельную сущность
под названием Buyer . Сущность Buyer имеет тот же идентификатор, что и исходная сущность User , но
содержит лишь некоторые атрибуты, необходимые для предметной области Ordering , а не весь профиль
пользователя.

Вы можете использовать любой протокол для асинхронной передачи и распространения данных в


микрослужбах, чтобы достичь итоговой согласованности. Как уже упоминалось, можно использовать
события интеграции с помощью шины событий или брокера сообщений или даже HTTP, чтобы
опрашивать другие службы. Это неважно. Главное правило — не создавать синхронные зависимости
между микрослужбами.
В следующих разделах описываются разные стили взаимодействия, которые вы можете использовать в
приложении на базе микрослужб.

Стили взаимодействия
Вы можете выбирать разные протоколы для взаимодействия в зависимости от желаемого типа
взаимодействия. В качестве механизма взаимодействия с помощью синхронных запросов и ответов
обычно используются HTTP и REST, особенно если вы публикуете службы за пределами узла Docker или
кластера микрослужб. Если взаимодействие между службами осуществляется в пределах узла Docker или
кластера микрослужб, вы можете использовать двоичный формат взаимодействия (например, WCF с
помощью TCP и двоичного формата). Кроме того, вы можете использовать механизмы асинхронного
взаимодействия на основе сообщений, например AMQP.

Существует также несколько форматов сообщений, например JSON или XML, или даже двоичных
форматов, которые могут быть более эффективными. Если вы выбрали нестандартный двоичный
формат , возможно, службы с этим форматом не следует публиковать. Вы можете использовать
нестандартный формат для внутреннего взаимодействия между микрослужбами. Например, при
взаимодействии между микрослужбами на узле Docker или кластере микрослужб (в оркестраторах
Docker) или для собственных клиентских приложений, которые обращаются к микрослужбам.
Операция запрос-ответ с использованием HTTP и REST
Если клиент использует взаимодействие типа "запрос-ответ ", он посылает запрос к службе, которая
обрабатывает этот запрос и отправляет ответ. Взаимодействие типа "запрос-ответ " особенно хорошо
подходит для запроса данных от клиентских приложений для пользовательского интерфейса в режиме
реального времени. Поэтому в архитектуре микрослужб лучше всего использовать этот механизм
взаимодействия для запросов, как показано на рис. 4-16.

Рис. 4-16 . Использование взаимодействия типа "запрос-ответ " по протоколу HTTP (синхронно или
асинхронно)

Когда клиент использует взаимодействие типа "запрос-ответ ", он предполагает , что ответ придет
быстро, меньше чем через секунду или максимум через несколько секунд. Если ответ задерживается,
необходимо реализовать асинхронное взаимодействие на основе шаблонов обмена сообщениями и
технологий обмена сообщениями. Этот подход рассматривается в следующем разделе.

Популярный стиль архитектуры для взаимодействия типа "запрос-ответ " — это REST. Этот подход
основан на HTTP-протоколе и тесно связан с ним. Он принимает HTTP-команды, например GET, POST и
PUT. REST — это самый распространенный архитектурный подход к взаимодействию при создании служб.
Службы REST можно использовать при разработке служб веб-API ASP.NET Core.

Использование служб HTTP REST в качестве IDL имеет дополнительные преимущества. Например, если вы
используете метаданные Swagger для описания API службы, вы можете применять средства, создающие
заглушки клиента, которые могут обнаруживать и использовать ваши службы напрямую.

Дополнительные ресурсы
Мартин Фоулер (Mar tin Fowler). Модель зрелости Ричардсона Описание модели REST.
https://martinfowler.com/articles/richardsonMaturityModel.html
Swagger Официальный сайт.
https://swagger.io/
Push-уведомления и связь в режиме реального времени по протоколу HTTP
Другой вариант (обычно используется не для тех же целей, что и REST) — это связь "один ко многим" в
режиме реального времени с платформами более высокого уровня, например ASP.NET SignalR, и такими
протоколами, как WebSockets.

Как показано на рисунке 4-17, связь в режиме реального времени по протоколу HTTP означает , что
серверный код может принудительно отправлять содержимое подключенным клиентам, когда данные
становятся доступны, а не ждать, пока клиент запросит новые данные.

Рис. 4-17 . Асинхронное взаимодействие "один ко многим" на основе сообщений в режиме реального
времени

SignalR — это лучший способ достичь взаимодействия в реальном времени для передачи содержимого
клиентам с внутреннего сервера. Поскольку взаимодействие происходит в режиме реального времени,
изменения отображаются в клиентских приложениях почти моментально. Обычно это обрабатывается
таким протоколом, как WebSockets, с помощью множества подключений WebSockets (по одному для
каждого клиента). Типичный пример — служба передает изменение счета матча множеству клиентских
веб-приложений одновременно.

НА ЗА Д ВПЕРЕД
Асинхронное взаимодействие на основе
сообщений
02.11.2021 • 7 minutes to read

Асинхронный обмен сообщениями и взаимодействие, управляемое событиями, имеют важное значение


при распространении изменений по многим микрослужбам и связанным с ними моделям доменов. Как
упоминалось ранее в обсуждении микрослужб и ограниченных контекстов (BC), модели (пользователь,
клиент , продукт , учетная запись и т. д.) могут иметь разное значение для разных микрослужб или BC. Это
означает , что при внесении изменений необходимо найти способ согласовать эти изменения для разных
моделей. Для решения этой проблемы необходимо обеспечить итоговую согласованность и
взаимодействие, управляемое событиями, на основе асинхронного обмена сообщениями.

При использовании системы обмена сообщениями процессы взаимодействуют путем асинхронного


обмена сообщениями. Клиент отправляет команду или запрос в службу при помощи сообщения. Если
служба должна ответить, она отправляет ответное сообщение клиенту. Так как это взаимодействие на
основе сообщений, клиент знает , что ответ может поступить не сразу, а возможно, что ответа не будет
вообще.

Сообщение состоит из заголовка (метаданные, например, идентификатор или данные для обеспечения
безопасности) и текста. Обычно сообщения отправляются с использованием асинхронного протокола,
например AMQP.

Предпочтительной инфраструктурой для такого типа обмена данными в сообществе микрослужб


является упрощенный брокер сообщений, который отличается от больших брокеров и оркестраторов,
используемых в SOA. В случае упрощенного брокера сообщений задача инфраструктуры обычно
сводится к выполнению функций брокера обмена сообщениями с использованием простой реализации,
например RabbitMQ или масштабируемой служебной шины в облаке, такой как служебная шина Azure.
При таком сценарии основная обработка данных выполняется в конечных точках, там, где создаются и
используются сообщения, т. е. микрослужбами.

Есть еще правило, которого следует придерживаться, насколько это возможно. Между внутренними
службами следует использовать только асинхронный обмен сообщениями, а синхронное взаимодействие
(например, HTTP) использовать только для клиентских приложений, работающих со службами
интерфейса (шлюзами API и микрослужбами первого уровня).

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

Взаимодействие на основе сообщений с одним получателем


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

Взаимодействие на основе сообщений с одним получателем особенно хорошо подходит в случаях


отправки асинхронных команд из одной микрослужбы другую. На рис. 4-18 иллюстрируется этот метод.

После того как вы начнете взаимодействие на основе сообщений (с использованием команд или
событий), вам не следует использовать этот тип взаимодействия вместе с синхронным обменом по
протоколу HTTP.

Рис. 4-18 . Одна микрослужба, получающая асинхронное сообщение

Когда команды поступают из клиентских приложений, они могут быть реализованы в виде синхронных
команд HTTP. Используйте команды на основе сообщений, когда требуется высокая масштабируемость,
или когда вы уже запустили бизнес-процесс на основе сообщений.

Взаимодействие на основе сообщений с несколькими


получателями
Существует более гибкий подход. Это механизм публикации или подписки, позволяющий сделать
сообщения от отправителя доступными дополнительным микрослужбам-подписчикам или внешним
приложениям. Он позволяет реализовать принцип "открыт — закрыт " в службе отправки. Таким
образом, в будущем могут быть добавлены дополнительные подписчики без изменения службы
отправителя.

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

Асинхронное взаимодействие, упра