--- title: Многоуровневое хранилище и изоляция привилегий description: Структура ссылок @tier, разделяемое хранилище и локальные noroot-пользователи для проектов. weight: 16 --- Данные сервисов никогда не хранятся внутри репозитория [узла](/apex/glossary#node). Они распределяются по трём [уровням](/apex/glossary#tier) хранилища — отдельным каталогам, настраиваемым индивидуально для каждого хоста, — и подключаются к [композициям](/apex/glossary#compositions) через стандартизированную структуру символьных ссылок. Права на эти каталоги делегируются системным пользователям проектов, благодаря чему ни один контейнер не ведёт запись от имени root. ## Структура ссылок уровней {#links} Команда `apex tiers/link ` формирует два уровня символьных ссылок: - **На уровне узла:** `compositions/@tierN` → корень хранилища соответствующего уровня. Именно эти пути движок предоставляет в переменных `APEX_TIER_ROOT1..3`. - **Для каждого проекта:** в каталоге `compositions//` создаётся путь `//`, на который указывает ссылка `compositions//@tierN`. Внутри каждого уровня поддерживается общий каталог `shared/` с поддиректорией для каждого проекта, а внутри каталога уровня проекта создаётся относительная ссылка `shared`, ведущая обратно в общую зону. Каждый проект дополнительно получает символьную ссылку `compositions//.env` → `//.env` (создаётся пустым, если файл отсутствует). В нём хранятся незакоммиченные секреты (см. [Концепция: Композиции и общее ядро](/apex/concepts/compositions)). Ссылки `@tierN` и файлы `.env` исключены из git через `.gitignore`, благодаря чему репозиторий остаётся чистым источником кода. Если по пути предполагаемой символьной ссылки уже существует обычный файл или каталог, действие предупреждает об этом и запрашивает подтверждение перед удалением. При отказе (включая неинтерактивный EOF) создание ссылки пропускается, а выполнение продолжается дальше. ## Пользователи и группы {#users} Команда `apex tiers/useradd` создаёт по одному заблокированному системному пользователю на проект — `noroot-` (с санитизацией имени и собственной первичной группой), а также общефлотовую группу `noroot-shared`, в которую входят все пользователи проектов. Затем сгенерированные идентификаторы прописываются в файл `.env` соответствующего проекта между комментариями-маркерами, перезаписывая старый блок при повторных запусках: ```ini {filename="compositions//.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}"]`. ## Матрица владения {#ownership} Действие `apex tiers/chown` выставляет корректные права по всем трём уровням хранилища. Без аргументов оно обрабатывает корни уровней (`APEX_TIER_ROOT1..3`); при необходимости можно указать конкретные пути вручную. | Путь | Владение | Примечания | |---|---|---| | `` | `root:root` | Только inode каталога. | | `/shared` | `root:root` | Только inode каталога (без рекурсии, чтобы не затронуть пользовательские данные проектов). | | `/node-infra` | `root:root` | Рекурсивно. | | `/` | `uid:gid` | Рекурсивно; идентификаторы читаются из `.env` проекта. | | `/shared/` | `uid:shared_gid` | Рекурсивно, с установкой sticky-бита: участники могут добавлять файлы, но удалять — только собственные. | Проекты с неполным набором переменных `APEX_UID`, `APEX_GID` или `APEX_SHARED_GID` пропускаются с предупреждением и рекомендацией выполнить `tiers/useradd`. ## Переменные уровней движка {#variables} | Переменная | Разрешается в | |---|---| | `APEX_TIER_ROOT1..3` | Корни хранилищ уровней (`compositions/@tierN`, абсолютные пути). | | `APEX_TIER1..3` | Каталоги данных ядрового проекта на каждом уровне (`compositions/apex/@tierN`). | | `APEX_TIER1..3_SHARED` | Общие области внутри уровней ядрового проекта. | Ядровая композиция монтирует каталоги исключительно через эти переменные. Контейнер резервного копирования, напротив, монтирует общий корень данных флота `/srv` в режиме «только для чтения» и сопоставляет контейнерные пути каждого сервиса с их реальными путями на хосте. ## Резервное копирование {#backups} Команда `apex backup/run ` полностью берёт на себя управление сервисом `resticontainer` (профиль `manual`, одноразовый запуск). Резервное копирование **управляется метками**: resticontainer находит все контейнеры с меткой `restic.enable=true`, считывает список путей `restic.backup.paths` (и необязательные параметры `restic.backup.stop` / `restic.hooks.*`), транслирует пути контейнеров в пути хоста и создаёт единый снимок restic. 1. Проверяет доступность репозитория с помощью команды `snapshots`; при необходимости автоматически инициализирует его. 2. Запускает команду `backup` с параметрами `--host ` и `--tag biweekly`. При этом resticontainer выполняет pre-hook сервиса, временно останавливает контейнеры с меткой `restic.backup.stop`, делает снимок хостовых путей, перезапускает остановленные контейнеры и запускает post-hooks. Запуск не засчитывается как успешный, если в репозитории не появился новый снимок (защита от ложного успеха при отсутствии помеченных сервисов). 3. Применяет политику хранения с помощью `forget --prune` (хранятся 7 ежедневных, 4 еженедельных и 12 ежемесячных снимков). 4. Отправляет статус выполнения в Telegram. Если уведомление не удалось доставить, операция завершается с кодом ошибки `1` даже при успешном бэкапе, чтобы сбой в канале оповещения не остался незамеченным. Параметры подключения и учётные данные репозитория считываются из конфигурации `APEX_RESTIC_*` (см. [Справочник: Переменные окружения](/apex/reference/environment)). Состав сохраняемых данных определяется метками каждого отдельного сервиса. Например, для ядровых сервисов копируются только файлы конфигурации (динамические правила traefik, настройки xray и adguard), тогда как легко восстановимые данные уровня 3 (кэши и журналы) в снимок не включаются. --- **См. также:** - [Концепция: Модель безопасности](/apex/concepts/security-model) - [Справочник: Действия](/apex/reference/actions) - [Руководство: Добавление сервисной композиции](/apex/guides/service-composition)