320 lines
11 KiB
Markdown
320 lines
11 KiB
Markdown
# 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 при необходимости
|