Статья Docker в приложениях asp.net core

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

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

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

Так что же такое Docker
Docker это технология, которая позволяет нам создавать контейнеры ( песочницы ) для упрощения деплоя, развертки и запуска наших приложений на хостовых системах, например на Linux’ах.
Тут вы могли бы подумать, что Docker и виртуальные машины - это одно и тоже, но это не так. Давайте разбираться вместе, первым делом определим понятие виртуализация следующим образом: физически существует один компьютер, выполняющий функции нескольких. Данное поведение достигается за счёт специального программного обеспечения, называемого гипервизором. Гипервизор позволяет разделять ресурсы одного физического компьютера между многими “виртуальными”. Вот так по-детски просто мы описали это понятие.
Докер решают ту же задачу, но другим путём, более эффективным. Рассмотрим картинку ( с офф сайта docker )
1.png


Хорошо можно заметить, насколько эффективнее работает докер.

Docker для windows.
Поставить docker на Linux не составит проблем, винда же как всегда “преуспела” в этом плане. Чтобы запустить docker под окнами нужно скачать Docker Toolbox. Обычный docker под windows создает много проблем ( в частности забирает возможность пользоваться virtual box ). Скачиваем и ставим. Ничего сложного быть не должно.

Что такое ASP.NET Core
Это логичный виток эволюции, microsoftовского ASP.NET MVC - фреймворка для разработки web-приложений. Наконец-то мелкомягкие сделали кроссплатформенный фреймворк с открытым исходным кодом. Видать, не за горами, светлое будущее.
Думаю нет особого смысла расписывать что это, чем это лучше - поэтому просто отправлю вас читать документацию по этой замечательной вещи.

Необходимое отступление
Конечно рассматривая docker, нужно разрабатывать приложение. Наиболее классно - docker смотрится в микросервисной архитектуре, поэтому мы будем её использовать.
Что у нас будет:
  • Микросервис конвертации валют
  • Микросервис погоды
  • Фронтенд, который будет показывать два виджета - погоду и курс рубля к доллару.
Сервисы выбраны максимально теоретически - основная цель статьи показать красоту docker’а при разработке под asp.net core.

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


Переходим к коду. Создаем проект ASP.NET Core.
Определим структуру проекта. Хорошей практикой при разработки апи является его версионирование. Поэтому создадим папку с названием V1, что соответствует нашей версии. Также создадим папку Contracts, где будем хранить модель данных. Затем создадим библиотеку классов (dll) для описания бизнес правил. В нашем случае тут будет размещен апи клиент для сайта .
После этого структура выглядит примерно так:
2.png


Далее всё просто, как всегда обращаемся к апи сайта, получаем результат. Должен предупредить, что бесплатный план накладывает множество ограничений, например нельзя менять source currencie, но не будем по этому поводу огорчаться.
3.png

На этом закончим с микросервисом для валюты, не забываем, что микросервисы намеренно выбраны элементарными - цель статьи показать как использовать docker.

Далее создадим микрослужбу для прогноза погоды. В этом нам поможет api, предоставляемое сайтом openweathermap.org. Нам так же необходимо получить API ключ, для этого нужно зарегистрироваться. И так же наш бесплатный аккаунт ограничивают. После регистрации на почту падает ключик.
Нас интересует вот этот endpoint:

Я буду наблюдать зависимость для Новосибирска, параметр units определяет единицы измерения температуры, значение metric - соответствует цельсию.
Аналогично создаем сервис и апи клиент. После нехитрых преобразований выглядеть у нас должно так.
4.png

и код контроллера
5.png


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

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

Начнём с CurrencyConvert. Уберём апи ключ, и baseurl в файл настроек. Кстати, защита апи ключей в asp.net приложениях целая отдельная тема, которую я раскрою в другой статье. Кроме того, используем принцип DI и воспользуемся новым microsoft’овским DI-контейнером.
Первым делом вынесем url и api key. Для этого в файле appsettings.json создадим секцию Urls и добавим туда данные следующим образом:
7.png

Ключи я в конце поменял, так что особого профита скрывать их - нет.
Теперь настроим DI контейнер, для этого создадим интерфейс IApiClient следующим образом:
8.png

Теперь порефакторим старый класс клиента, после преобразований он имеет следующий вид:
9.png

На 11 строке определяется стратегия повторения запроса запроса к апи, в данном случае это реализовано с помощью библиотеки Polly, используется экспоненциальное повторение. Далее объявляются два приватных поля для url и api ключа соответственно. На строках 21-25 объявлен конструктор класса с параметром. Именно для этого конструктора мы позднее настроим DI. 23 и 24 строки демонстрируют извлечение данных из файла appsettings.json. Далее идёт реализация http метода get средствами стандартного HttpClient’a.

Теперь настроим DI контейнер. Для этого напишем метод расширения для интерфейса IServiceCollection ( который представляет microsoft DI framework ). В нём мы опишем конкретную реализацию интерфейса IApiClient. Выглядеть данный метод будет так.
10.png

Теперь перейдём в класс Startup.cs проекта CurrencyConvert.WebApi. И изменим метод ConfigureServices. Благодаря нашему методу расширения, мы можем сделать так:
11.png

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

На 13 строке объявляется апи клиент, именно сюда DI-контейнер будет “подсовывать” нужную реализацию данного интерфейса.
Далее всё осталось как было, за исключением преобразования возвращаемого объекта. Теперь там тоже обрезается не нужная информация. Если ты один из тех кто не знает, что такое принцип DI, DI-контейнер, не расстраивайся, а читаю мою другую статью и просвещайся.
Аналогично поступаем с сервисом WeatherInformation.

Для фронтэнда я хочу использовать typescript, react, redux для управления состоянием, axios для запросов к апи, less для разработки стилей. Помимо этого, я буду использовать апи gateway (в виде сервиса на asp net core) Как засетапить и настроить всю эту прелесть я рассказываю тут.

Контейнеризируй всё.
Перед тем как занятся фронтэнд частью я перейду к основной теме статьи - docker контейнеризации.
Первое, что необходимо - это поставить Docker Toolbox. По невнятным причинам Docker for windows не работает на 90% систем. К тому же он просит Hyper-v для своей работы. А Hyper-V убивает oracle virtual box, как известно. Поэтому DockerToolbox - бро, Docker for windows - не бро.
Затем нам необходимо скачать образы microsoft net core. Конкретно нужно скачать:
Код:
microsoft/dotnet:2.1-sdk
microsoft/dotnet:2.1-aspnetcore-runtime
Микрософт, оптимизировала свой образ и образ runtime содержит только необходимый минимум. Кстати, контейнеры на нём получаются порядка 290 мб.
Чтобы загрузить образы, необходимо выполнить следующие команды в терминале
Код:
docker pull microsoft/dotnet:2.1-sdk
docker pull microsoft/dotnet:2.1-aspnetcore-runtime

Итак продолжим, создадим Dockerfile в корневой папке солюшена - это то место где лежат файлы *.sln. Для WeatherInformation (да и для большинства asp net core приложений) - docker файл выглядит так

Хочу сразу сказать, что это оптимизированный образ, по сути, мы создаем тут 2 образа: один который base (я буду назвать его base-runtime) будем запускать, публиковать и так далее, а второй, который build ( он же publish ) удалим, так как он будет весить 1.75GB или около того.
13.png

На 1-3 строке происходит создание того самого base-runtime слоя. В нём создаётся рабочая директория app и открывается 80-ый порт.
Далее создается build слой и устанавливается рабочая директория - src. Теперь мы должны перенести в контейнер все зависимости, это делается на строках 7-10. Под зависимостями я также подразумеваю установку nuget пакетов. Далее, на строка 12-15 мы билдим и готовим к публикации проект. С 17 строке начинается та самая оптимизация: мы берём результаты команды dotnet publish и копируем их из build слоя в base-runtime слой. Ну и 20ой, завершающей строкой - указываем докеру - какую команду он должен выполнить когда мы запустим контейнер.
Сохраняем файл, и открываем терминал. Теперь нам нужно собрать наш образ. Для этого используем команду docker build. Находясь (в терминале) в папке с Dockerfile’ом выполним следующую команду:
14.png

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

Тут видно как докер создает ваш образ шаг за шагом. Наконец, чтоб запустить сие чудо нужно воспользоваться командой docker run. Я не вижу особого смысла описывать известные команды docker, так что почитайте о них в документации.
Команда для запуска контейнера выглядит так:
16.png

Как вы узнаете из документации параметр -d указывает на то, что контейнер нужно запустить в фоновом режиме, параметр порт указывает какой порт прокинуть наружу, а далее следует наименование образа и версия, которую мы запускаем.
Теперь проверим, что docker run запустил контейнер и всё хорошо. Для этого пропишем docker ps
17.png

как видим всё хорошо - контейнеры работают.
Чтобы узнать ip назначенный докер машине можно в терминале прописать docker-machine ip
Команда вернет IP адрес докер машины. Так чтобы обратится к контейнеру созданным на основе образа weather, необходимо обратится к 63573 порту, ip адреса docker-machine ip.
Аналогично поступаем с currency микросервисом. Запускаем контейнеры и переходим к фронтенд разработке.
Перед тем как перейти к разработке компонентов, создадим немного инфраструктурного кода (это такой код, который не решает бизнес задач, но без него нельзя обойтись). Нам нужно написать провайдер, для доступа url сервисов. Поскольку в ApiGetewaу у нас имеется файл appsettings.json, где мы храним эти urlы создадим провайдер для него. В папке src/ создаём файл appSettingsProvider.ts и подключаем json файл.
18.png

Далее нам нужно объявить интерфейс для доступа к сервисам, который повторяет структуру appsettings.json файла.
19.png

и теперь отдадим объект с настройками клиентскому коду, например так:

20.png


Теперь везде где необходимо, мы просто подключаем наш провайдер:
21.png

и используем его
22.png

Воспользуясь структурой из статьи про установку фронтенд стэка, начнём создавать виджет погоды.
  1. Создаём константы.
    23.png
  2. Создаём интерфейс для данных
    24.png
  3. Создаём ActionCreator
    25.png
  4. Создаём редьюсер
    26.png
  5. Добавляем редьюсер в корневой редьюсер
    27.png

  6. Создаем компонент
    28.png
  7. И подключаем его к хранилищу
    29.png

Как видите получился довольно четкий алгоритм действий, как я и обещал. Если вы не знакомы с reactом, возможно мне стоит написать и о нём тоже. Поделитесь желанием в комментариях.
Немного поверстав, получаем два виджета выглядит финал версия как-то так ( слишком просто чтобы делать на react & redux ):

30.png


Docker compose
У нас получилось 3 сервиса:
  • Сервис погоды
  • Сервис курса валют
  • Фронтенд сервис
Разумеется запускать всё через docker run не кошерно. Нужно как менеджить всю нащу docker-сеть. Стандартное средство для этого - docker compose. Он основан на yml файле, в котором описываются все настройки микросервисов. По сути, это удобочитаемый файл конфигурации команды docker run. Итак начнём создавать docker-compose файл.
31.png


вот и вся хитрость. В свойство build мы указываем путь к Dockerfile. Предполагается, что docker-compose.yml лежит в самом верху иерархии. Свойство ports говорит само за себя. Сервис с фронтендом - добавьте сами.
Теперь прежде чем запустить оркестрацию - необходимо собрать всё это дело. Делается это командой docker-compose build ( находясь в папке с docker-compose файлом ).
После билда, достаточно выполнить docker-compose up чтобы запустить настроенные сервисы.

32.png

А на этом у меня всё.
ссылка на репозиторий: enterDevelop/Currency
 
Последнее редактирование:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!