Эксплуатация

Операторские процедуры: регистрация пользователей, восстановление зависших окружений, резервное копирование и восстановление.

Параметры платформы

Параметры задаются в конфигурации NixOS-хоста. Все они переопределяемы; значения по умолчанию рассчитаны на профиль team.

ПараметрТипПо умолчанию
platform.baseDomainstring"example.com"
platform.controlHoststringconfig.platform.baseDomain
platform.profileone of "home", "team", "enterprise""team"
platform.tls.modeone of "acme", "selfsigned"if profile == "home" then "selfsigned" else "acme"
platform.audit.retentionDayspositive integer, meaning >0365
platform.envRetention.daysnull or (positive integer, meaning >0)null
platform.defaultQuotanull or stringnull
platform.diskWatermarkPercentinteger between 1 and 99 (both inclusive)85

Добавление оператора

Чтобы выдать доступ к платформе, зарегистрируйте SSH-ключ пользователя в реестре и, если нужно, дайте права администратора.

  1. Добавьте публичный ключ в platform.sshKeys в конфигурации NixOS-хоста:
platform.sshKeys = {
alice = [ "ssh-ed25519 AAAA..." ];
};
  1. При необходимости дайте права администратора в platform.operators:
platform.operators = {
alice = { admin = true; };
};
  1. Пересоберите хост:
nixos-rebuild switch --flake .#maximaster

После этого пользователь может отправлять flake через mev и получать доступ по SSH к окружениям, где он указан в users.

Ротация SSH-ключа

  1. Обновите ключ в platform.sshKeys.
  2. Пересоберите хост: nixos-rebuild switch --flake .#maximaster.
  3. Старый ключ больше не принимается.

Восстановление зависшего окружения

Если окружение не отвечает и не спит:

# Проверить состояние юнита.
systemctl status container@env<id>

# Принудительно остановить.
systemctl stop container@env<id>

# Разбудить вручную через CLI.
mev status <owner/slug>

# Или через активатор, по HTTP-пути.
curl -fsS https://<domain>/

Если сборка контейнера зависла или сломалась:

# Посмотреть журнал.
mev logs <owner/slug>
journalctl -u container@env<id> -n 100

# При необходимости удалить и создать заново (данные сохраняются).
mev destroy <owner/slug>
mev push /path/to/flake

Флаг --purge-data при destroy удаляет ZFS-датасет необратимо — применяйте, только если данные действительно не нужны.

Восстановление mev.db из резервной копии

/var/lib/mev/mev.db — хранилище плоскости управления: идентификаторы окружений, членство, аудит. Резервная копия снимается ежедневно таймером mev-backup-db через VACUUM INTO.

Шаги восстановления

# 1. Остановить демон.
systemctl stop mevd.service

# 2. Найти последнюю (или нужную) копию.
ls -lt /var/lib/mev/backup/db/mev-*.db | head -5

# 3. Проверить целостность копии.
sqlite3 /var/lib/mev/backup/db/mev-YYYY-MM-DD-HHmmss.db '.tables'
# Ожидаемый вывод: audit domains envs members schema_versions

# 4. Заменить базу.
cp /var/lib/mev/mev.db /var/lib/mev/mev.db.pre-restore
cp /var/lib/mev/backup/db/mev-YYYY-MM-DD-HHmmss.db /var/lib/mev/mev.db
chown mev:mev /var/lib/mev/mev.db

# 5. Запустить демон.
systemctl start mevd.service

# 6. Проверить список окружений.
mev list

После восстановления базы pkgs/mev-rs/crates/mev-core/src/publish.rs заново соберёт реестр пробуждения, таблицу маршрутов и фрагменты Traefik при следующем mev push (согласование на хосте выполняет mevd-apply). Окружения, созданные или изменённые между снимком и потерей, нужно отправить заново.

Восстановление данных окружений из ZFS

rpool/environments содержит датасеты окружений (rpool/environments/env<id>) с данными приложений и age-ключами секретов.

2a. Откат к локальному снимку

# 1. Посмотреть запущенные окружения.
mev list

# 2. Остановить каждое работающее окружение.
# systemctl stop container@env<id>

# 3. Откатить датасет.
zfs rollback -r rpool/environments@mev-YYYY-MM-DD-HHmmss

# 4. Проверить состояние.
mev status <owner/slug>

Флаг -r уничтожает снимки новее целевого. Если текущее состояние ещё может понадобиться, сделайте его снимок перед откатом.

2b. Получить снимок с резервного хоста

# На хосте-источнике или локально:
zfs list -t snapshot backup-pool/environments

# Передать на хост восстановления.
ssh user@backup-host \
"zfs send backup-pool/environments@mev-YYYY-MM-DD-HHmmss" \
| zfs receive -F rpool/environments

# Или инкрементально от общей базы:
ssh user@backup-host \
"zfs send -I backup-pool/environments@base backup-pool/environments@target" \
| zfs receive -F rpool/environments

2c. Восстановить одно окружение

# Клонировать датасет окружения из снимка.
zfs clone rpool/environments@mev-YYYY-MM-DD-HHmmss/env<id> \
rpool/environments/env<id>-restore

# Смонтировать и проверить или продвинуть и переименовать.
zfs promote rpool/environments/env<id>-restore

Полное восстановление на чистом хосте

# 1. Установить NixOS (disko + nixos-anywhere или nixos-install).

# 2. Получить датасет окружений с резервного хоста.
ssh user@backup-host \
"zfs send rpool/environments@mev-YYYY-MM-DD-HHmmss" \
| zfs receive -F rpool/environments

# 3. Восстановить mev.db.
cp /path/to/mev-YYYY-MM-DD-HHmmss.db /var/lib/mev/mev.db
chown mev:mev /var/lib/mev/mev.db

# 4. Активировать систему.
nixos-rebuild switch --flake .#maximaster

# 5. Проверить список окружений.
mev list

# 6. Проверить секреты на тестовом окружении.
mev push path/to/test-env-flake
mev status <owner/slug>

После первого mev push pkgs/mev-rs/crates/mev-core/src/publish.rs сам восстановит реестр пробуждения, таблицу маршрутов и фрагменты Traefik из хранилища.

Управление резервным копированием

# Проверить последний запуск.
systemctl status mev-backup-db.service
journalctl -u mev-backup-db.service -n 50

# Запустить копирование вручную.
systemctl start mev-backup-db.service

# Список доступных копий SQLite.
ls -lh /var/lib/mev/backup/db/

# Список снимков ZFS.
zfs list -t snapshot -o name,creation rpool/environments

Хранение журнала аудита

Журнал аудита (таблица audit в mev.db) только дополняется. Строки старше platform.audit.retentionDays (по умолчанию 365) ежедневно удаляет таймер mev-audit-prune — это mevd audit-prune, запущенный от пользователя mev. Обычный таймер systemd, а не cron внутри базы: systemd (PID 1) всегда активен, а плоскость управления вызывается через forced-command и не держит постоянный воркер (см. honker-eventbus.md).

# Проверить последний запуск очистки.
systemctl status mev-audit-prune.service
journalctl -u mev-audit-prune.service -n 50

# Запустить очистку вручную.
systemctl start mev-audit-prune.service

Хранение окружений

Окружение, не использованное дольше platform.envRetention.days, сносится автоматически вместе с томом данных. Активность — это lastSeen активатора (запросы через Traefik и открытые SSH-сессии); окружение, которое ни разу не будили, отсчитывается от времени создания. По умолчанию параметр null: автоматический снос выключен, включите его на хосте, где окружения — расходуемый ресурс.

Ежедневный таймер mev-retention запускает mevd retention от пользователя mev — локальное обслуживание без прав оператора (как audit-prune), каждый снос пишется в аудит под служебным оператором retention с флагом purge. Метки времени, которые не удалось разобрать, считаются свежими: битый store или state.json активатора не может привести к удалению данных.

# Показать кандидатов, ничего не удаляя.
sudo -u mev /run/current-system/sw/bin/mevd retention --dry-run

# Последний запуск и журнал.
systemctl status mev-retention.service
journalctl -u mev-retention.service -n 50

# Запустить немедленно.
systemctl start mev-retention.service