Skip to main content
Version: Next

Развёртывание

Деплой через Makefile

# Первый раз: сгенерировать пароли
make generate-passwords

# Деплой всего стека (QMServer, QMAdmin, QMWeb, QMDocs)
make deploy

Синхронизация каталогов проекта на сервер в $(DEPLOY_PATH) (по умолчанию /opt/qmserver) выполняется через rsync с --delete: файлы и папки, которые вы удалили в репозитории, удаляются и на хосте (внутри зеркалируемого дерева). Исключение — копирование конфигов в /etc/nginx/: там --delete не используется, чтобы не трогать сторонние файлы в conf.d и sites-available.

QMServer в Docker: образ ghcr.io/<GHCR_OWNER>/qmserver, подставляется из .env.cloud / .env (GHCR_OWNER — владелец пакетов на GitHub). При таргете make deploy на сервер зеркалируются исходники QMServer/ (и др.) для отладки и Swagger, а контейнер qmserver поднимается с уже собранного образа (make build-all-cloud делает pull для QMServer и build для QMAdmin/QMWeb/QMDocs). Платформа образа — Linux x86_64 (amd64) (platform: linux/amd64).

Локальный стек в Docker: docker-compose.yaml → по умолчанию ghcr.io/<GHCR_OWNER>/qmserver:latest.

Без Docker: один исполняемый qmserver и systemd — см. QMServer — Запуск и deploy/systemd/ в репозитории QMServer. Сценарий install.sh (нативно или Docker Compose): QMServer.

Репозиторий mindevis/QMServer — см. BUILD.md. Образы GHCR: ghcr.io/<owner>/qmserver:latest (и теги по SHA в CI).

Только QMAdmin без монорепозитория: образ ghcr.io/<owner>/qmadmin, релизы со статикой qmadmin-*-dist.tar.gz, сценарий install.sh (QMAdmin) — репозиторий mindevis/QMAdmin.

Только QMWeb без монорепозитория: образ ghcr.io/<owner>/qmweb, релизы qmweb-*-dist.tar.gz, install.sh (QMWeb)mindevis/QMWeb.

Отдельные цели deploy-qmadmin, deploy-qmweb, deploy-qmserver, deploy-qmdocs, deploy-images используют тот же принцип для своих деревьев под DEPLOY_PATH.

QMDocs — статический сайт: в каталоге QMDocs выполняется npm ci (или npm install) и npm run build; артефакты каталога build/ отдаются через Nginx на хосте (порт 8243 в таблице ниже). Документация открыта без входа; /login и /licensing используют QMSERVER_API_URL на этапе сборки (customFields.qmserverApiUrl / переменная окружения при docusaurus build). Для Kubernetes используйте образ со статикой, например ghcr.io/<owner>/qmdocs:<tag>, собранный из Dockerfile в репозитории QMDocs — в Helm-чарте QMDeploy задайте образ и хосты через values.yaml (см. репозиторий QMDeploy).

Pro без «вечного» env: опционально QMSERVER_LICENSE_PUBLIC_KEY (hex публичного ключа) и активация токена в QMAdmin; выпуск токена — QMSERVER_LICENSE_ISSUER_SEED только на площадке продавца — см. Лицензия Pro.

Фронтенды QMAdmin и QMWeb (Vite): базовый URL API задаётся переменной QMSERVER_API_URL на этапе npm run build / docker build (вшивается в статику). В docker-compose.cloud.yaml в оба образа передаётся build-arg QMSERVER_API_URL=${QMSERVER_PUBLIC_URL}/api/v1 (см. env.cloud.example). Локально — файлы .env в каталогах QMAdmin и QMWeb (образцы: .env.example). В vite.config у обоих приложений указано envPrefix: ['VITE_', 'QMSERVER_'], поэтому QMSERVER_* и прежние VITE_* (например ссылки QMClient, лаунчер в QMWeb) доступны в import.meta.env.

Стек согласован так: QMAdmin, QMWeb и (при облачных настройках) QMLauncher обращаются к QMServer по одному базовому URL API. После развёртывания в QMAdmin обычно включают нужные модули и интеграции (QMLauncher, QMWeb). Иначе часть API для клиентов будет недоступна (см. QMServer). Синхронизация инвентаря (POST /api/v1/inventory, QXSync, coming soon) на QMServer действует при модуле Minecraft и интеграции QMWeb — см. Синхронизация инвентаря. В env.cloud.example кратко описаны флаги по умолчанию.

Компоненты на сервере

СервисПортДомен
QMServer8240api.qx-dev.ru
QMAdmin8241admin.qx-dev.ru
QMWeb8242web.qx-dev.ru
QMDocs8243qm.qx-dev.ru
Nginx (на хосте)80, 443Reverse proxy → 127.0.0.1:8240–8243

Nginx (на хосте)

Nginx устанавливается на хост, не в Docker. При деплое конфиги из nginx/sites-available/ копируются в /etc/nginx/sites-available/, в /etc/nginx/sites-enabled/ создаются симлинки на них.

  • api.qx-dev.ru.conf → 127.0.0.1:8240
  • admin.qx-dev.ru.conf → 127.0.0.1:8241
  • web.qx-dev.ru.conf → 127.0.0.1:8242
  • qm.qx-dev.ru.conf → 127.0.0.1:8243

Kubernetes (K3s)

Развёртывание в кластере (K3s или любой Kubernetes) — репозиторий QMDeploy: чарт qm-project, единая утилита scripts/k8s-manage.py (подкоманды bootstrap / secrets / addons). От root: README.md. Bootstrap ставит K3s, Helm, опционально секреты и Argo CD + Application qm (GitOps, values-argocd.yaml). Прямой Helm: bootstrap --direct-helm. В рабочей копии qm-project каталог QMDeploy/ — отдельный клон репозитория QMDeploy (рядом с корнем монорепо). Пути kubectl apply / render.py / migrate-from-kubectl не поддерживаются.

Кратко:

  1. Клонируйте QMDeploy (или откройте QMDeploy/ в монорепо).
  2. От root: файл /root/.ghcr-credentials (одна строка — PAT для ghcr.io, пользователь по умолчанию mindevis), затем python3 scripts/k8s-manage.py создаёт qm-mysql/qm-app, ghcr-credentials и при необходимости Argo — см. QMDeploy/README.md. Ручные секреты / --dry-run: k8s-manage.py secrets.
  3. Домены и образы — values-argocd.yaml. Прямой Helm: --direct-helm (см. README QMDeploy).

GRAFANA_ADMIN_PASSWORD и др. — qm-app / values.

Подробности — QMDeploy/README.md.

Массовая выгрузка модов (QMAdmin → API)

QMAdmin шлёт массовую загрузку несколькими POST: в каждом запросе суммарный размер файлов в пачке не превышает ~50 МиБ (один файл больше 50 МиБ уходит отдельным запросом). Так проще обойти лимиты Cloudflare (~100 МБ на один запрос на обычных тарифах) и не раздувать client_max_body_size у прокси до сотен мегабайт.

Конфиг nginx/sites-available/api.qx-dev.ru.conf в монорепозитории — для Nginx на отдельной ВМ перед локальным QMServer (127.0.0.1:8240). В K3s этот файл не применяется автоматически: наружу смотрит Ingress (часто Traefik). Обычно дополнительный Traefik Middleware под гигантские POST не нужен; если перед кластером всё же стоит nginx с дефолтом 1m, выставьте client_max_body_size хотя бы 64m и адекватные таймауты чтения тела.

Cloudflare на api-имени: каждый POST остаётся ниже типичного лимита ~100 МБ на запрос; отдельный очень большой .jar в одном POST может снова упереться в лимит CF — тогда DNS-only для API или обход CF.

Если перед кластером свой Nginx (DNS → Nginx → NodePort/Ingress): используйте вариант api.qx-dev.ru.conf из репозитория (подставьте proxy_pass на вход в K3s), nginx -t, systemctl reload nginx.

Синхронизация с GitHub без полного клона (sync-from-github.py)

Скрипт QMDeploy/scripts/sync-from-github.py скачивает в кэш (по умолчанию /opt/qm у root, иначе ~/.cache/qm) чарт qm-project, файл VERSION и скрипты из QMDeploy. Переменные: QM_HELM_BASE_URL, QM_DEPLOY_BASE_URL, QM_HELM_CACHE, QM_DEPLOY_ROOT. Затем на сервере от root обычно python3 …/k8s-manage.py (GitOps) или helm upgrade --install с путём к чарту в кэше (bootstrap --direct-helm).

Argo CD и MinIO S3 (Helm)

Argo CD ставится bootstrap-ом k8s-manage.py (внутри — установщик Argo + Application). MinIO: QMDeploy/scripts/k8s-manage.py addons --s3 или --argocd --s3. Нужны Helm и kubectl. Домен UI Argo: k3s.qx-dev.ru (--argocd-host). Значения: QMDeploy/helm/argocd/values-k3s.yaml.

Опционально: мониторинг (Grafana и Prometheus)

В чарте qm-project поддерживается стек Grafana + Prometheus. В пути GitOps (values-argocd.yaml) по умолчанию monitoring.enabled: false — поды мониторинга не создаются. Чтобы включить: monitoring.enabled: true в Git (коммит в QMDeploy) или параметры Application в Argo, затем Sync; в Secret qm-appGRAFANA_ADMIN_PASSWORD. Ingress Grafana по умолчанию — monit.qx-dev.ru. Локально без k8s: docker-compose.monitoring.yml в QMDeploy.

Версионирование

В QMDeploy: VERSION (semver бандла), helm/qm-project/Chart.yaml (version, appVersion) — согласуются при релизе.

Обновление образов (например QMWeb)

# По умолчанию GitOps: imageTag=latest, images.* пустые (см. values-argocd.yaml).
helm upgrade qm ./helm/qm-project -n qm --reuse-values --set imageTag=latest
# Пин одного сервиса (редко):
helm upgrade qm ./helm/qm-project -n qm --reuse-values --set images.qmweb=ghcr.io/<GHCR_OWNER>/qmweb:<тег>

Образы должны быть доступны в реестре (для приватного GHCR — pull-secret на ноде).

Релизы QMWeb и текст из CHANGELOG на GitHub

В репозитории QMWeb workflow CI подставляет в описание GitHub Release содержимое секции ## [<версия>] из CHANGELOG.md (номер совпадает с package.json) при релизе по git-тегу vX.Y.Z. Релиз со статикой не создаётся от push в main (только образ в GHCR). Автогенерация заметок только по коммитам для этого шага отключена. Подробнее — QMWeb/CHANGELOG.md и .github/workflows/build-qmweb-image.yml.

DNS

Настроить A-записи для доменов на IP сервера:

  • api.qx-dev.ru
  • admin.qx-dev.ru
  • web.qx-dev.ru
  • qm.qx-dev.ru
  • monit.qx-dev.ru (опционально Grafana, если monitoring.enabled в Helm QMDeploy)
  • k3s.qx-dev.ru (Argo CD при стандартном k8s-manage.py (bootstrap); только MinIO — см. k8s-manage.py addons)

Swagger / ReDoc

Документация API доступна по адресам:

SSL и CloudFlare

Nginx настроен для работы с CloudFlare:

  • Редирект HTTP → HTTPS
  • Real IP из заголовка CF-Connecting-IP
  • Gzip сжатие
  • Кэширование статики (JS, CSS, изображения)

Сертификаты Let's Encrypt в /etc/letsencrypt/live/DOMAIN/:

  • fullchain.pem, privkey.pem

Выпустите сертификаты заранее (certbot) для каждого домена. В каждом конфиге указан путь по имени домена.

Ely.by OAuth (привязка аккаунта Ely.by)

Для использования скинов Ely.by пользователям нужно привязать аккаунт Ely.by. Настройка:

  1. Зарегистрировать приложение на account.ely.by/dev/applications/new (тип: Website).
  2. Указать Redirect URI: https://api.qx-dev.ru/api/v1/auth/ely/callback (или ваш домен API).
  3. Добавить в .env.cloud (передаётся в QMServer при deploy):
    • ELY_CLIENT_ID — Client ID из приложения
    • ELY_CLIENT_SECRET — Client Secret
    • ELY_REDIRECT_URI — тот же URL, что в п.2 (например https://api.qx-dev.ru/api/v1/auth/ely/callback)
    • ELY_FRONTEND_REDIRECThttps://web.qx-dev.ru (куда редиректить после OAuth)