11 KiB
Operations Guide
Документ для оператора ZBrain (admin) — повседневные задачи, типовые проблемы, runbook.
Чек-лист после деплоя
После завершения 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)
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:
- Залогинься как owner
- /users → New user
- Email + role (admin / editor / viewer)
- Скопировать temp password из ответа
Через CLI (только owner):
sudo docker exec zbrain-api node -e '
// TODO: команда будет добавлена в Sprint 7
'
Создать новый брейн
sudo bash /opt/zbrain/scripts/create-brain.sh <name> "<display name>" <port>
# Пример
sudo bash /opt/zbrain/scripts/create-brain.sh fontvielle "Fontvielle Infrastructure" 3005
Импорт большого корпуса в брейн
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 до новой версии
-
На рабочей машине (с GitHub доступом):
git clone --bare https://github.com/garrytan/gbrain.git cd gbrain.git git push --mirror git@git.zetit.ru:zuevav/gbrain-mirror.git -
На VM ZBrain — проверить changelog upstream'а на breaking changes, особенно в БД схеме.
-
Создать ADR в
docs/DECISIONS/если есть значимые изменения. -
Останавливаем все брейны:
sudo systemctl stop 'zbrain-gbrain-*' -
Обновляем gbrain:
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 ' -
Применяем миграции каждого брейна:
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 -
Запускаем брейны:
sudo systemctl start 'zbrain-gbrain-*' -
Проверяем health.
Восстановление из бэкапа
См. scripts/restore.sh. Краткая инструкция:
sudo bash /opt/zbrain/scripts/restore.sh 20260520-031500
# спросит путь к age приватному ключу
ВАЖНО: после restore удалить age ключ с VM:
shred -u /tmp/backup.age
Реактивация заблокированного пользователя
Если пользователь забыл пароль или нужно сбросить:
-- Через 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 секунд кэша:
# Через 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/
# 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
# 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
# По брейнам
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/, в UI брейн помечен красным.
# 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, все брейны лежат.
# 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.
# Проверка через 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
Сценарий: подозрение на утечку токена
# 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 при необходимости