9.1 KiB
title, description, weight
| title | description | weight |
|---|---|---|
| Многоуровневое хранилище и изоляция привилегий | Структура ссылок @tier, общее хранилище и понодовые noroot-пользователи. | 16 |
Данные сервисов никогда не живут внутри репозитория узла. Они живут в трёх уровнях хранилища — раздельных расположениях, выбираемых для каждого хоста, — и достигают композиций через стандартизированную структуру символьных ссылок. Владение этими данными делегируется системным пользователям для каждого проекта, поэтому ни один сервисный контейнер не пишет от имени root.
Структура ссылок уровней
apex tiers/link <tier1> <tier2> <tier3> строит два слоя ссылок:
- На уровне узла:
compositions/@tierN→ корень хранилища уровня. Именно их движок выставляет какAPEX_TIER_ROOT1..3. - Для каждого проекта: для каждого
compositions/<project>/действие создаёт<tier-root>/<project>/и связываетcompositions/<project>/@tierN→<tier-root>/<project>. Внутри каждого уровня оно также поддерживаетshared/с подкаталогом для каждого проекта и относительной ссылкойsharedвнутри каталога уровня каждого проекта, указывающей обратно на него.
Каждый проект дополнительно получает compositions/<project>/.env → <tier1-root>/<project>/.env (создаётся пустым, если отсутствует) — файл незакоммиченных секретов, описанный в Концепция: Композиции. Ссылки @tierN и файлы .env игнорируются git; репозиторий остаётся чистым источником.
Если путь, который должен быть символьной ссылкой, существует как настоящий файл или каталог, действие предупреждает и запрашивает подтверждение перед его удалением; отказ (включая неинтерактивный EOF) пропускает эту ссылку и продолжает.
Пользователи и группы
apex tiers/useradd провизионирует по одному заблокированному системному пользователю на проект — noroot-<project> (имя санитизируется, собственная первичная группа) — плюс общефлотовую группу noroot-shared, к которой присоединяется каждый пользователь проекта. Затем оно внедряет разрешённые ID в .env проекта между комментариями-маркерами, заменяя любой предыдущий блок при повторных запусках:
# START AUTO GENERATED APEX-NOROOT-USERS
APEX_UID=998
APEX_GID=998
APEX_SHARED_GID=997
# END AUTO GENERATED APEX-NOROOT-USERS
Композиции потребляют их как user: "${APEX_UID?error}:${APEX_GID?error}" и group_add: ["${APEX_SHARED_GID?error}"].
Матрица владения
apex tiers/chown обеспечивает владение по всем трём уровням. Без аргументов оно работает с корнями уровней (APEX_TIER_ROOT1..3); явные пути уровней могут переопределить это.
| Путь | Владение | Примечания |
|---|---|---|
<tier-root> |
root:root |
Только inode каталога. |
<tier-root>/shared |
root:root |
Только inode каталога — никогда рекурсивно, поэтому существующие данные проектов внутри не затрагиваются. |
<tier-root>/node-infra |
root:root |
Рекурсивно. |
<tier-root>/<project> |
uid:gid |
Рекурсивно; ID читаются из .env проекта. |
<tier-root>/shared/<project> |
uid:shared_gid |
Рекурсивно, плюс sticky-бит — участники могут добавлять файлы, но удалять только свои. |
Проекты с неполным набором APEX_UID/APEX_GID/APEX_SHARED_GID пропускаются с предупреждением, указывающим на tiers/useradd.
Переменные уровней движка
| Переменная | Разрешается в |
|---|---|
APEX_TIER_ROOT1..3 |
Корни хранилищ уровней (compositions/@tierN, полностью разрешённые). |
APEX_TIER1..3 |
Каталоги данных ядрового проекта внутри каждого уровня (compositions/apex/@tierN). |
APEX_TIER1..3_SHARED |
Общая область внутри уровней ядрового проекта. |
Ядровая композиция монтирует исключительно через них; исполнитель резервного копирования вместо этого монтирует корень данных флота /srv в режиме только для чтения и разрешает контейнерные монтирования каждого помеченного сервиса обратно в их хостовые пути.
Резервные копии
apex backup/run <telegram-bot-url> управляет ядровым сервисом resticontainer (профиль manual, одноразовый) от начала до конца. Намерение резервного копирования управляется метками: resticontainer обнаруживает каждый сервис, несущий restic.enable=true, читает его restic.backup.paths (и опциональные restic.backup.stop / restic.hooks.*), разрешает эти контейнерные пути в хостовые пути и делает снимок их объединения в одном запуске restic.
- Проверяет доступность репозитория через
snapshots; инициализирует репозиторий при необходимости. - Выполняет
backupс--host <APEX_NODE_HOST>и--tag biweekly— resticontainer выполняет pre-hook каждого помеченного сервиса, останавливает любой контейнер, помеченныйrestic.backup.stop, делает снимок разрешённых хостовых путей, затем перезапускает и выполняет post-hooks. Запуск отказывается сообщать об успехе, если не появляется новый снимок (защита от обнаружения нулевого количества меток). - Применяет удержание через
forget --prune(7 ежедневных, 4 еженедельных, 12 ежемесячных). - Отправляет статус в Telegram в любом случае; успех, уведомление о котором не может быть доставлено, всё равно завершается с кодом
1, чтобы планировщики это заметили.
Расположение репозитория и учётные данные полностью берутся из конфигурации APEX_RESTIC_* (см. Справочник: Переменные окружения). Какие данные захватываются, решается для каждого сервиса его метками restic.* — например, ядровые сервисы резервируют только свою конфигурацию (динамические правила traefik, конфигурацию xray/adguard), оставляя воспроизводимые данные уровня 3, такие как кэши и логи, вне набора.
См. также: