🤖 PR generated for branch `fix/cyrillic-fonts-dev-certs-and-page-head`.
### Changes Summary
- **Fonts**: Add Cyrillic glyph subsets for Lato, EB Garamond, and Fira
Code.
- **Dev**: Support remote Root CA and encrypted dev CA key in
`.env.dev`.
- **UI & Kits**: Add size variant to `Breadcrumbs` component and enlarge
`PageHead` breadcrumbs with tuned collapse scroll threshold.
- **ESLint**: Add `no-hanging-particles` i18n & markdown typography rule
with auto-fixer.
- **Content & i18n**: Apply `ru-text` editorial and typography polish
(em dashes, number ranges, «ё» restoration, non-breaking spaces) across
`services/www` and `services/docs`.
10 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. Внутри каждого уровня поддерживается общий каталогshared/с поддиректорией для каждого проекта, а внутри каталога уровня проекта создаётся относительная ссылкаshared, ведущая обратно в общую зону.
Каждый проект дополнительно получает символьную ссылку compositions/<project>/.env → <tier1-root>/<project>/.env (создаётся пустым, если файл отсутствует). В нём хранятся незакоммиченные секреты (см. Концепция: Композиции и общее ядро). Ссылки @tierN и файлы .env исключены из git через .gitignore, благодаря чему репозиторий остаётся чистым источником кода.
Если по пути предполагаемой символьной ссылки уже существует обычный файл или каталог, действие предупреждает об этом и запрашивает подтверждение перед удалением. При отказе (включая неинтерактивный EOF) создание ссылки пропускается, а выполнение продолжается дальше.
Пользователи и группы
Команда apex tiers/useradd создаёт по одному заблокированному системному пользователю на проект — noroot-<project> (с санитизацией имени и собственной первичной группой), а также общефлотовую группу noroot-shared, в которую входят все пользователи проектов. Затем сгенерированные идентификаторы прописываются в файл .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 |
Рекурсивно; идентификаторы читаются из .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_* (см. Справочник: Переменные окружения). Состав сохраняемых данных определяется метками каждого отдельного сервиса. Например, для ядровых сервисов копируются только файлы конфигурации (динамические правила traefik, настройки xray и adguard), тогда как легко восстановимые данные уровня 3 (кэши и журналы) в снимок не включаются.
См. также: