WeatherForecast. Setup.
Предисловие
Мы начали разбираться с Docker Compose на предыдущем шаге. Теперь хочется охватить чуть больше полезных фич этого инструмента, которые сильно помогут в разработке. Реальные проекты состоят нескольких приложений, программ, сервисов. В нашем случае мы рассмотрим следующий момент. Сервис при запуске ожидает настроенную схему базы данных Postgres. В режиме разработки мы при старте выполняли скрипты sql для создании таблиц. Но в "бою" такой подход не подойдет, так как у нас может одновременно запускаться несколько копий приложения или само приложение может состоять из нескольких сервисов. Обычно процедуру миграции (обновления) схемы базы данных выносят в отдельное приложение или используют для этого сторонний инструмент. На пример, если вы используете Entity Framework, то выполняете команду 'dotnet ef database update'. Мы создадим консольную программу, которая будет выполнять обновление схемы базы данных.
Поехали
Исходники к этому посту находятся тут.
Создадим консольный проект, добавим необходимые зависимости:
Добавим кофигурационные файлы и код:
Для демонстрации тут всё максимально просто: считываем настройки подключения, вызываем уже знакомый метод Setup класса Db.
Позвольте уделить внимание ещё одному важному моменту. Ранее наше приложение подключалось к postgres пользователем с "админскими" правами. Что не есть хорошо и не безопасно. Приложение должно иметь минимально необходимый уровень доступа к базе данных. Давайте это исправим. В проект "DeployToProduction.WeatherForecast.Data.Psql" нужно добавить новый sql-скрипт, который будет создавать пользователя для нашего приложения:
Не забудьте в настройках нового скрипта установить свойство "Build Action":
И, конечно же, нужно проверить как наш код работает с новым пользователем с помощью автоматического теста, модифицируем уже имеющийся тест:
В 31-ой строке я меняю логин/пароль в строке подключения на нового пользователя.
В коде самого приложения мы убираем обновление схемы базы данных под условие с проверкой среды выполнения, таким образом при разработке нам будет удобно - схема обновляется, а в "бою" приложение будет ожидать подготовленной базы данных:
Удалим ранее созданные образы контейнера нашего приложения.
У нас теперь будет два docker-файла, один "Dockerfile.app" для сборки приложения, второй "Dockerfile.setup" для сборки нашей утилиты setup:
Обратите внимание, что при сборке консольного проекта на linux, расширение файла будет "dll", и его также нужно запускать через dotnet.
Веб приложение использует Postgres и Redis, для консольной утилиты setup нужен только Postgres, но нам лень (ладно, мне лень) и не хочется усложнять пример, поэтому мы создадим один файл docker compose "docker-compose.db.yml" для запуска баз данных, который далее будем переиспользовать:
Добавим "docker-compose.setup.yml" для запуска setup:
Запускаем setup в контейнере командой:
docker compose -f docker-compose.db.yml -f docker-compose.setup.yml up
Обратите внимание, я указываю оба файла.
В выводе в консоль мы видим, что два наших sql-скрипты были выполнены:
Ctrl+C - остановить, удалить остановленные контейнеры:
docker compose -f docker-compose.db.yml -f docker-compose.setup.yml down
Теперь docker compose для приложения. У нас будет два файла, один "docker-compose.app.dev.yml" для запуска при разработке, второй "docker-compose.app.prd.yml" - "боевой":
Тут у нас и Environment=Development и логин в Postgres админский. А, вот, второй будет интереснее:
Мы добавили в services нашу утилиту setup, которая будет выполнена перед запуском app, так как app зависит от setup, смотри depends_on. И логин/пароль в строке подключения Postgres используется пользователь, которого мы создали в новом sql-скрипте.
docker compose -f docker-compose.db.yml -f docker-compose.app.prd.yml up
Запустилось. Видим работающие контейнеры баз данных и приложения, а контейнер setup выполнил свое дело и остановился:
Ctrl+C - остановить. Удалить контейнеры:
docker compose -f docker-compose.db.yml -f docker-compose.app.prd.yml down
Таким образом вы можете упростить себе процесс разработки, создавая переиспользуемые части инфраструктуры вашего приложения или организуя специфичные режимы работы.
З.Ы.
Ну, вы уже догадались... нет нам покоя пока тесты не будут полностью автоматизированы, поэтому вот код UI теста, который запускает все базы данных и приложение в контейнерах и "прокликивает" с помощью Selenium: