Files
admin/.wiki/concepts/sched-vds-deploy-runbook.md

134 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "sched — VDS deploy runbook (ядро daemon + admin API, MariaDB, стек sched)"
type: concept
tags: [sched, vds, deploy, docker, portainer, traefik, mariadb, runbook, scheduler]
related: [concepts/runbooks-index.md, concepts/portainer-stack-management-vds.md, concepts/sched-publish-runbook.md]
sources: []
updated: 2026-08-27
---
# sched → VDS deploy runbook (ядро daemon)
> **⚙️ СЛУЖЕБНЫЙ РАНБУК — только для администратора проекта `.admin`.**
> Применять/выполнять шаги может только **`.admin`** (оператор проекта admin).
> Из проекта не выносить: не копировать в другие вики, не пересказывать, не публиковать.
> Нужен деплой или прод-операция по этому ранбуку — **поставить задачу админу (`.admin`) и написать письмо**.
Развёртывание **ядра sched** (шедулер: daemon + in-process admin API) на инфра-VDS
(`89.253.255.94`), storage-адаптер **MariaDB** (общая MariaDB-стек 11, отдельная база `sched`).
Первый деплой — 2026-08-27 (task:790). Вводные с 2026-08-27: org/scope **@schedjs**
(github.com/schedjs/schedjs), self-host на MariaDB (не sqlite).
## Параметры
| Что | Значение |
|---|---|
| Хост | VDS kzntsv `89.253.255.94` |
| Стек Portainer | **Id 28**, name `sched`, endpointId **1** |
| Образ | `registry.kzntsv.site/sched-custom:0.12.1-mysql` (custom single-binary)
| Compose source-of-truth | `admin/host-stacks/vds-kzntsv/sched.compose.yml` |
| tasks.json source-of-truth | `admin/host-stacks/vds-kzntsv/sched.tasks.json` → VDS `/opt/stacks/sched/tasks.json` |
| Даемон | published `@schedjs/daemon@0.12.1` + `@schedjs/storage-mysql@0.4.0` + `@schedjs/admin-api@0.3.0` + `@schedjs/mcp@0.4.1` + `@schedjs/ui@0.3.0` |
| БД | MariaDB `mariadb:3306` (сеть `shared-dbs`), база `sched`, роль `sched@%`. Креды: `pass sched/mysql` |
| Admin API | `https://sched.vds.kzntsv.site` (traefik websecure, letsEncrypt). `SCHED_ADMIN_KEY` = `pass sched/admin-key` |
| mem_limit | `512m` (канон app-стеков) |
| Сети | `shared-dbs` + `proxy` (обе external) |
## Артефакты
- **Код/пакеты:** публикуются на npm `@schedjs/*` (см. `sched-publish-runbook`). Dev-исходники — репо `sched` (Gitea).
- **Dockerfile.** Стандартный `apps/daemon/Dockerfile` собирает из `@schedjs/daemon`. Для MariaDB — **композиция** адаптера. В репо добавлен `apps/daemon/Dockerfile.mysql` (public npm, без токена):
```dockerfile
FROM node:24-alpine
WORKDIR /app; ENV NODE_ENV=production
RUN echo '{"name":"schedd","private":true,"packageManager":"yarn@4.18.0"}' > package.json \
&& corepack enable && printf 'nodeLinker: node-modules\nnpmMinimalAgeGate: 0\n' > .yarnrc.yml \
&& CI=1 yarn add @schedjs/daemon@0.12.1 @schedjs/storage-mysql@0.4.0 \
&& rm -f .yarnrc.yml && yarn cache clean
ENV PATH="/app/node_modules/.bin:${PATH}"; EXPOSE 8080; VOLUME ["/data"]; ENTRYPOINT ["schedd"]
```
Сборка: `docker build -f apps/daemon/Dockerfile.mysql -t registry.kzntsv.site/sched-daemon:0.12.1-mysql apps/daemon`.
Единственный слой, который важно композить — `@schedjs/storage-mysql` (иначе `--storage mysql` падает `ERR_MODULE_NOT_FOUND`).
## Первичный деплой (сделано 2026-08-27)
**0. База (однократно).**
```bash
# на VDS, root внутри mariadb контейнера
docker exec mariadb mariadb -uroot -p"$ROOT_PW" -e "
CREATE DATABASE IF NOT EXISTS sched CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'sched'@'%' IDENTIFIED BY '<pw>';
GRANT ALL PRIVILEGES ON sched.* TO 'sched'@'%'; FLUSH PRIVILEGES;"
```
Креды → `pass insert -m sched/mysql` (user/pass/db/host).
**1. Образ (custom single-binary).** `apps/daemon/Dockerfile.custom` собирает один образ с опубликованными `@schedjs/{daemon,storage-mysql,admin-api,mcp,ui}` + `custom-entry.mjs` — один HTTP-сервер на `:8080`:
- `/api/*` → админ API (health open, остальное Bearer `SCHED_ADMIN_KEY`)
- `/mcp` → Streamable HTTP MCP (projection of admin API, `SCHED_MCP_READONLY=1` read-only)
- `/` → UI morda (web-components)
- `/sched-ui.bundle.js` → статический UI-бандл
Сборка: `docker build -f apps/daemon/Dockerfile.custom -t registry.kzntsv.site/sched-custom:0.12.1-mysql apps/daemon`.
→ ЕДИНЫЙ бинарь: даемон + UI-морда + MCP не плодит отдельные контейнеры (обратная связь vitya).
`createDaemon` даёт `engine`+`storage` (admin server НЕ bind — маршрутизация своя). MCP/морда импортируются по **file-URL** (subpath-импорты заблокированы npm `exports`-маской).
**2. tasks.json.** Ядро стартует с `{"tasks":[]}` (воркеры — отдельными тасками). Закинуть на VDS:
```bash
scp sched.tasks.json vds.kzntsv.site:/tmp/ ; ssh vds.kzntsv.site 'sudo mkdir -p /opt/stacks/sched && sudo cp /tmp/sched.tasks.json /opt/stacks/sched/tasks.json && sudo chmod 644 /opt/stacks/sched/tasks.json'
```
**3. Стек Portainer.** compose в `host-stacks/vds-kzntsv/sched.compose.yml`, env через Portainer API (`SCHED_DB_PASS`, `SCHED_ADMIN_KEY`). Create `standalone/string?endpointId=1`.
**Ключевой момент — MYSQL_URL + TLS.** MariaDB-стек 11 запущен с `--require-secure-transport=ON` и self-signed TLS. Подключение через `mariadb:3306` (внутренняя сеть `shared-dbs`) **без TLS НЕ проходит**: `fatal: Connections using insecure transport are prohibited`. Фикс — ssl в connstring:
```
MYSQL_URL=mysql://sched:${SCHED_DB_PASS}@mariadb:3306/sched?ssl={"rejectUnauthorized":false}
```
`mysql2` парсит `ssl` из query-string (`ConnectionConfig.parseUrl`), self-signed → `rejectUnauthorized:false`.
## Реденплой (обновление образа)
```bash
# 1. build + push нового тега (см. артефакты)
# 2. на VDS docker pull ДО restart (иначе застрянет на старом digest)
ssh vds.kzntsv.site 'docker pull registry.kzntsv.site/sched-daemon:<new>'
# 3. source-of-truth compose: сменить image: тег
# 4. Portainer PUT /api/stacks/28?endpointId=1 {stackFileContent, env:[...], prune:false, pullImage:true}
```
⚠️ PUT сбрасывает env-массив, если не передать `env` (gotcha 4b portainer-канон).
⚠️ Синхронизировать source-of-truth compose после PUT (иначе следующий redeploy из гита откатит тег).
## Verify
```bash
# контейнер
docker ps -a --filter name=schedd --format "{{.Status}}" # Up ... (healthy)
docker logs --tail 5 schedd # "daemon started (tasks=..., storage=mysql db=sched, ...)"
# health (публичный, открыт)
curl -ksS https://sched.vds.kzntsv.site/api/health # {"ok":true,"uptimeMs":...,"version":"0.12.1"}
# авторизованный доступ (SCHED_ADMIN_KEY = Bearer)
curl -ksS -H "Authorization: Bearer $AK" https://sched.vds.kzntsv.site/api/tasks # {"tasks":[]}
curl -ksS https://sched.vds.kzntsv.site/api/tasks # 401 (без Bearer)
# таблицы в MariaDB
docker exec mariadb mariadb -uroot -p"$ROOT_PW" -e "USE sched; SHOW TABLES; SELECT version FROM sched_schema_version;"
# → scheduled_tasks, schedules, task_runs, sched_schema_version; version = 6
```
## Rollback
PUT стека 28 с предыдущим тегом образа (или `{"tasks":[]}` пустой cron). Старые теги в registry.
## Gotchas
1. **TLS к MariaDB обязателен** — `--require-secure-transport=ON`, без `?ssl={"rejectUnauthorized":false}` → daemon в restart-loop с `fatal: insecure transport prohibited`.
2. **basicAuth — оставлен ВЫКЛ** (первый деплой). У daemon самодостаточный `SCHED_ADMIN_KEY` (Bearer) — второй слой. `/api/health` открыт (для мониторинга), всё остальное 401 без Bearer. Если нужен front-layer basicAuth — добавить middleware в traefik labels (сгенерировать bcrypt-хэш `htpasswd -nbB`), НО хэш передавать аккуратно (traefik может не принять `$2y$` при кривой передаче).
3. **`--admin-host 0.0.0.0`** — daemon слушает на всех интерфейсах внутри `proxy`-сети для traefik. Наружу VDS-порт НЕ публикуется (нет `ports:`), только через traefik.
4. **Воркеры НЕ в этом ядре** — `task:1190` (yt-digest), `task:1311` (tg-digest) отдельные; добавляются как задачи в `tasks.json`.
5. **`SCHED_ADMIN_KEY`** — в `pass sched/admin-key` (не basic-auth; это разные вещи).
6. **storage-mysql сам применяет миграции** на старте (`sched_schema_version`, версия 6) — внешний инструментарий не нужен, но БД должна быть доступна с правами на CREATE/ALTER.
## Связи
- [[concepts/portainer-stack-management-vds.md]] — общий Portainer-канон (JWT, gotchas, mem_limit)
- [[concepts/sched-publish-runbook.md]] — паблиш @schedjs на npm/GitHub
- [[concepts/runbooks-index.md]] — индекс ранбуков
- Репо sched: `docs/content/docs/13.self-hosting.md` — композиция storage-адаптеров, security model