m2/08/tasks refactoring of p.1

pull/3/head
Dmitry Ignatiev 12 months ago
parent b6183c62fb
commit 9f498642b2

@ -5,22 +5,36 @@
В полученной вами директории `todo_app` находятся исходные коды Enterprise Quality™® системы для менеджмента напоминаний.
Она состоит из следующих частей:
- `TodoApi` - API-сервис, на платформе `.NET 7`.
- `todo_ui` - веб-интерфейс к этому сервису, Single-Page `JavaScript` приложение(`SPA`), написанное с использованием `Vue.js 3`.
- API-сервис использует `PostgreSQL` для хранения данных.
- `TodoApi` - API-сервис, на платформе `.NET 7`,
- `todo_ui` - веб-интерфейс к этому сервису, Single-Page `JavaScript` приложение(`SPA`), написанное с использованием `Vue.js 3`,
- `PostgreSQL` - API-сервис использует `PostgreSQL` для хранения данных.
Необходимо будет контейнеризировать эту систему.
Сервис TodoApi имеет следующие шаги сборки:
#### 1 Контейнеризация приложения
- Во-первых, для его сборки необходим .NET 7 SDK
- Далее, из директории, в которой находятся исходные коды сервиса(см. `todo_app/TodoApi`), \
##### 1.1 Подготовка образа для `TodoApi` и `todo_ui`
Используя подход к многоступенчатой сборке образов, напишите `Dockerfile`, из которого можно было бы создать образ, \
и который отвечал бы следующим требованиям:
- Фаза сборки API-сервиса должна использовать образ `mcr.microsoft.com/dotnet/sdk:7.0`
- Фаза сборки `JavaScript` приложения должна использовать образ `node:21`
- Результирующий образ должен основываться на `mcr.microsoft.com/dotnet/aspnet:7.0`
- Готовое приложение API-сервиса вместе с зависимостями должно находиться в директории `/app`
- `JavaScript` приложение должно находиться в директории `/app/wwwroot`
- При старте контейнера из такого образа, должно запускаться приложение API-сервиса.
Документация по многоступенчатой сборке образов находится тут: https://docs.docker.com/build/building/multi-stage/.
Фаза сборки сервиса `TodoApi` состоит из следующих шагов:
- Во-первых, для его сборки необходим .NET 7 SDK
- Далее, из директории, в которой находятся исходные коды сервиса(см. `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`).
@ -30,8 +44,7 @@
Запуск осуществляется вызовом исполняемого файла `./TodoApi` из директории, которая хранит опубликованные \
бинарные файлы сервиса и его зависимостей.
`JavaScript` приложение собирается следующим образом:
Фаза сборки `JavaScript` приложения состоит из следующих шагов:
- Прежде всего, необходим `NodeJS` - в данном случае подойдет версия `21`.
- Далее, из директории, в которой находятся исходные коды приложения(см. `todo_app/todo_ui`), \
нужно вызывать `npm install` - это команда скачает зависимости приложения.
@ -45,108 +58,110 @@
Для хостинга JS-приложения в API-сервисе, необходимо всего лишь скопировать упомянутую выше директорию \
`wwwroot` внутрь результирующей директории API-сервиса(которая получается после выполнения `dotnet publish ...`).
#### Задачи.
1. Напишите `Dockerfile`, из которого можно было бы создать образ, и который отвечал бы следующим требованиям:
- Фаза сборки API-сервиса должна использовать образ `mcr.microsoft.com/dotnet/sdk:7.0`
- Фаза сборки `JavaScript` приложения должна использовать образ `node:21`
- Результирующий образ должен основываться на `mcr.microsoft.com/dotnet/aspnet:7.0`
- Готовое приложение API-сервиса вместе с зависимостями должно находиться в директории `/app`
- `JavaScript` приложение должно находиться в директории `/app/wwwroot`
- При старте контейнера из такого образа, должен запускаться приложение API-сервиса.
Документация по многоступенчатой сборке образов находится тут: https://docs.docker.com/build/building/multi-stage/
Создайте образ из полученного `Dockerfile` и назовите его `todo-bundle`.
2. Создайте образ из полученного `Dockerfile` и назовите его `todo-bundle`
##### 1.2 Подготовка образа PostgreSQL
3. Перед запуском самого приложения, необходимо запустить и подготовить `PostgreSQL` в сети `todo`.
Перед запуском самого приложения, необходимо запустить и подготовить `PostgreSQL` в сети `todo`.
Создайте именованную сеть типа `bridge`, в которой будет работать вся система, назовите ее `todo`.
Создайте именованную сеть типа `bridge`, в которой будет работать вся система, назовите ее `todo`.
Создайте том данных, в котором `PostgreSQL` будет хранить БД. Назовите его `todo_pgdata`.
Создайте том данных, в котором `PostgreSQL` будет хранить БД. Назовите его `todo_pgdata`.
Запустите именованный контейнер `todo_postgres` из образа `postgres:16`, при этом:
1. При запуске установите следующие переменные окружения контейнера в значение `todo`:
Запустите именованный контейнер `todo_postgres` из образа `postgres:16`, при этом:
1. При запуске установите следующие переменные окружения контейнера в значение `todo`:
- `POSTGRES_DB` - имя базы данных, к которой будет обращаться API-сервис
- `POSTGRES_USER` - пользователь БД, через которого будет работать сервис
- `POSTGRES_PASSWORD` - пароль для пользователя
2. Установите значение переменной среды `PGDATA` в значение `/var/lib/postgresql/data` - здесь `PostgreSQL` будет хранить данные.
3. Примонтируйте том данных `todo_pgdata` в качестве директории `/var/lib/postgresql/data`.
4. Примонтируйте директорию `initdb` из `todo_app` в качестве директории `/docker-entrypoint-initdb.d` внутри контейнера. \
2. Установите значение переменной среды `PGDATA` в значение `/var/lib/postgresql/data` - здесь `PostgreSQL` будет хранить данные.
3. Примонтируйте том данных `todo_pgdata` в качестве директории `/var/lib/postgresql/data`.
4. Примонтируйте директорию `initdb` из `todo_app` в качестве директории `/docker-entrypoint-initdb.d` внутри контейнера. \
Там находится скрипт `init_db.sql`, который используется для инициализации базы данных при первом старте контейнера.
4. Запустите контейнер `todo_bundle` в сети `todo` из созданного вами образа `todo-bundle`, при этом:
- Установите значение переменной среды `ConnectionStrings__PostgreSQL` в контейнере равной \
##### 1.3 Проверка работоспособности контейнеризованного приложения
Запустите контейнер `todo_bundle` в сети `todo` из созданного вами образа `todo-bundle`, при этом:
- Установите значение переменной среды `ConnectionStrings__PostgreSQL` в контейнере равной \
`Host=todo_postgres;Port=5432;Database=todo;Username=todo;Password=todo`.
Можете выбрать другой `Host` в этой строке, если вы назвали контейнер с PostgreSQL по-другому.
Аналогично - и другие параметры.
- Пробросьте порт 80 на хост-систему(например на порт 8080). \
- Пробросьте порт 80 на хост-систему(например на порт 8080). \
API-сервис работает на 80м порту по умолчанию, но это можно изменить, установив значение \
переменной `ASPNETCORE_URLS` например в `http://*:5000` - тогда внутри контейнера сервис \
будет слушать порт 5000.
Убедитесь, что приложение работает и доступно на выбранном вами порту на локальной машине.
Убедитесь, что приложение работает и доступно на выбранном вами порту на локальной машине.
При возникновении сложностей и необходимости отладки, вы можете также установить значение переменной \
`ASPNETCORE_ENVIRONMENT` в `Development` - таким образом сервис будет выдавать больше логов.
При возникновении сложностей и необходимости отладки, вы можете также установить значение переменной \
`ASPNETCORE_ENVIRONMENT` в `Development` - таким образом сервис будет выдавать больше логов.
#### 2 Рефакторинг контейнеризованного приложения
5. Несмотря на то что API-сервис поддерживает хостинг `JavaScript` приложения, в реальном(или скорее, идеальном) мире \
никто так не делает. Над интерфейсом и API часто работают разные команды, у них может быть разный график работы, \
разное версионирование приложений, и тем более разные репозитарии, и разный подход к разработке.
##### 1.1 Декомпозиция образа `todo-bundle`
Кроме того, хотя `Kestrel` - хороший веб-сервер, все же раздача статических файлов - не основная его специализация.
Несмотря на то что API-сервис поддерживает хостинг `JavaScript` приложения, в реальном(или скорее, идеальном) мире \
никто так не делает. Над интерфейсом и API часто работают разные команды, у них может быть разный график работы, \
разное версионирование приложений, и тем более разные репозитарии, и разный подход к разработке.
Поэтому, руководствуясь принципом разделения ответственности, вам необходимо разделить контейнеризацию \
API-сервиса и `JavaScript` приложения.
Кроме того, хотя `Kestrel` - хороший веб-сервер, все же раздача статических файлов - не основная его специализация.
Остановите контейнер `todo_bundle`, удалите его и образ `todo-bundle`
Поэтому, руководствуясь принципом разделения ответственности, вам необходимо разделить контейнеризацию \
API-сервиса и `JavaScript` приложения.
Модифицируйте `Dockerfile` для API-сервиса, таким образом, чтобы убрать из него все упоминание `JavaScript` приложения \
и его этапов сборки.
Остановите контейнер `todo_bundle`, удалите его и образ `todo-bundle`
Создайте образ `todo-api` на основе нового докер-файла.
Модифицируйте `Dockerfile` для API-сервиса, таким образом, чтобы убрать из него все упоминание `JavaScript` приложения \
и его этапов сборки.
Напишите конфигурацию `Nginx` для использования его как в качестве обратного прокси для API-сервиса, так и для \
раздачи файлов из `wwwroot`, получаемой после сборки `JavaScript` приложения. \
При этом:
- Учтите, что все методы API-сервера имеют префикс `/api`
- Не забудьте о том, что приложение на `JS` является `SPA`, и веб-сервер должен перенаправлять все нераспознанные пути \
Создайте образ `todo-api` на основе нового докер-файла.
Напишите конфигурацию `Nginx` для использования его как в качестве обратного прокси для API-сервиса, так и для \
раздачи файлов из `wwwroot`, получаемой после сборки `JavaScript` приложения. \
При этом:
- Учтите, что все методы API-сервера имеют префикс `/api`
- Не забудьте о том, что приложение на `JS` является `SPA`, и веб-сервер должен перенаправлять все нераспознанные пути \
на `index.html` (используйте директиву `try_files`)
- Содержимое `wwwroot` должно лежать в `/var/www/todo`
- Содержимое `wwwroot` должно лежать в `/var/www/todo`
Напишите `Dockerfile` для `JavaScript` приложения, взяв за основу образ `nginx`. \
При сборке образа копируйте написанную вами конфигурацию Nginx в `/etc/nginx/nginx.conf`, \
а результат сборки `JavaScript` приложения в `/var/www/todo`.
Напишите `Dockerfile` для `JavaScript` приложения, взяв за основу образ `nginx`. \
При сборке образа копируйте написанную вами конфигурацию Nginx в `/etc/nginx/nginx.conf`, \
а результат сборки `JavaScript` приложения в `/var/www/todo`.
Создайте образ `todo-ui` из этого докер-файла.
Создайте образ `todo-ui` из этого докер-файла
##### 1.2 Проверка работоспособности контейнеризованного приложения
6. Запустите в сети `todo` контейнер `todo_api` из образа `todo-api`, при этом:
- Не забудьте про переменную среды `ConnectionStrings__PostgreSQL`.
- Убедитесь что контейнер недоступен из внешней сети.
Запустите в сети `todo` контейнер `todo_api` из образа `todo-api`, при этом:
- Не забудьте про переменную среды `ConnectionStrings__PostgreSQL`.
- Убедитесь что контейнер недоступен из внешней сети.
Запустите в сети `todo` контейнер `todo_ui` из образа `todo-ui`, при этом:
- Пробросьте порт контейнера 80(или любой другой, который вы использовали при \
Запустите в сети `todo` контейнер `todo_ui` из образа `todo-ui`, при этом:
- Пробросьте порт контейнера 80(или любой другой, который вы использовали при \
написании конфигурации Nginx) на локальную машину(например, опять же на порт 8080)
Убедитесь что приложение доступно извне и работает.
Убедитесь что приложение доступно извне и работает.
7. Платформа `.NET`, на самом деле, позволяет собирать приложения, отвязанные от "внешней" предустановленной \
##### 1.3 Рефакторинг образа `todo-api`
Платформа `.NET`, на самом деле, позволяет собирать приложения, отвязанные от "внешней" предустановленной \
среды выполнения.
Хотя рекомендованный способ докеризации приложений на `.NET` - отталкиваться от образа с `mcr.microsoft.com`,
иногда возникает необходимость именно в `self-contained` приложениях.
Хотя рекомендованный способ докеризации приложений на `.NET` - отталкиваться от образа с `mcr.microsoft.com`,
иногда возникает необходимость именно в `self-contained` приложениях.
Модифицируйте `Dockerfile` для `todo-api`, следующим образом:
- Поменяйте образ SDK для сборки на `mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim`
- Замените команду публикации приложения на \
Модифицируйте `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` приложения. \
- Поменяйте результирующий исходный образ на `debian:bullseye-slim`
- В образе `debian:bullseye-slim` не хватает `ICU`, необходимого для запуска полноценного `.NET` приложения. \
Установите `libicu` в этом образе при сборке: `apt-get update && apt-get install libicu67`
Пересоберите образ `todo-api`, и перезапустите контейнер `todo_api` на его основе, проверьте что всё работает.
##### 1.4 Проверка работоспособности контейнеризованного приложения
Пересоберите образ `todo-api`, и перезапустите контейнер `todo_api` на его основе, проверьте что всё работает.
### 2. Политики перезапуска и базовый мониторинг

Loading…
Cancel
Save