WeatherForecast. Docker Compose.
Предисловие
На предыдущих шагах (dev, Docker-изация) мы запускали контейнеры баз данных руками. Да, это полезно для понимания и тренировки, но не удобно в повседневной работе. Для сборки необходимого окружения одной командой есть Docker Compose - один файл описывает всё необходимое. Попробуем запустить всё наше приложение одни легким движением руки.
Поехали
Исходники к этому посту находятся тут.
Как всегда сначала почистим запущенные контейнеры и ранее созданные образы.
Добавим в проект файл docker-compose.yml:
version: "3.9" name: "weather-forecast" networks: weather-forecast-net: services: postgres: image: "postgres" container_name: "weather-forecast-postgres" networks: - weather-forecast-net ports: - "5432:5432" environment: POSTGRES_PASSWORD: postgres redis: image: "redis" container_name: "weather-forecast-redis" networks: - weather-forecast-net ports: - "6379:6379" app: container_name: "weather-forecast-app" image: "weather-forecast-app-img" build: context: . dockerfile: Dockerfile networks: - weather-forecast-net ports: - "5022:80" environment: ASPNETCORE_ENVIRONMENT: Production DOTNET_PRINT_TELEMETRY_MESSAGE: false ConnectionStrings__Postgres: Host=weather-forecast-postgres;Username=postgres;Password=postgres;Database=postgres ConnectionStrings__Redis: weather-forecast-redis:6379 depends_on: postgres: condition: service_started redis: condition: service_started
networks - определяем сеть в которой будут работать наши контейнеры.
services - перечисляем нужные нам контейнеры.
postgres - указываем образ, имя контейнера, сеть, к которой его подключить, порты и переменные окружения.
app - наше приложение, его контейнер будет собираться из Dockerfile-а, также имя, сеть, порты и переменные окружения мы уже выносим сюда, ещё нужно указать зависимости, чтобы наше приложение запускалось после того, как базы данных будут готовы.
Подредактируем Dockerfile, нам уже не нужно указывать в нем переменные окружения:
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build # Copy everything COPY . ./ # Build and publish a release RUN dotnet publish DeployToProduction.WeatherForecast.App --configuration Release -o out # Build runtime image FROM mcr.microsoft.com/dotnet/aspnet:7.0 EXPOSE 80 COPY --from=build /out . # Start App ENTRYPOINT ["dotnet", "DeployToProduction.WeatherForecast.App.dll"]
Дл запуска открываем терминал в каталоге проекта и выполняем команду:
docker compose up
Команда "docker compose up" запускает все контейнеры перечисленные в файле docker-compose.yml и выводит в консоль их логи. Чтобы остановить контейнеры нажмите Ctrl+C. Для запуска в фоновом режиме используйте параметр -d:
docker compose up -d
Удалить все контейнеры можно командой:
docker compose down
Если вы внесли изменения в проект или Dockerfile, то пересобрать образ можно командой
docker compose build
Есть маленький нюанс. Наше приложение при старте выполняет обновление схемы базы данных Postgres. Хоть мы и указали, что контейнер приложения зависит от контейнера postgres, в момент выполнения запуска приложения база данных postgres может быть ещё не готова принимать запросы. Способов решения этой проблемы несколько, один из них - воспользоваться фичей docker compose - healthcheck. Но, так как я не хочу сильно закапывать вас в эти тонкости (при том что первый результат поиска из гугла и SO не сработает), я сделаю более простую и понятную проверку в коде Db.cs:
Пару слов в сторону. Мы ручками создавали простейший проект и настраивали работу с docker, чтобы вся эта кухня не казалась магией. Сегодня Visual Studio из коробки поддерживает интегрированную работу с Docker. Вы просто создаете новый проект и ставити галочку "Enable Docker". VS создаст для вас Dockerfile и настроит запуск и отладку приложения в контейнере. Более того, вы просто сможете добавить docker-compose.yml для инфраструктуры приложения.
З.Ы.
Хотелось бы тут добавить "вишенку на торте", как мы можем автоматизировать UI тест и запускать не просто контейнер из образа нашего приложения, а запускать docker compose, чтобы не приходилось руками поднимать контейнеры базы данных. Но, Testcontainers для Java имеет фичу по работе с docker compose (DockerComposeContainer), а вот в .NET её ещё не завезли. Хотя всё, что делает docker compose, вы можете воспроизвести в коде теста: создать сеть, создать контейнеры базы данных.