17 KiB
Задания
1. Многоступенчатая сборка образов
В полученной вами директории todo_app
находятся исходные коды Enterprise Quality™® системы для менеджмента напоминаний.
Она состоит из следующих частей:
TodoApi
- API-сервис, на платформе.NET 7
.todo_ui
- веб-интерфейс к этому сервису, Single-PageJavaScript
приложение(SPA
), написанное с использованиемVue.js 3
.- API-сервис использует
PostgreSQL
для хранения данных.
Необходимо будет контейнеризировать эту систему.
Сервис TodoApi имеет следующие шаги сборки:
- Во-первых, для его сборки необходим образ
mcr.microsoft.com/dotnet/sdk:7.0
- Далее, из директории, в которой находятся исходные коды сервиса(см.
todo_app/TodoApi
),
нужно сделатьdotnet restore TodoApi.csproj
- эта команда скачает зависимости сервиса. - Следующим шагом идет непосредственно сборка сервиса.
Она производится командойdotnet build TodoApi.csproj -c Release -o <output_directory>
,
в которой вместо<output_directory>
необходимо подставить имя директории, которое будет
содержать бинарные файлы сервиса, например/app/build
- Последняя вещь, которую необходимо сделать - это вызывать команду
dotnet publish TodoApi.csproj -c Release -o <publish_directory>
,
которая опубликует результирующие бинарные файлы, а также зависимости сервиса
в<publish_directory>
(например в/app/publish
).
Для запуска процесса сервиса, образ SDK не нужен, достаточно лишь образа, содержащего соответствующий фреймворк
ASP.NET
- в данном случае mcr.microsoft.com/dotnet/aspnet:7.0
.
Запуск осуществляется вызовом исполняемого файла ./TodoApi
из директории, которая хранит опубликованные
бинарные файлы сервиса и его зависимостей.
JavaScript
приложение собирается следующим образом:
- Прежде всего, необходим образ
NodeJS
- в данном случае подойдетnode:21
. - Далее, из директории, в которой находятся исходные коды приложения(см.
todo_app/todo_ui
),
нужно вызыватьnpm install
- это команда скачает зависимости приложения. - После этого, в этой же директории необходимо выполнить команду
npm run build
, в результате чего,
в этой директории появится директорияwwwroot
, содержащая файлindex.html
,
результирующий код на JS, а также его ресурсы, такие как картинки и файлы стилей(css).
Для запуска JavaScript
приложения NodeJS
не нужен, достаточно лишь любого веб-сервера, и в
нашем случае, в API-сервисе такой имеется(он называется Kestrel
).
Для хостинга JS-приложения в API-сервисе, необходимо всего лишь скопировать упомянутую выше директорию
wwwroot
внутрь результирующей директории API-сервиса(которая получается после выполнения dotnet publish ...
).
Задачи.
-
Напишите
Dockerfile
, из которого можно было бы создать образ, который отвечал бы следующим требованиям:- Образ должен основываться на образе
mcr.microsoft.com/dotnet/aspnet:7.0
- Готовое приложение API-сервиса вместе с зависимостями должно находиться в директории
/app
JavaScript
приложение должно находиться в директории/app/wwwroot
- При старте контейнера из такого образа, должен запускаться приложение API-сервиса.
Документация по многоступенчатой сборке образов находится тут: https://docs.docker.com/build/building/multi-stage/
- Образ должен основываться на образе
-
Создайте образ из полученного
Dockerfile
и назовите егоtodo-bundle
-
Перед запуском самого приложения, необходимо запустить и подготовить
PostgreSQL
в сетиtodo
.Создайте именованную сеть типа
bridge
, в которой будет работать вся система, назовите ееtodo
.Создайте том данных, в котором
PostgreSQL
будет хранить БД. Назовите егоtodo_pgdata
.Запустите именованный контейнер
todo_postgres
из образаpostgres:16
, при этом:- При запуске установите следующие переменные окружения контейнера в значение
todo
:POSTGRES_DB
- имя базы данных, к которой будет обращаться API-сервисPOSTGRES_USER
- пользователь БД, через которого будет работать сервисPOSTGRES_PASSWORD
- пароль для пользователя
- Установите значение переменной среды
PGDATA
в значение/var/lib/postgresql/data
- здесьPostgreSQL
будет хранить данные. - Примонтируйте том данных
todo_pgdata
в качестве директории/var/lib/postgresql/data
. - Примонтируйте директорию
initdb
изtodo_app
в качестве директории/docker-entrypoint-initdb.d
внутри контейнера.
Там находится скриптinit_db.sql
, который используется для инициализации базы данных при первом старте контейнера.
- При запуске установите следующие переменные окружения контейнера в значение
-
Запустите контейнер
todo_bundle
в сетиtodo
из созданного вами образаtodo-bundle
, при этом:- Установите значение переменной среды
ConnectionStrings__PostgreSQL
в контейнере равной
Host=todo_postgres;Port=5432;Database=todo;Username=todo;Password=todo
. Можете выбрать другойHost
в этой строке, если вы назвали контейнер с PostgreSQL по-другому. Аналогично - и другие параметры. - Пробросьте порт 80 на хост-систему(например на порт 8080).
API-сервис работает на 80м порту по умолчанию, но это можно изменить, установив значение
переменнойASPNETCORE_URLS
например вhttp://*:5000
- тогда внутри контейнера сервис
будет слушать порт 5000.
Убедитесь, что приложение работает и доступно на выбранном вами порту на локальной машине.
При возникновении сложностей и необходимости отладки, вы можете также установить значение переменной
ASPNETCORE_ENVIRONMENT
вDevelopment
- таким образом сервис будет выдавать больше логов. - Установите значение переменной среды
-
Несмотря на то что API-сервис поддерживает хостинг
JavaScript
приложения, в реальном(или скорее, идеальном) мире
никто так не делает. Над интерфейсом и API часто работают разные команды, у них может быть разный график работы,
разное версионирование приложений, и тем более разные репозитарии, и разный подход к разработке.Кроме того, хотя
Kestrel
- хороший веб-сервер, все же раздача статических файлов - не основная его специализация.Поэтому, руководствуясь принципом разделения ответственности, вам необходимо разделить контейнеризацию
API-сервиса иJavaScript
приложения.Остановите контейнер
todo_bundle
, удалите его и образtodo-bundle
Модифицируйте
Dockerfile
для API-сервиса, таким образом, чтобы убрать из него все упоминаниеJavaScript
приложения
и его этапов сборки.Создайте образ
todo-api
на основе нового докер-файла.Напишите конфигурацию
Nginx
для использования его как в качестве обратного прокси для API-сервиса, так и для
раздачи файлов изwwwroot
, получаемой после сборкиJavaScript
приложения.
При этом:- Учтите, что все методы API-сервера имеют префикс
/api
- Не забудьте о том, что приложение на
JS
являетсяSPA
, и веб-сервер должен перенаправлять все нераспознанные пути
наindex.html
(используйте директивуtry_files
) - Содержимое
wwwroot
должно лежать в/var/www/todo
Напишите
Dockerfile
дляJavaScript
приложения, взяв за основу образnginx
.
При сборке образа копируйте написанную вами конфигурацию Nginx в/etc/nginx/nginx.conf
,
а результат сборкиJavaScript
приложения в/var/www/todo
.Создайте образ
todo-ui
из этого докер-файла - Учтите, что все методы API-сервера имеют префикс
-
Запустите в сети
todo
контейнерtodo_api
из образаtodo-api
, при этом:- Не забудьте про переменную среды
ConnectionStrings__PostgreSQL
. - Убедитесь что контейнер недоступен из внешней сети.
Запустите в сети
todo
контейнерtodo_ui
из образаtodo-ui
, при этом:- Пробросьте порт контейнера 80(или любой другой, который вы использовали при
написании конфигурации Nginx) на локальную машину(например, опять же на порт 8080)
Убедитесь что приложение доступно извне и работает.
- Не забудьте про переменную среды
-
Платформа
.NET
, на самом деле, позволяет собирать приложения, отвязанные от "внешней" предустановленной
среды выполнения.Хотя рекомендованный способ докеризации приложений на
.NET
- отталкиваться от образа сmcr.microsoft.com
, иногда возникает необходимость именно вself-contained
приложениях.Модифицируйте
Dockerfile
дляtodo-api
, следующим образом:- Поменяйте образ SDK для сборки на
mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
- Замените команду публикации приложения на
dotnet publish TodoApi.csproj --self-contained -r linux-x64 -c Release -o /app/publish
(замените/app/publish
на директорию которую использовали вы, если она у вас отличается) - Поменяйте результирующий исходный образ на
debian:bullseye-slim
- В образе
debian:bullseye-slim
не хватаетICU
, необходимого для запуска полноценного.NET
приложения.
Установитеlibicu
в этом образе при сборке:apt-get update && apt-get install libicu67
Пересоберите образ
todo-api
, и перезапустите контейнерtodo_api
на его основе, проверьте что всё работает. - Поменяйте образ SDK для сборки на
2. Политики перезапуска и базовый мониторинг
-
Запустите
todo_ui
,todo_api
иtodo_postgres
так, чтобы они перезапускались при ошибке или же
при перезапуске демона Docker.Перезапустите демон Docker, или же вообще, сделайте перезагрузку машины,
и проверьте что контейнеры запустились при старте Docker. -
Перезапустите контейнер
todo_postges
, так чтобы healthcheck:- Запускался командой
pg_isready -U todo -d todo
- Имел интервал 10 секунд
- Имел timeout 5 секунд
- Проверка имела бы до 5 попыток старта в случае неудачи
- Начиналась бы после 10 секунд после старта контейнера
- Запускался командой
3. Ограничение ресурсов
-
Перезапустите контейнеры
todo_ui
,todo_api
иtodo_postgres
, так они имели ограничение по памяти в
300, 500 и 800 мегабайт соответственно. Поэкспериментируйте с ограничениями и посмотрите что выходит,
в случае их превышения. -
Перезапустите контейнеры
todo_ui
,todo_api
иtodo_postgres
, так они имели ограничение по ресурсам процессора в
1, 1 и 2 соответственно
4. Docker Compose
-
Убедитесь что docker compose установлен, проверьте версию.
-
Напишите
docker-compose.yml
для контейнера на основеbusybox
, который бы печаталHello, World
при запуске. Запустите. -
Напишите конфигурацию compose для приложения
cats_app
.
Сделайте так, чтобы образcats_app
собирался, если его еще не существует.
Запустите приложение через docker compose, используя эту конфигурацию.
Убедитесь в том, что приложение работает. -
Напишите конфигурацию compose для вышеописанной системы todo. При этом:
- Добавьте туда как healthcheck, так и ограничения ресурсов описанные выше
- Сделайте так чтобы контейнер
todo_api
зависел отtodo_postgres
, аtodo_ui
- отtodo_api
.
Сделайте так, чтобы образыtodo-ui
иtodo-api
собирались, если они еще не существуют.
Запустите систему через docker compose, и убедитесь что все работает.
-
Добавьте контейнер из образа
dpage/pgadmin4:7
в compose файл к вышеописанной системе, так чтобы он подключался кPostgreSQL
и позволял смотреть данные приложенияtodo
.
При этом установите следующие переменные среды в контейнере в соответствующие значения:PGADMIN_DEFAULT_EMAIL
=todo@example.com
PGADMIN_DEFAULT_PASSWORD
=todo
PGADMIN_CONFIG_SERVER_MODE
=False