main
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
# Operations Guide
|
||||
|
||||
Документ для оператора ZBrain (admin) — повседневные задачи, типовые проблемы, runbook.
|
||||
|
||||
## Чек-лист после деплоя
|
||||
|
||||
После завершения [DEPLOYMENT.md](DEPLOYMENT.md):
|
||||
|
||||
- [ ] Все systemd unit'ы для брейнов активны: `systemctl status 'zbrain-gbrain-*'`
|
||||
- [ ] Docker контейнеры brainhub запущены: `docker compose -f /opt/zbrain/deploy/docker/docker-compose.yml ps`
|
||||
- [ ] Nginx обслуживает оба домена: `curl -H "Host: brain.zetit.local" http://localhost/health`
|
||||
- [ ] Cron для backup'ов настроен: `sudo crontab -l | grep backup`
|
||||
- [ ] Логи пишутся: `ls -lh /var/log/zbrain/`
|
||||
- [ ] Disk usage в норме: `df -h /var/lib/postgresql /var/lib/zbrain /var/log`
|
||||
|
||||
## Ежедневные задачи (автоматические)
|
||||
|
||||
### Backup (cron, 03:00)
|
||||
|
||||
```cron
|
||||
0 3 * * * root /opt/zbrain/scripts/backup.sh
|
||||
```
|
||||
|
||||
Что проверять раз в неделю:
|
||||
- `ls -lh /var/backups/zbrain/` — есть свежий бэкап
|
||||
- `cat /var/log/zbrain/backup.log | tail -20` — нет ошибок
|
||||
- Раз в месяц — тестовое восстановление на отдельной VM
|
||||
|
||||
### Sync (опционально, cron, 06:00 / 18:00)
|
||||
|
||||
Если источники не настроены через UI с расписанием, можно запускать вручную через scripts/sync-all.sh (будет добавлено в Sprint 4).
|
||||
|
||||
## Типовые задачи
|
||||
|
||||
### Создать нового пользователя
|
||||
|
||||
Через UI:
|
||||
1. Залогинься как owner
|
||||
2. /users → New user
|
||||
3. Email + role (admin / editor / viewer)
|
||||
4. Скопировать temp password из ответа
|
||||
|
||||
Через CLI (только owner):
|
||||
```bash
|
||||
sudo docker exec zbrain-api node -e '
|
||||
// TODO: команда будет добавлена в Sprint 7
|
||||
'
|
||||
```
|
||||
|
||||
### Создать новый брейн
|
||||
|
||||
```bash
|
||||
sudo bash /opt/zbrain/scripts/create-brain.sh <name> "<display name>" <port>
|
||||
|
||||
# Пример
|
||||
sudo bash /opt/zbrain/scripts/create-brain.sh fontvielle "Fontvielle Infrastructure" 3005
|
||||
```
|
||||
|
||||
### Импорт большого корпуса в брейн
|
||||
|
||||
```bash
|
||||
sudo -u zbrain bash -c '
|
||||
export PATH=$HOME/.bun/bin:$PATH
|
||||
source /etc/zbrain/.env
|
||||
export DATABASE_URL=$(cat /var/lib/zbrain/brains/zetit/config.json | jq -r .database_url)
|
||||
cd /var/lib/zbrain/gbrain
|
||||
bun run gbrain import /path/to/markdown/
|
||||
'
|
||||
```
|
||||
|
||||
Для очень больших корпусов (>10000 страниц) — лучше через UI после Sprint 4, там SSE прогресс.
|
||||
|
||||
### Обновить gbrain до новой версии
|
||||
|
||||
1. **На рабочей машине** (с GitHub доступом):
|
||||
```bash
|
||||
git clone --bare https://github.com/garrytan/gbrain.git
|
||||
cd gbrain.git
|
||||
git push --mirror git@git.zetit.ru:zuevav/gbrain-mirror.git
|
||||
```
|
||||
|
||||
2. **На VM ZBrain** — проверить changelog upstream'а на breaking changes, особенно в БД схеме.
|
||||
|
||||
3. Создать ADR в `docs/DECISIONS/` если есть значимые изменения.
|
||||
|
||||
4. Останавливаем все брейны:
|
||||
```bash
|
||||
sudo systemctl stop 'zbrain-gbrain-*'
|
||||
```
|
||||
|
||||
5. Обновляем gbrain:
|
||||
```bash
|
||||
sudo -u zbrain bash -c '
|
||||
cd /var/lib/zbrain/gbrain
|
||||
git fetch
|
||||
git checkout v0.27.0 # новая версия
|
||||
export PATH=$HOME/.bun/bin:$PATH
|
||||
export HTTPS_PROXY=$(grep HTTPS_PROXY /etc/zbrain/.env | cut -d= -f2-)
|
||||
bun install
|
||||
'
|
||||
```
|
||||
|
||||
6. Применяем миграции каждого брейна:
|
||||
```bash
|
||||
for brain in zetit telerapharma personal community; do
|
||||
sudo -u zbrain bash -c "
|
||||
export PATH=\$HOME/.bun/bin:\$PATH
|
||||
export DATABASE_URL=\$(cat /var/lib/zbrain/brains/$brain/config.json | jq -r .database_url)
|
||||
cd /var/lib/zbrain/gbrain
|
||||
bun run gbrain migrate
|
||||
"
|
||||
done
|
||||
```
|
||||
|
||||
7. Запускаем брейны:
|
||||
```bash
|
||||
sudo systemctl start 'zbrain-gbrain-*'
|
||||
```
|
||||
|
||||
8. Проверяем health.
|
||||
|
||||
### Восстановление из бэкапа
|
||||
|
||||
См. `scripts/restore.sh`. Краткая инструкция:
|
||||
|
||||
```bash
|
||||
sudo bash /opt/zbrain/scripts/restore.sh 20260520-031500
|
||||
# спросит путь к age приватному ключу
|
||||
```
|
||||
|
||||
**ВАЖНО:** после restore удалить age ключ с VM:
|
||||
```bash
|
||||
shred -u /tmp/backup.age
|
||||
```
|
||||
|
||||
### Реактивация заблокированного пользователя
|
||||
|
||||
Если пользователь забыл пароль или нужно сбросить:
|
||||
|
||||
```sql
|
||||
-- Через UI пока нет, делаем напрямую
|
||||
sudo -u postgres psql -d brainhub
|
||||
|
||||
-- Сгенерировать новый bcrypt hash (cost=12)
|
||||
-- Можно через: echo 'newpassword' | htpasswd -bnBC 12 "" -
|
||||
UPDATE users
|
||||
SET password_hash = '<new-bcrypt-hash>',
|
||||
must_change_password = true
|
||||
WHERE email = 'user@example.com';
|
||||
```
|
||||
|
||||
### Срочный отзыв токена
|
||||
|
||||
Если подозрение на утечку токена и нельзя ждать 30 секунд кэша:
|
||||
|
||||
```bash
|
||||
# Через UI: /tokens → Revoke. Это уже делает invalidate cache.
|
||||
|
||||
# Срочное через API:
|
||||
curl -X POST http://brain.zetit.local/api/admin/cache/invalidate-token \
|
||||
-H "Authorization: Bearer <admin-session-token>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"tokenPrefix":"brain_pat_a8f3"}'
|
||||
|
||||
# Полный сброс кэша токенов (drastic):
|
||||
sudo systemctl restart docker
|
||||
sudo docker compose restart brainhub-api
|
||||
```
|
||||
|
||||
## Мониторинг
|
||||
|
||||
### Что смотреть в /var/log/zbrain/
|
||||
|
||||
```bash
|
||||
# Live tail всех логов
|
||||
sudo tail -F /var/log/zbrain/*.log
|
||||
|
||||
# Ошибки за последний час
|
||||
sudo journalctl --since "1 hour ago" -u 'zbrain-gbrain-*' | grep -i error
|
||||
|
||||
# Brainhub access pattern
|
||||
sudo tail -1000 /var/log/zbrain/brainhub.log | jq -r 'select(.req.url) | "\(.time) \(.req.method) \(.req.url) → \(.res.statusCode)"'
|
||||
```
|
||||
|
||||
### Метрики Postgres
|
||||
|
||||
```bash
|
||||
# Connection count
|
||||
sudo -u postgres psql -c 'SELECT count(*), state FROM pg_stat_activity GROUP BY state;'
|
||||
|
||||
# Размер БД
|
||||
sudo -u postgres psql -c "
|
||||
SELECT datname, pg_size_pretty(pg_database_size(datname))
|
||||
FROM pg_database WHERE datname IN ('brainhub','gbrain_zetit','gbrain_telerapharma','gbrain_personal','gbrain_community')
|
||||
ORDER BY pg_database_size(datname) DESC;
|
||||
"
|
||||
|
||||
# Топ медленных запросов
|
||||
sudo -u postgres psql -c '
|
||||
SELECT calls, mean_exec_time, query
|
||||
FROM pg_stat_statements
|
||||
ORDER BY mean_exec_time DESC LIMIT 10;
|
||||
' # если pg_stat_statements включён
|
||||
```
|
||||
|
||||
### Disk usage
|
||||
|
||||
```bash
|
||||
# По брейнам
|
||||
du -sh /var/lib/zbrain/brains/*/
|
||||
|
||||
# Postgres data
|
||||
sudo du -sh /var/lib/postgresql/16/main/
|
||||
|
||||
# Логи
|
||||
sudo du -sh /var/log/zbrain/ /var/log/postgresql/ /var/log/nginx/
|
||||
```
|
||||
|
||||
Если /var/log пухнет — настроить logrotate.
|
||||
|
||||
## Runbook'и инцидентов
|
||||
|
||||
### Сценарий: брейн не отвечает на MCP запросы
|
||||
|
||||
**Симптомы:** Claude Code получает 502 от /mcp/<brain>, в UI брейн помечен красным.
|
||||
|
||||
```bash
|
||||
# 1. Проверить systemd unit
|
||||
sudo systemctl status zbrain-gbrain-<brain>
|
||||
|
||||
# 2. Если down - последние логи
|
||||
sudo journalctl -u zbrain-gbrain-<brain> -n 100 --no-pager
|
||||
|
||||
# 3. Если crash loop - проверить Postgres connection
|
||||
sudo -u postgres psql -d gbrain_<brain> -c 'SELECT version()'
|
||||
|
||||
# 4. Если ОК - перезапустить
|
||||
sudo systemctl restart zbrain-gbrain-<brain>
|
||||
|
||||
# 5. Если не помогло - временно отключить и эскалировать
|
||||
sudo systemctl stop zbrain-gbrain-<brain>
|
||||
```
|
||||
|
||||
### Сценарий: Postgres недоступен
|
||||
|
||||
**Симптомы:** brainhub возвращает 503, все брейны лежат.
|
||||
|
||||
```bash
|
||||
# 1. Статус
|
||||
sudo systemctl status postgresql
|
||||
|
||||
# 2. Если crashed - проверить логи
|
||||
sudo tail -200 /var/log/postgresql/postgresql-16-main.log
|
||||
|
||||
# 3. Частые причины:
|
||||
# a) Disk full → освободить место (старые WAL, логи)
|
||||
df -h /var/lib/postgresql
|
||||
sudo du -sh /var/lib/postgresql/16/main/pg_wal/
|
||||
|
||||
# b) OOM → проверить dmesg
|
||||
sudo dmesg | tail -50 | grep -i 'killed process'
|
||||
|
||||
# c) Corrupt → restore из бэкапа
|
||||
```
|
||||
|
||||
### Сценарий: исчерпался лимит OpenAI/Anthropic API
|
||||
|
||||
**Симптомы:** sync падает с 429, новые pages не получают embeddings.
|
||||
|
||||
```bash
|
||||
# Проверка через FNA прокси
|
||||
sudo -u zbrain bash -c '
|
||||
source /etc/zbrain/.env
|
||||
curl --proxy "$HTTPS_PROXY" \
|
||||
https://api.openai.com/v1/dashboard/billing/usage \
|
||||
-H "Authorization: Bearer $OPENAI_API_KEY"
|
||||
'
|
||||
|
||||
# Действия:
|
||||
# 1. Пополнить баланс на платформе OpenAI/Anthropic
|
||||
# 2. Или временно поставить на паузу автоматический sync
|
||||
# 3. Прикинуть стоимость re-embed: ~$0.65 на 7500 страниц для text-embedding-3-large
|
||||
```
|
||||
|
||||
### Сценарий: подозрение на утечку токена
|
||||
|
||||
```bash
|
||||
# 1. Найти токен в UI: /tokens → найти по prefix
|
||||
# 2. Посмотреть активность: /audit?actor_type=token&actor_id=<id>
|
||||
# 3. Revoke + invalidate cache
|
||||
# 4. Создать новый токен с теми же scope, передать пользователю
|
||||
# 5. Анализ через audit log:
|
||||
sudo -u postgres psql -d brainhub -c "
|
||||
SELECT created_at, ip, action, payload
|
||||
FROM audit_log
|
||||
WHERE actor_type='token' AND actor_id='<token-id>'
|
||||
ORDER BY created_at DESC LIMIT 100;
|
||||
"
|
||||
# 6. Если был доступ из неожиданного IP - эскалация (анализ что было прочитано/изменено)
|
||||
```
|
||||
|
||||
## Регулярные процедуры
|
||||
|
||||
### Раз в неделю
|
||||
- Проверить freshness бэкапов и логи backup.log
|
||||
- Проверить disk usage
|
||||
- Глянуть audit log на необычную активность
|
||||
|
||||
### Раз в месяц
|
||||
- Тестовый restore на отдельной VM
|
||||
- Review обновлений gbrain upstream
|
||||
- Обновить ОС (`apt update && apt upgrade`)
|
||||
- Rotate session secrets (опционально, но повышает security posture)
|
||||
|
||||
### Раз в квартал
|
||||
- Penetration test публичного контура (хотя бы на nikto/zap-baseline)
|
||||
- Review активных токенов, удаление неиспользуемых
|
||||
- Review активных пользователей, удаление неактивных
|
||||
- Capacity planning: смотреть рост БД и проектировать апгрейд VM при необходимости
|
||||
Reference in New Issue
Block a user