docs(apex): document safe operations and replication ownership

This commit is contained in:
deytenit committed 2026-10-26 12:27:09 +03:00
1 parent 47c70471e1
commit 582fac434f
5 files changed
+205 -16

No files matched your search

@@ -0,0 +1,94 @@
---
title: Composition replication
description: Patterns, ownership, and acceptance requirements for replicated applications.
weight: 28
---
Replication belongs to an application deployment across independently owned node
repositories. It does not clone a node or turn unrelated compositions into a
cluster. Each node pins commons, owns its secrets and storage, and runs APEX
commands locally.
This contract describes design requirements. It does not certify a deployment's
availability or provide a shared failover daemon, readiness adapter, or promotion
command. Those implementations and their evidence belong to the participating
applications and node repositories.
## Choose a pattern
| Pattern | Responsibility |
|---|---|
| Stateless copies | Deploy compatible configuration and route only to ready instances. |
| Replicated backends | Use application-supported shared state; each backend owns its consistency and recovery. |
| Application-native cluster | Follow the application's membership, replication, election, and recovery procedures. |
| Active instance with standby | Transfer state consistently and fence the previous writer before promotion. |
| Recovery-only deployment | Restore a verified backup and activate explicitly when live replication is not validated. |
A composition may combine patterns. Duplicate web instances do not imply that
duplicate schedulers or workers are safe. Do not copy live database directories
as a generic replication method. Backups remain necessary for corruption,
accidental deletion, and total group loss.
## Record the deployment contract
Keep the following non-secret information beside each participating composition:
- Group identity, members, failure domains, desired roles, and compatible versions.
- Every mutable state store, its write authority, replication method, and recovery procedure.
- Dependencies, private endpoints, required ports, and credentials referenced by location.
- Shared versus node-specific configuration and the order of coordinated updates.
- Readiness, ingress withdrawal, joining, draining, promotion, rejoining, and full-outage recovery.
- Recovery-time targets, possible acknowledged-data loss, and session or revocation behavior.
Distinct hostnames do not prove independent failure domains. Two application
instances depending on one unreplicated backend do not survive loss of that
backend. Secrets that must match across replicas stay outside Git; node-specific
credentials remain distinct.
## Network and lifecycle requirements
Validate the actual protocols over the existing private transport, including
peer identity, reconnects, port restrictions, and container-network replacement.
Node-local Docker names and bridge addresses do not provide cross-host discovery.
Do not introduce another network overlay as a side effect of replication setup.
Container health alone is insufficient: readiness must reflect required
dependencies and write authority. Traffic routing must not promote a database
or send application writes to an unpromoted standby. Multiple ingress paths to
one backend provide ingress redundancy, not backend replication.
Initial creation, joining, and ordinary restart are separate operations. An
ordinary restart must not replay a seed, create a replacement cluster, discard
existing data, or promote a replica. A returning former primary stays fenced
until reconciled or reseeded and accepted as a replica. Image rollback does not
automatically reverse schema changes.
## Controlled SSO promotion
The selected Daedalus–Metis pattern is active/standby with native asynchronous
database and session replication over existing Xray transport. Icarus is not a
member of this application group. No automatic promotion controller or election
service is implied by this pattern.
Before promotion, positively fence the previous writer. An unreachable SSH or
tunnel endpoint is not proof of fencing. Record replication positions, possible
lost changes, and the explicit native role changes. Preserve enrolled directory
data, account identifiers, groups, and application encryption secrets.
Recent account changes, sessions, or revocations can be lost with asynchronous
replication. Verify login, session reset, and stale-session rejection after
promotion; resetting application sessions does not revoke every downstream
token. Measure operator-driven recovery time rather than promising automatic
failover or zero data loss. Node-specific runbooks own the executable procedure.
## Acceptance evidence
For each claimed guarantee, exercise relevant process failures, loss of each
location, network partitions, stale members, rejoining, and rolling updates.
Observe end-user operations and dependency state. Record recovery time, lost
acknowledged data, conflicting writers, session behavior, and manual intervention.
Test full-group restoration separately.
Standalone host enrollment through `ci/scripts/init-node.py` ends before
application data migration or replication-group creation. It does not authorize
formatting disks or promoting writers during a composition operation.
@@ -12,7 +12,8 @@ weight: 24
| Step | Effect |
|---|---|
| `configure/base` | Ensures a Debian base: package index update, essential packages (`curl`, `wget`, `git`, `rsyslog`), rsyslog running, `ufw` installed, and the `ufw-docker` helper at `~/.local/bin/ufw-docker`. |
| `configure/base` | Installs missing Debian packages after checking that APT's simulation contains no upgrades or removals, ensures rsyslog is running, and verifies the pinned `/usr/local/bin/ufw-docker` before privileged execution. Avoid concurrent package operations. |
| `configure/timezone` | Applies `configs/timezone` when present and refreshes active cron after a timezone change. Supports `--dry-run`. |
| `configure/ufw` | Applies host rules, injects the managed kernel-rule blocks, applies container rules via `ufw-docker`. Supports `--dry-run`. |
| `configure/crowdsec` | Installs CrowdSec if absent, deploys `configs/crowdsec/` to `/etc/crowdsec/`, installs collections, and the firewall bouncer when configured. Supports `--dry-run`. |
| `configure/cron` | Renders `configs/cron/crontab` through the template layer and installs it — with preview, empty-render refusal (exit `65`), and rollback on a failed install. Supports `--dry-run`. |
@@ -27,10 +28,40 @@ After `configure/ufw`, restart `ufw` deliberately (`sudo systemctl restart ufw`)
apex compose up # core first, then services alphabetically
apex compose down # reverse order
apex compose restart
apex compose up --dry-run # print the commands only
apex compose --dry-run up # print the commands only
apex compose -p apex restart traefik
apex compose -p sso up -d
```
Extra arguments pass through to `docker compose` per project. Each project's `.env` and `apex.env` are supplied automatically when present.
Put wrapper options (`-p` and `--dry-run`) before the action. Extra arguments pass
through to Docker Compose for the selected project. Each project's `.env` and
`apex.env` are supplied automatically when present. Positional targeting remains
available as `apex compose restart apex traefik` or `apex compose up -d apex`;
prefer `-p` when arguments could also name a composition.
APEX does not unlink Xray sockets during Compose operations. Keep node-owned
cleanup in Xray's startup entrypoint; unrelated service restarts and unchanged
`up` operations can leave Xray running. When a mount or other container definition
changes, use targeted `up -d` to recreate it: `restart` retains the old definition.
### Direct core Compose commands
```bash
apex env --sync
cd compositions/apex
docker compose config --quiet
docker compose restart traefik
```
Sync preserves existing secret and UID/GID text in `.env` and its tier-storage
symlink. A managed block loads committed `apex.env` settings, including profiles,
then synthesized node/path values. Writes use mode `0600`. Resync after changing
those settings or paths; do not hand-edit the managed block. Docker's shell
environment still overrides file values.
`eval "$(apex env)"`, `apex env --dotenv`, and `apex env --write generated.env`
export or save generated APEX values only. They do not load composition secrets
or replace the full `--sync` bridge. Output modes are mutually exclusive.
## Backups {#backups}
@@ -4,7 +4,7 @@ description: "Every commons action: arguments and behavior."
weight: 32
---
The sixteen [commons](/apex/glossary#commons) actions, by group. Arguments are shown as the parser accepts them; optional arguments are bracketed. Exit codes follow the [engine convention](/apex/reference/cli#exit-codes).
The [commons](/apex/glossary#commons) actions, by group. Arguments are shown as the parser accepts them; optional arguments are bracketed. Exit codes follow the [engine convention](/apex/reference/cli#exit-codes).
## configure {#configure}
@@ -12,13 +12,19 @@ The sixteen [commons](/apex/glossary#commons) actions, by group. Arguments are
`apex configure [--dry-run]`
Runs the whole suite in fixed order — `base`, `ufw`, `crowdsec`, `cron`, `systemd`, `routing` — and stops at the first failing step, propagating its exit code. `--dry-run` is forwarded to the steps that support it.
Runs the suite in order: `base`, `timezone`, `ufw`, `crowdsec`, `cron`, `systemd`, `routing`, then additional node actions. A failing step contributes a nonzero exit status; later steps may still run. `--dry-run` is forwarded only to steps that support it, so it is not a guarantee that the entire umbrella command is read-only.
### configure/base
`apex configure/base`
Debian-only guard (exit `1` elsewhere). Updates the package index, installs the essential packages (`curl`, `wget`, `git`, `rsyslog`), ensures rsyslog is running, installs `ufw` when absent, and downloads the `ufw-docker` helper to `~/.local/bin/ufw-docker` (skipped when already present).
Debian-only guard (exit `1` elsewhere). Checks installed package state for `curl`, `wget`, `git`, `rsyslog`, and `ufw`; installs missing packages and ensures rsyslog is running. Refuses an APT simulation containing upgrades or removals and uses `--no-upgrade --no-remove`. Avoid concurrent package operations: simulation and installation are separate transactions. Verifies the immutable revision and SHA-256 of `/usr/local/bin/ufw-docker` before running it as root. Unsafe paths and unverified downloads are rejected; an executable file alone is not trusted.
### configure/timezone
`apex configure/timezone [--dry-run]`
Applies the IANA zone named in `configs/timezone` and refreshes active cron after a change. An absent declaration preserves the current timezone; an invalid zone fails before changing it.
### configure/ufw
@@ -110,9 +116,19 @@ Two passes: (1) [anchor-IP](/apex/glossary#anchor-ip) validation over `compositi
### compose
`apex compose <action> [--dry-run] [extra...]`
`apex compose [-p <composition>] [--dry-run] <action> [extra...]`
Orchestrates `docker compose <action>` across the node: the core project first, then services alphabetically (reversed for `down`). `up` implies `-d`; `.env`/`apex.env` are passed per project when present; extra arguments pass through; `--dry-run` (accepted in any position) prints commands instead of executing.
Without a target, visits core first and other compositions alphabetically, reversed for `down`. `-p` selects one composition or `all`; `up` defaults to detached mode. `.env` then `apex.env` are passed per project, with generated identity/path values in the process environment. Remaining arguments pass through to Docker Compose. Wrapper options precede the action; `--dry-run` prints commands without executing them.
Compatibility forms include `apex compose restart apex traefik` and `apex compose up -d apex`. Use explicit `-p` to distinguish a composition from a service or option value. No Compose action removes Xray socket paths; cleanup belongs to the node's Xray startup lifecycle.
## env {#env}
`apex env [--export | --dotenv | --write <path> | --sync]`
Default output is shell-quoted APEX exports for `eval "$(apex env)"`. `--dotenv` emits dotenv syntax; `--write` writes generated values to a separate file, including a relative filename. These modes do not read composition credentials or merge `apex.env`.
`--sync` preserves existing `compositions/apex/.env` text and updates only its managed block: committed `apex.env` settings first, generated identity/path values last. This includes non-APEX settings such as `COMPOSE_PROFILES` and `TZ`, allowing bare Docker Compose commands in the core directory. Existing tier symlinks remain intact, and synchronized files use mode `0600`. Resync after changing source settings or tier paths. Malformed managed markers fail without rewriting uncertain content. Shell environment values still have Docker Compose precedence.
---
@@ -12,7 +12,8 @@ weight: 24
| Шаг | Эффект |
|---|---|
| `configure/base` | Готовит базовую систему Debian: обновляет списки пакетов, ставит базовые утилиты (`curl`, `wget`, `git`, `rsyslog`), запускает службу rsyslog, устанавливает `ufw` и вспомогательный скрипт `ufw-docker` в `~/.local/bin/ufw-docker`. |
| `configure/base` | Устанавливает недостающие пакеты Debian после проверки плана APT на обновления и удаления, запускает rsyslog и проверяет закреплённую версию `/usr/local/bin/ufw-docker` перед запуском от root. Не запускайте другие пакетные операции одновременно. |
| `configure/timezone` | Применяет `configs/timezone`, если файл есть, и перезапускает активную службу cron после смены часового пояса. Поддерживает `--dry-run`. |
| `configure/ufw` | Применяет правила хоста, настраивает цепочки правил ядра и пробрасывает правила для контейнеров через `ufw-docker`. Поддерживает флаг `--dry-run`. |
| `configure/crowdsec` | Устанавливает CrowdSec (если он ещё не поставлен), копирует `configs/crowdsec/` в `/etc/crowdsec/`, ставит коллекции и firewall bouncer (если включён в настройках). Поддерживает флаг `--dry-run`. |
| `configure/cron` | Рендерит `configs/cron/crontab` через шаблонизатор и устанавливает расписание. Предусмотрены предпросмотр, аварийная остановка при пустом результате (код выхода 65) и откат при ошибке установки. Поддерживает флаг `--dry-run`. |
@@ -27,10 +28,41 @@ weight: 24
apex compose up # сначала core, затем сервисы по алфавиту
apex compose down # обратный порядок
apex compose restart
apex compose up --dry-run # только напечатать команды
apex compose --dry-run up # только напечатать команды
apex compose -p apex restart traefik
apex compose -p sso up -d
```
Все дополнительные аргументы движок передаёт напрямую в `docker compose` каждого проекта. Файлы `.env` и `apex.env` проектных каталогов подставляются автоматически при их наличии.
Указывайте параметры APEX (`-p` и `--dry-run`) перед действием. Остальные аргументы
передаются Docker Compose для выбранного проекта. Файлы `.env` и `apex.env`
подключаются автоматически, если существуют. Формы `apex compose restart apex traefik`
и `apex compose up -d apex` сохраняются; если имя сервиса или значение параметра
совпадает с именем композиции, выбирайте цель через `-p`.
APEX не удаляет сокеты Xray при операциях Compose. Очистка остаётся
в скрипте запуска Xray на узле: перезапуск другого сервиса или повторный `up`
могут оставить Xray работающим. После изменения монтирования или конфигурации
контейнера используйте `up -d` для нужной композиции; `restart` сохраняет прежнюю
конфигурацию контейнера.
### Прямой запуск Compose для core
```bash
apex env --sync
cd compositions/apex
docker compose config --quiet
docker compose restart traefik
```
Синхронизация сохраняет текст секретов и UID/GID в `.env`, а также ссылку
на файл в хранилище tier. Управляемый блок содержит настройки `apex.env`, включая
профили, затем вычисленные значения узла и путей. Файл записывается с правами
`0600`. Повторите синхронизацию после изменения настроек или путей; не редактируйте
управляемый блок вручную. Переменные оболочки сохраняют приоритет Docker Compose.
`eval "$(apex env)"`, `apex env --dotenv` и `apex env --write generated.env`
выводят или записывают только вычисленные значения APEX. Они не загружают секреты
композиции и не заменяют `--sync`. Выбирайте один режим вывода за вызов.
## Резервные копии {#backups}
@@ -4,7 +4,7 @@ description: "Каждое действие commons: аргументы и по
weight: 32
---
Шестнадцать действий [«commons»](/apex/glossary#commons) (общего репозитория), разбитых по группам. Аргументы показаны в том виде, в котором их принимает парсер; необязательные аргументы заключены в квадратные скобки. Коды возврата следуют [соглашению движка](/apex/reference/cli#exit-codes).
Действия [commons](/apex/glossary#commons) по группам. Аргументы показаны в том виде, в котором их принимает парсер; необязательные аргументы заключены в квадратные скобки. Коды возврата следуют [соглашению движка](/apex/reference/cli#exit-codes).
## configure {#configure}
@@ -12,13 +12,19 @@ weight: 32
`apex configure [--dry-run]`
Запускает весь набор в фиксированном порядке (`base`, `ufw`, `crowdsec`, `cron`, `systemd`, `routing`) и останавливается на первом неудачном шаге, возвращая его код возврата. Флаг `--dry-run` передаётся шагам, которые его поддерживают.
Запускает `base`, `timezone`, `ufw`, `crowdsec`, `cron`, `systemd`, `routing`, затем дополнительные действия узла. Ошибка шага даёт ненулевой итоговый код; последующие шаги могут продолжить работу. Флаг `--dry-run` передаётся только тем шагам, которые его поддерживают, поэтому не гарантирует отсутствие изменений для всей команды.
### configure/base
`apex configure/base`
Проверяет, что операционная система — Debian (иначе завершается с кодом `1`). Обновляет индекс пакетов, устанавливает необходимые пакеты (`curl`, `wget`, `git`, `rsyslog`), проверяет статус службы `rsyslog`, устанавливает `ufw`, если его нет, и загружает вспомогательную утилиту `ufw-docker` в `~/.local/bin/ufw-docker` (если утилита уже есть, загрузка пропускается).
Проверяет, что операционная система — Debian; иначе завершается с кодом `1`. Проверяет состояние пакетов `curl`, `wget`, `git`, `rsyslog` и `ufw`, устанавливает недостающие и запускает rsyslog. Отклоняет план APT с обновлениями или удалениями и использует `--no-upgrade --no-remove`. Не запускайте другие пакетные операции одновременно: проверка плана и установка выполняются отдельно. Перед запуском `/usr/local/bin/ufw-docker` от root проверяет закреплённую ревизию и SHA-256. Небезопасные пути и непроверенные загрузки отклоняются; одних прав на исполнение недостаточно.
### configure/timezone
`apex configure/timezone [--dry-run]`
Применяет часовой пояс IANA из `configs/timezone` и перезапускает активную службу cron после изменения. Если файла нет, сохраняет текущий пояс; неверное имя приводит к ошибке до внесения изменений.
### configure/ufw
@@ -110,9 +116,19 @@ weight: 32
### compose
`apex compose <action> [--dry-run] [extra...]`
`apex compose [-p <composition>] [--dry-run] <action> [extra...]`
Оркеструет запуск `docker compose <action>` по всему узлу: сначала основной проект, затем сервисы в алфавитном порядке (в обратном — для команды `down`). Команда `up` по умолчанию использует ключ `-d`; файлы `.env` и `apex.env` подключаются для каждого проекта при их наличии; дополнительные аргументы пробрасываются дальше; флаг `--dry-run` (принимается в любой позиции) выводит сформированные команды без их выполнения.
Без цели обходит сначала core, затем остальные композиции по алфавиту; для `down` порядок обратный. Параметр `-p` выбирает одну композицию или `all`. Команда `up` по умолчанию добавляет `-d`; файлы `.env` и `apex.env` подключаются в этом порядке, вычисленные значения узла и путей передаются через окружение. Параметры APEX ставятся перед действием, остальные аргументы передаются Docker Compose. Флаг `--dry-run` печатает команды без запуска.
Сохраняются формы `apex compose restart apex traefik` и `apex compose up -d apex`. Используйте `-p`, чтобы явно отличить композицию от сервиса или значения параметра. Команда не удаляет сокеты Xray: очисткой управляет скрипт запуска Xray на узле.
## env {#env}
`apex env [--export | --dotenv | --write <path> | --sync]`
По умолчанию выводит экспорты APEX для `eval "$(apex env)"` с экранированием оболочки. `--dotenv` выводит формат dotenv; `--write` записывает вычисленные значения в отдельный файл, в том числе по относительному пути. Эти режимы не читают секреты композиции и не объединяют `apex.env`.
Режим `--sync` сохраняет пользовательский текст `compositions/apex/.env` и обновляет управляемый блок: сначала настройки `apex.env`, затем вычисленные значения. В блок входят `COMPOSE_PROFILES` и `TZ`, поэтому Compose можно запускать напрямую из каталога core. Ссылки tier сохраняются, файл получает права `0600`. Повторяйте синхронизацию после изменения исходных настроек или путей. Некорректные маркеры останавливают запись; переменные оболочки сохраняют приоритет Docker Compose.
---