WeatherForecast. Ads. Docker.
Предисловие
О следующем шаге вы уже догадались. Нужно новый сервис "упаковать" в docker-контейнер.
Поехали
Как всегда, код тут.
Первым делом мы создадим docker-файл (Dockerfile.ads) с инструкцией по сборке контейнера, он не будет сольно отличаться от docker-файла для основного приложения:
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build # Copy everything COPY . ./ # Build and publish a release RUN dotnet publish DeployToProduction.Ads.WebApi --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.Ads.WebApi.dll"]
Далее у нас несколько вариантов.
Первый - это собрать образ отдельной командой:
docker build -t weather-forecast-ads-img -f Dockerfile.ads .
Второй вариант - обновить файлы docker-compose и пересобрать все образы.
Как вы помните, у нас был один файл docker-compose для конфигурации Development - docker-compose.app.dev.yml:
version: "3.9" services: ads: container_name: "weather-forecast-ads" image: "weather-forecast-ads-img" build: context: . dockerfile: Dockerfile.ads networks: - weather-forecast-net ports: - "5298:80" environment: ASPNETCORE_ENVIRONMENT: Development DOTNET_PRINT_TELEMETRY_MESSAGE: false app: container_name: "weather-forecast-app" image: "weather-forecast-app-img" build: context: . dockerfile: Dockerfile.app networks: - weather-forecast-net ports: - "5022:80" environment: ASPNETCORE_ENVIRONMENT: Development DOTNET_PRINT_TELEMETRY_MESSAGE: false ConnectionStrings__Postgres: Host=weather-forecast-postgres;User Id=postgres;Password=postgres;Database=postgres ConnectionStrings__Redis: weather-forecast-redis:6379 ConnectionStrings__AdsServerUrl: http://weather-forecast-ads depends_on: postgres: condition: service_started redis: condition: service_started ads: condition: service_started
Второй - для конфигурации Production - docker-compose.app.prd.yml:
version: "3.9" services: ads: container_name: "weather-forecast-ads" image: "weather-forecast-ads-img" build: context: . dockerfile: Dockerfile.ads networks: - weather-forecast-net ports: - "5298:80" environment: ASPNETCORE_ENVIRONMENT: Production DOTNET_PRINT_TELEMETRY_MESSAGE: false setup: container_name: "weather-forecast-setup" image: "weather-forecast-setup-img" build: context: . dockerfile: Dockerfile.setup networks: - weather-forecast-net environment: ConnectionStrings__Postgres: Host=weather-forecast-postgres;User Id=postgres;Password=postgres;Database=postgres depends_on: postgres: condition: service_started redis: condition: service_started app: container_name: "weather-forecast-app" image: "weather-forecast-app-img" build: context: . dockerfile: Dockerfile.app networks: - weather-forecast-net ports: - "5022:80" environment: ASPNETCORE_ENVIRONMENT: Production DOTNET_PRINT_TELEMETRY_MESSAGE: false ConnectionStrings__Postgres: Host=weather-forecast-postgres;User Id=webapp;Password=webapppwd;Database=postgres ConnectionStrings__Redis: weather-forecast-redis:6379 ConnectionStrings__AdsServerUrl: http://weather-forecast-ads depends_on: setup: condition: service_completed_successfully
Обращу ваше внимание на один момент. В Dockerfile.ads мы указываем инструкцией EXPOSE 80, что контейнер из этого образа "выставляет" порт 80, то есть слушает и принимает запросы по этому порту. В docker-compose файле при описании сервиса ads в параметре ports мы указываем какой порт "хоста" будет использоваться для обращения к 80-му порту контейнера. НО в переменной окружения ConnectionStrings__AdsServerUrl для сервиса app мы указываем адрес сервиса http://weather-forecast-ads, где weather-forecast-ads - это имя контейнера, порт мы не указываем, так как используется 80-ый порт по умолчанию. Акцентирую, не правильными вариантами будут: http://localhost:5298, http://weather-forecast-ads:5298.
Собрать образы и запустить все сервисы вы можете одной из команд:
docker compose -f docker-compose.db.yml -f docker-compose.app.dev.yml up --build
docker compose -f docker-compose.db.yml -f docker-compose.app.prd.yml up --build
Проверим что все образы на месте в Docker Desktop:
Протестируем работу нашего приложения:
Освежим в памяти, как загрузить образ в Container Registry, на примере нового образа для ads. Для этого нужно сначала добавить тэг:
docker tag weather-forecast-ads-img cr.selcloud.ru/deploy2production/weather-forecast-ads-img:v1.0
А потом отправить образ в Container Registry:
docker push cr.selcloud.ru/deploy2production/weather-forecast-ads-img:v1.0
Проверяем список образов в интерфейсе Selectel:
Текущий вариант приложения мы не будем разворачивать в Selectel. Вы можете потренироваться самостоятельно, но для этого не забудьте обновить образ приложения app в Container Registry с новой версией кода. Далее мы добавим в сервис Ads базу данных.
З.Ы.
Традиционное заключение - автоматизированные тесты. Добавляем сборку для интеграционного тестирования сервиса Ads:
Сервис запускается в контейнере с помощью библиотеки Testcontainers:
Я выделил интересный момент - это ожидание, когда сервис запустится и будет готов отвечать на наши запросы. Для этого в сам сервис Ads я добавил контроллер, который называют health check:
Так же мы добавляем в UI-тест приложения проверку блока с рекламой: