sched: ядро выкачено на VDS (стек sched Id 28, MariaDB sched, admin-key) + deploy runbook
This commit is contained in:
@@ -34,6 +34,7 @@ updated: 2026-08-26
|
|||||||
| maljarka.tandemmebel.ru | [`maljarka-vds-deploy-runbook.md`](maljarka-vds-deploy-runbook.md) | restore-деплой 2026-07-31 |
|
| maljarka.tandemmebel.ru | [`maljarka-vds-deploy-runbook.md`](maljarka-vds-deploy-runbook.md) | restore-деплой 2026-07-31 |
|
||||||
| oCIS / owncloud | [`ocis-on-vds-deploy-recipe.md`](ocis-on-vds-deploy-recipe.md) | deploy recipe + gotchas |
|
| oCIS / owncloud | [`ocis-on-vds-deploy-recipe.md`](ocis-on-vds-deploy-recipe.md) | deploy recipe + gotchas |
|
||||||
| Локальный стенд sched-pipelines (sched + воркеры @apilki, мок-тест) | [`sched-pipelines-local-stack-runbook.md`](sched-pipelines-local-stack-runbook.md) | команды стенда, таймаут-сценарий (deadline-stop), gotchas 1-7 |
|
| Локальный стенд sched-pipelines (sched + воркеры @apilki, мок-тест) | [`sched-pipelines-local-stack-runbook.md`](sched-pipelines-local-stack-runbook.md) | команды стенда, таймаут-сценарий (deadline-stop), gotchas 1-7 |
|
||||||
|
| sched → VDS (ядро daemon + admin API, MariaDB) | [`sched-vds-deploy-runbook.md`](sched-vds-deploy-runbook.md) | стек sched Id 28, storage-mysql + TLS к mariadb, admin API, verify, gotchas |
|
||||||
|
|
||||||
## Публикация на GitHub (OSS)
|
## Публикация на GitHub (OSS)
|
||||||
|
|
||||||
|
|||||||
126
.wiki/concepts/sched-vds-deploy-runbook.md
Normal file
126
.wiki/concepts/sched-vds-deploy-runbook.md
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
---
|
||||||
|
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-daemon:0.12.1-mysql` |
|
||||||
|
| 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` |
|
||||||
|
| БД | 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. Образ** — собрать (см. выше) → `docker login registry.kzntsv.site -u vitya` → `docker push`. (внешний registry, публичный npm, BuildKit-секрет не нужен).
|
||||||
|
|
||||||
|
**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
|
||||||
47
host-stacks/vds-kzntsv/sched.compose.yml
Normal file
47
host-stacks/vds-kzntsv/sched.compose.yml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# sched — шедулер (ядро daemon + admin API) на инфра-VDS.
|
||||||
|
# Прод: VDS рядом с общей MariaDB (стек 11, сеть shared-dbs, отдельная база sched — свой role, решение 2026-08-27).
|
||||||
|
# Daemon: published @schedjs/daemon@0.12.1 + @schedjs/storage-mysql@0.4.0 (Dockerfile.mysql).
|
||||||
|
# Endpoint: https://sched.vds.kzntsv.site (admin API /api/*; health /api/health открыт, остальное Bearer SCHED_ADMIN_KEY).
|
||||||
|
# Deploy: Portainer-managed (см. portainer-stack-management-vds). Env через Portainer (не env_file).
|
||||||
|
|
||||||
|
services:
|
||||||
|
schedd:
|
||||||
|
image: registry.kzntsv.site/sched-daemon:0.12.1-mysql
|
||||||
|
container_name: schedd
|
||||||
|
restart: unless-stopped
|
||||||
|
mem_limit: 512m
|
||||||
|
networks:
|
||||||
|
- shared-dbs
|
||||||
|
- proxy
|
||||||
|
command:
|
||||||
|
- --tasks
|
||||||
|
- /app/config/tasks.json
|
||||||
|
- --storage
|
||||||
|
- mysql
|
||||||
|
- --admin-port
|
||||||
|
- "8080"
|
||||||
|
- --admin-host
|
||||||
|
- 0.0.0.0
|
||||||
|
environment:
|
||||||
|
MYSQL_URL: mysql://sched:${SCHED_DB_PASS}@mariadb:3306/sched?ssl={"rejectUnauthorized":false}
|
||||||
|
SCHED_ADMIN_KEY: ${SCHED_ADMIN_KEY}
|
||||||
|
volumes:
|
||||||
|
- /opt/stacks/sched/tasks.json:/app/config/tasks.json:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8080/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
|
labels:
|
||||||
|
traefik.enable: "true"
|
||||||
|
traefik.http.routers.sched.entrypoints: websecure
|
||||||
|
traefik.http.routers.sched.rule: Host(`sched.vds.kzntsv.site`)
|
||||||
|
traefik.http.routers.sched.tls.certresolver: letsEncrypt
|
||||||
|
traefik.http.services.sched.loadbalancer.server.port: "8080"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
shared-dbs:
|
||||||
|
external: true
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
3
host-stacks/vds-kzntsv/sched.tasks.json
Normal file
3
host-stacks/vds-kzntsv/sched.tasks.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"tasks": []
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user