You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

17 KiB

Задания

1. Многоступенчатая сборка образов

В полученной вами директории todo_app находятся исходные коды Enterprise Quality™® системы для менеджмента напоминаний.

Она состоит из следующих частей:

  • TodoApi - API-сервис, на платформе .NET 7.
  • todo_ui - веб-интерфейс к этому сервису, Single-Page JavaScript приложение(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 ...).

Задачи.

  1. Напишите Dockerfile, из которого можно было бы создать образ, который отвечал бы следующим требованиям:

    • Образ должен основываться на образе mcr.microsoft.com/dotnet/aspnet:7.0
    • Готовое приложение API-сервиса вместе с зависимостями должно находиться в директории /app
    • JavaScript приложение должно находиться в директории /app/wwwroot
    • При старте контейнера из такого образа, должен запускаться приложение API-сервиса.

    Документация по многоступенчатой сборке образов находится тут: https://docs.docker.com/build/building/multi-stage/

  2. Создайте образ из полученного Dockerfile и назовите его todo-bundle

  3. Перед запуском самого приложения, необходимо запустить и подготовить PostgreSQL в сети todo.

    Создайте именованную сеть типа bridge, в которой будет работать вся система, назовите ее todo.

    Создайте том данных, в котором PostgreSQL будет хранить БД. Назовите его todo_pgdata.

    Запустите именованный контейнер 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 внутри контейнера.
      Там находится скрипт init_db.sql, который используется для инициализации базы данных при первом старте контейнера.
  4. Запустите контейнер 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 - таким образом сервис будет выдавать больше логов.

  5. Несмотря на то что 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 из этого докер-файла

  6. Запустите в сети todo контейнер todo_api из образа todo-api, при этом:

    • Не забудьте про переменную среды ConnectionStrings__PostgreSQL.
    • Убедитесь что контейнер недоступен из внешней сети.

    Запустите в сети todo контейнер todo_ui из образа todo-ui, при этом:

    • Пробросьте порт контейнера 80(или любой другой, который вы использовали при
      написании конфигурации Nginx) на локальную машину(например, опять же на порт 8080)

    Убедитесь что приложение доступно извне и работает.

  7. Платформа .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 на его основе, проверьте что всё работает.

2. Политики перезапуска и базовый мониторинг

  1. Запустите todo_ui, todo_api и todo_postgres так, чтобы они перезапускались при ошибке или же
    при перезапуске демона Docker.

    Перезапустите демон Docker, или же вообще, сделайте перезагрузку машины,
    и проверьте что контейнеры запустились при старте Docker.

  2. Перезапустите контейнер todo_postges, так чтобы healthcheck:

    • Запускался командой pg_isready -U todo -d todo
    • Имел интервал 10 секунд
    • Имел timeout 5 секунд
    • Проверка имела бы до 5 попыток старта в случае неудачи
    • Начиналась бы после 10 секунд после старта контейнера

3. Ограничение ресурсов

  1. Перезапустите контейнеры todo_ui, todo_api и todo_postgres, так они имели ограничение по памяти в
    300, 500 и 800 мегабайт соответственно. Поэкспериментируйте с ограничениями и посмотрите что выходит,
    в случае их превышения.

  2. Перезапустите контейнеры todo_ui, todo_api и todo_postgres, так они имели ограничение по ресурсам процессора в
    1, 1 и 2 соответственно

4. Docker Compose

  1. Убедитесь что docker compose установлен, проверьте версию.

  2. Напишите docker-compose.yml для контейнера на основе busybox, который бы печатал Hello, World при запуске. Запустите.

  3. Напишите конфигурацию compose для приложения cats_app.
    Сделайте так, чтобы образ cats_app собирался, если его еще не существует.
    Запустите приложение через docker compose, используя эту конфигурацию.
    Убедитесь в том, что приложение работает.

  4. Напишите конфигурацию compose для вышеописанной системы todo. При этом:

    • Добавьте туда как healthcheck, так и ограничения ресурсов описанные выше
    • Сделайте так чтобы контейнер todo_api зависел от todo_postgres, а todo_ui - от todo_api.
      Сделайте так, чтобы образы todo-ui и todo-api собирались, если они еще не существуют.
      Запустите систему через docker compose, и убедитесь что все работает.
  5. Добавьте контейнер из образа dpage/pgadmin4:7 в compose файл к вышеописанной системе, так чтобы он подключался к PostgreSQL
    и позволял смотреть данные приложения todo.
    При этом установите следующие переменные среды в контейнере в соответствующие значения:

    • PGADMIN_DEFAULT_EMAIL = todo@example.com
    • PGADMIN_DEFAULT_PASSWORD = todo
    • PGADMIN_CONFIG_SERVER_MODE = False

5. Docker Swarm