Files
LMS/deploy/DEPLOY.md

10 KiB
Raw Blame History

Деплой LMS на сервер lms.our-place.ru

Стек целиком запускается в Docker. Java на сервере не устанавливается — приложение собирается и работает внутри контейнеров (multi-stage Dockerfile: сборка на JDK 21, запуск на JRE 21).

Компоненты:

Сервис Контейнер Наружу
web (Thymeleaf UI) lms-web 127.0.0.1:8090 (проксирует nginx)
gateway lms-gateway нет
identity / academic / progress lms-* нет
PostgreSQL 18 lms-postgres нет

Данные лежат в именованных volume: lms_pgdata (БД), lms_submissions (решения), lms_assets (картинки материалов).


0. Что нужно

  • Сервер с Ubuntu 22.04/24.04 (или другим Linux с Docker), sudo/root.
  • Домен lms.our-place.ru, A-запись которого указывает на IP сервера.
  • Открытые порты 80 и 443 (443 — если настраиваете HTTPS).

1. Установка Docker

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"   # перелогиньтесь, чтобы работать без sudo
docker compose version            # нужна версия v2

2. Получить код

sudo mkdir -p /opt/lms && sudo chown "$USER" /opt/lms
git clone <URL-репозитория> /opt/lms
cd /opt/lms

3. Настроить окружение

cp .env.prod.example .env.prod
nano .env.prod

Обязательно задайте LMS_DB_PASSWORD и LMS_INTERNAL_TOKEN. Остальные значения по умолчанию подходят.

LMS_INTERNAL_TOKEN — общий секрет для внутренних вызовов identity из academic/progress (профиль студента, состав группы). Сгенерируйте длинную случайную строку (например, openssl rand -hex 32) и укажите её в .env.prod. Compose передаёт одно и то же значение identity, academic и progress. Значение по умолчанию dev-internal-token для production не используйте; .env.prod не коммитьте.

Сроки аутентификации и сессии (можно не задавать — действуют значения ниже):

LMS_ACCESS_TOKEN_TTL=15m       # access JWT identity, короткий
LMS_REFRESH_TOKEN_TTL=7d       # refresh-токен, ротация и отзыв
LMS_SESSION_TIMEOUT=7d         # web-сессия LMS_SESSION, sliding

LMS_ACCESS_TOKEN_TTL и LMS_REFRESH_TOKEN_TTL читает identity, LMS_SESSION_TIMEOUT — web. docker-compose.prod.yml прокидывает эти переменные в environment соответствующих сервисов; при переопределении используются значения из .env.prod. Access обновляется автоматически за 2 минуты до истечения; прямой API-клиент должен сам вызывать POST /api/v1/auth/refresh. Уменьшайте значения только осознанно: слишком короткая web-сессия заставит пользователей чаще входить заново.

4. Собрать и запустить

./deploy/deploy.sh up

Скрипт соберёт образы (первый раз ~5–15 минут: скачиваются Gradle и зависимости) и поднимет контейнеры. Проверка:

docker compose -f docker-compose.prod.yml --env-file .env.prod ps
curl -fsS http://127.0.0.1:8090/actuator/health   # {"status":"UP",...}

5. Nginx + HTTPS

sudo apt-get update && sudo apt-get install -y nginx certbot python3-certbot-nginx
sudo mkdir -p /var/www/certbot

sudo cp deploy/nginx/lms.our-place.ru.conf /etc/nginx/sites-available/lms.our-place.ru.conf
sudo ln -sf /etc/nginx/sites-available/lms.our-place.ru.conf /etc/nginx/sites-enabled/lms.our-place.ru.conf
sudo rm -f /etc/nginx/sites-enabled/default

sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d lms.our-place.ru --redirect -m admin@our-place.ru --agree-tos

certbot --nginx сам добавит TLS-блок и редирект с HTTP на HTTPS. Автопродление уже настроено пакетом (systemctl status certbot.timer).

6. Первый запуск приложения

Откройте https://lms.our-place.ru → откроется /setup → создайте администратора.

6a. Наполнение данными

Дальше всё через интерфейс: импорт групп (.xls), импорт лабораторной ZIP'ом, раздача вариантов, оценки и защита, материалы. Подробный порядок с проверками — в IMPORT.md. Файлы со списками студентов и выгрузками паролей — персональные данные, держите их вне репозитория.

7. Обновление версии

cd /opt/lms
git pull
./deploy/deploy.sh up        # backup → сборка → миграции → перезапуск

deploy.sh up обязательно делает backup перед обновлением. Если backup завершился ошибкой, деплой прерывается. Миграции БД (Flyway) применяются автоматически при старте сервисов: identity V4–V11 (V10 создаёт identity.audit_events, V11 — identity.refresh_tokens), academic V6–V12, progress V13.

После обновления проверьте, что админ открывает /admin/audit и видит события (например, после входа в профиль студента — PROFILE_VIEW); преподаватель и студент на эту страницу не попадают. Журнал листается через page/limit («Показать ещё»). Для инвентаризации старых файлов админ может вызвать GET /api/v1/content/legacy-assets: файлы без привязки к статье больше не публичны (404 для обычных пользователей), их нужно привязать или удалить.

CI (.gitlab-ci.yml) на каждом push/MR выполняет ./gradlew --no-daemon test ktlintCheck detekt evidenceCheck и job smoke (./scripts/ldd-smoke.sh: полный стек, health, вход админа, один курс). Полный job release-evidence (./scripts/ldd-release.sh) обязателен для тегов и запускается вручную для веток. check использует privileged docker:dind для Testcontainers; smoke/release-evidence выполняются на shell-runner с Java 21, Docker Compose v2, Python 3, Node и Chromium Playwright.

8. Резервное копирование

Полная инструкция — BACKUP.md. Кратко:

./deploy/backup.sh backup          # БД + решения + материалы
./deploy/backup.sh list
./deploy/backup.sh verify <dir>
./deploy/backup.sh restore <dir>   # destructive, требует ввода RESTORE

Backup включает pg_dump БД, volume решений и volume материалов, контрольные суммы и manifest. По умолчанию хранится 14 дней (LMS_BACKUP_KEEP_DAYS), каталог — /opt/lms/backups (LMS_BACKUP_DIR).

Ежедневное расписание:

sudo cp deploy/systemd/lms-backup.service deploy/systemd/lms-backup.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now lms-backup.timer

Backup на том же сервере — не единственная защита: настройте выгрузку на отдельный хост и периодически проверяйте восстановление на staging.

9. Диагностика

./deploy/deploy.sh ps
./deploy/deploy.sh logs web
./deploy/deploy.sh logs gateway
./deploy/deploy.sh logs identity

Типичные проблемы:

  • web отдаёт 502 через nginx — контейнер web не поднялся: смотрите logs web. Часто причина — занят порт 8090 или не задан LMS_DB_PASSWORD (compose не стартует).
  • Страница входа открывается, но запросы падают — проверьте logs gateway и logs identity; gateway должен получить JWKS от identity.
  • 401 на страницах после входа (Docker) — у backend-сервисов не задан адрес JWKS: должно быть LMS_JWT_JWK_SET_URI=http://identity:8081/api/v1/auth/jwks.json (уже прописано в docker-compose.prod.yml для academic/progress/gateway). Внутри контейнера localhost:8081 недоступен, поэтому токен не проверяется.
  • 403/502 в профиле студента или составе группы — проверьте, что LMS_INTERNAL_TOKEN задан в .env.prod и одинаков у identity, academic и progress. При неверном внутреннем токене identity отвечает 403.
  • Не проходят загрузки больших ZIP — увеличьте client_max_body_size в nginx (сейчас 120 МБ) и spring.servlet.multipart.max-request-size.

Замечания по безопасности

  • PostgreSQL наружу не публикуется; связь между контейнерами — по внутренней сети lms.
  • Публикуется только 127.0.0.1:8090, доступ снаружи — исключительно через nginx/TLS.
  • .env.prod содержит пароль БД и не коммитится (в .gitignore).
  • Пароль администратора задаётся вами на шаге 6; хранение — BCrypt.