Правила Rediacc
Каждый репозиторий Rediacc работает в изолированной среде с собственным Docker-демоном, зашифрованным томом LUKS и выделенным диапазоном IP-адресов. Эти правила обеспечивают корректную работу вашего приложения в рамках этой архитектуры.
Rediaccfile
- Каждому репозиторию нужен Rediaccfile, bash-скрипт с функциями жизненного цикла.
- Функции жизненного цикла:
up(),down(). Необязательная:info(). up()запускает ваши сервисы.down()останавливает их.info()предоставляет информацию о состоянии (состояние контейнеров, последние логи, здоровье).- Rediaccfile подключается (source) через renet, имеет доступ к переменным оболочки, а не только к переменным окружения.
Доступные переменные окружения в Rediaccfile
| Переменная | Пример | Описание |
|---|---|---|
REDIACC_WORKING_DIR | /mnt/rediacc/mounts/abc123/ | Корневой путь смонтированного репозитория |
REDIACC_NETWORK_ID | 6336 | Идентификатор сетевой изоляции |
REDIACC_REPOSITORY | abc123-... | GUID репозитория |
{SVCNAME}_IP | HEARTBEAT_IP=127.0.24.195 | Loopback IP для каждого сервиса (имя сервиса в верхнем регистре) |
Минимальный Rediaccfile
#!/bin/bash
_compose() {
renet compose -- "$@"
}
up() {
_compose up -d
}
down() {
_compose down
}
Compose
- Используйте
renet compose, никогдаdocker compose, renet внедряет сетевую изоляцию, хост-сеть, loopback IP-адреса и метки сервисов. - НЕ устанавливайте
network_modeв вашем compose-файле, renet принудительно устанавливаетnetwork_mode: hostдля всех сервисов. Любое ваше значение будет перезаписано. - НЕ устанавливайте метки
rediacc.*, renet автоматически внедряетrediacc.network_id,rediacc.service_ipиrediacc.service_name. - Маппинги
ports:игнорируются в режиме хост-сети. Добавляйте меткуrediacc.service_portдля HTTP-маршрутизации (сервисы без этой метки не получают HTTP-маршрутов). Используйте меткиrediacc.tcp_ports/rediacc.udp_portsдля TCP/UDP-перенаправления. - Политики перезапуска (
restart: always,on-failureи др.) безопасны в использовании, renet автоматически удаляет их для совместимости с CRIU. Watchdog маршрутизатора автоматически восстанавливает остановленные контейнеры на основе исходной политики, сохранённой в.rediacc.json. - Опасные настройки заблокированы по умолчанию,
privileged: true,pid: host,ipc: hostи bind-монтирование системных путей отклоняются. Используйтеrenet compose --unsafeдля переопределения на ваш страх и риск.
Переменные окружения внутри контейнеров
Renet автоматически внедряет их в каждый контейнер:
| Переменная | Описание |
|---|---|
SERVICE_IP | Выделенный loopback IP этого контейнера |
REDIACC_NETWORK_ID | ID сетевой изоляции |
Именование сервисов и маршрутизация
- Имя сервиса в compose становится префиксом URL автомаршрута.
- Grand repos:
https://{service}.{repo}.{machine}.{baseDomain}(например:https://myapp.marketing.server-1.example.com). - Fork repos:
https://{service}-fork-{tag}.{repo}.{machine}.{baseDomain}(например:https://myapp-fork-staging.marketing.server-1.example.com). Разделитель-fork-предотвращает коллизии URL с именами сервисов grand repo. URL форка всегда использует существующий wildcard-сертификат родительского репозитория, поэтому новый сертификат не требуется. - Для пользовательских доменов используйте метки Traefik (примечание: пользовательские домены НЕ совместимы с fork, домен принадлежит grand repo).
Сеть
- Каждый репозиторий получает собственный Docker-демон по пути
/var/run/rediacc/docker-<networkId>.sock. - Каждый сервис получает уникальный loopback IP в подсети /26 (например,
127.0.24.192/26). - Привязка автоматическая: Сервисы могут привязываться к
0.0.0.0илиlocalhost, ядро прозрачно переписывает адрес на присвоенный сервису loopback IP. Явная привязка к${SERVICE_IP}по-прежнему работает, но больше не требуется. - Health-проверки могут использовать
localhostили${SERVICE_IP}. Пример:healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] - Межрепозиторные соединения блокируются ядром: Ядро автоматически блокирует соединения с loopback IP-адресами за пределами подсети
/26репозитория. Сервис в одном репозитории не может достичь сервисов в другом репозитории. - Межсервисное взаимодействие: Используйте имена сервисов (например,
db,redis), renet автоматически инжектит каждое имя сервиса как имя хоста, резолвящееся на правильный IP. DNS-имена Docker НЕ работают в хост-режиме, но имена сервисов через/etc/hostsработают. Избегайте встраивания${DB_IP}или подобного в постоянные файлы конфигурации (например, строки подключения, сохранённые в базе данных), при форке сырой IP переносится и указывает на неправильный репозиторий. Имена сервисов всегда корректно резолвятся для каждого репозитория. - Конфликты портов невозможны между репозиториями, у каждого свой Docker-демон и диапазон IP-адресов.
- Перенаправление портов TCP/UDP: Добавьте метки для открытия не-HTTP портов:
labels: - "rediacc.tcp_ports=5432,3306" - "rediacc.udp_ports=53"
Хранение
- Все данные Docker хранятся внутри зашифрованного репозитория,
data-rootDocker находится по пути{mount}/.rediacc/docker/dataвнутри тома LUKS. Именованные тома, образы и слои контейнеров, всё зашифровано, включено в резервные копии и автоматически форкается. - Bind-монтирование в
${REDIACC_WORKING_DIR}/...рекомендуется для ясности, но именованные тома также работают безопасно.volumes: - ${REDIACC_WORKING_DIR}/data:/data # bind-монтирование (рекомендуется) - pgdata:/var/lib/postgresql/data # именованный том (тоже безопасно) - Том LUKS монтируется в
/mnt/rediacc/mounts/<guid>/. - Снапшоты BTRFS захватывают весь файл поддержки LUKS, включая все данные bind-монтирования.
- Хранилище данных, это файл пула BTRFS фиксированного размера на системном диске. Используйте
rdc machine query --name <name> --systemдля просмотра эффективного свободного пространства. Расширяйте с помощьюrdc datastore resize.
CRIU (Живая миграция)
- Подключение через метку: Добавьте
rediacc.checkpoint=trueк контейнерам, которые хотите чекпоинтить. Контейнеры без метки (базы данных, кеши) запускаются заново и восстанавливаются через собственные механизмы (WAL, LDF, AOF). repo down --checkpointсохраняет состояние процессов перед остановкой, при следующемrepo upавтоматически восстанавливается. Это основной рабочий процесс на той же машине, проверенный и работающий.backup push --checkpointзахватывает состояние памяти работающих процессов и состояние диска для помеченных контейнеров, затем передаёт том на другую машину. Восстановление на целевой машине черезrepo up.repo fork --checkpointзахватывает состояние процессов перед форком и CoW-клонирует контрольную точку вместе с форком. ⚠️ На той же машине последующийrepo upна форке в настоящее время терпит неудачу сcriu failed: type RESTORE errno 0, пока родитель ещё работает. Upstream-баги CRIU checkpoint-restore/criu#478 / #514. Используйтеrepo down --checkpointдля сохранения и восстановления на месте илиbackup push --checkpointдля межмашинной миграции.repo upавтоматически обнаруживает данные чекпоинта и восстанавливает при наличии. Используйте--skip-checkpointдля принудительного чистого запуска.- Восстановление с учётом зависимостей: Использует compose
depends_onдля запуска баз данных первыми (ожидание healthy), затем CRIU-восстановление контейнеров приложения. - TCP-соединения становятся устаревшими после восстановления, поэтому приложения должны обрабатывать
ECONNRESETи переподключаться. CRIU не сохраняет активное состояние TCP-соединения при восстановлении ни в одном из поддерживаемых потоков. - Экспериментальный режим Docker включается автоматически на демонах каждого репозитория.
- CRIU устанавливается во время
rdc config machine setup. /etc/criu/runc.confпо умолчанию настроен сtcp-established.- Настройки безопасности контейнеров автоматически внедряются для помеченных контейнеров,
renet composeдобавляет следующее к контейнерам сrediacc.checkpoint=true:cap_add:CHECKPOINT_RESTORE,SYS_PTRACE,NET_ADMIN(минимальный набор для CRIU на ядре 5.9+)security_opt:apparmor=unconfined(поддержка AppArmor в CRIU ещё нестабильна)userns_mode: host(CRIU требует доступ к пространству имён init для/proc/pid/map_files)
- Контейнеры без метки работают с более чистым профилем безопасности (без дополнительных capabilities).
- Стандартный профиль seccomp Docker сохраняется, CRIU использует
PTRACE_O_SUSPEND_SECCOMP(ядро 4.3+) для временной приостановки фильтров во время checkpoint/restore. - НЕ устанавливайте CRIU capabilities вручную в файле compose, renet управляет ими на основе метки.
- Смотрите шаблон heartbeat для эталонной реализации, совместимой с CRIU.
Паттерны приложений, совместимых с CRIU
- Обрабатывайте
ECONNRESETна всех постоянных соединениях (пулы баз данных, вебсокеты, очереди сообщений). - Используйте библиотеки пулов соединений, поддерживающие автоматическое переподключение.
- Добавьте
process.on("uncaughtException")как страховочную сеть для ошибок устаревших сокетов от внутренних объектов библиотек. - Политики перезапуска управляются автоматически renet (удаляются для CRIU, watchdog обрабатывает восстановление).
- Не полагайтесь на DNS Docker, используйте loopback IP-адреса для межсервисного взаимодействия.
Политики безопасности хоста по операционной системе
На всех пяти официально поддерживаемых серверных операционных системах (см. Требования) Docker-демон каждого репозитория и запускаемые им контейнеры используют метки контейнеров по умолчанию. rdc config machine setup не устанавливает собственную политику SELinux и не создаёт профиль AppArmor.
- Ubuntu 24.04 / openSUSE Leap 16.0: AppArmor включён по умолчанию. Контейнеры работают под стандартным профилем docker-container. Единственное исключение это CRIU (
apparmor=unconfinedдля контейнеров сrediacc.checkpoint=true, как указано выше). - Fedora 43 / Oracle Linux 10: SELinux работает в режиме enforcing по умолчанию. Контейнеры получают стандартный контекст
container_t. Дополнительная установка политики не требуется. Если шаг настройки завершается с AVC-отказами, обратитесь к разделу Устранение неполадок: отказы SELinux. - Debian 13: AppArmor доступен, но по умолчанию не применяется ко всем доменам. Контейнеры по-прежнему используют профиль docker-container.
Флаг постуры безопасности, специфичный для ОС, не требуется; rdc и renet определяют запущенную среду и обеспечивают одинаковую изоляцию на уровне репозитория на всех пяти дистрибутивах.
Безопасность
- Шифрование LUKS обязательно для стандартных репозиториев. Каждый репозиторий имеет свой ключ шифрования.
- Учётные данные хранятся в конфигурации CLI (
~/.config/rediacc/rediacc.json). Потеря конфигурации означает потерю доступа к зашифрованным томам. - Никогда не коммитьте учётные данные в систему контроля версий. Используйте
env_fileи генерируйте секреты вup(). - Изоляция репозитория: Docker-демон, сеть и хранилище каждого репозитория полностью изолированы от других репозиториев на той же машине.
- Изоляция агентов: ИИ-агенты по умолчанию работают в режиме только fork. Каждый репозиторий имеет собственный SSH-ключ с серверным применением sandbox (ForceCommand
sandbox-gateway). Все соединения изолированы с помощью Landlock LSM, оверлея OverlayFS для домашней директории и TMPDIR для каждого репозитория. Доступ к файловой системе между репозиториями блокируется ядром. sudoотключён внутри sandbox репозитория по замыслу. Изоляция файловой системы Landlock требуетNoNewPrivs, что предотвращает любое повышение привилегий, поэтомуsudoзавершится с ошибкойno new privileges flag is set. Пользователь-владелец репозитория уже имеет все необходимые права для работы с точкой монтирования и Docker-сокетом репозитория. Для действительно привилегированных операций (установка пакетов хоста, настройка ядра) запускайте их вне sandbox или из функцииup()Rediaccfile, выполняемой через инфраструктурный путь.- Сетевой мост Docker отключён на каждом демоне репозитория. В
daemon.jsonкаждого репозитория заданы"bridge": "none"и"iptables": false, поэтому обычныйdocker run <image>создаёт контейнер только с loopback-интерфейсом и без исходящего сетевого подключения. Это не ошибка, а способ обеспечения межрепозиторной изоляции: ядерные eBPF-хуки, которые блокируют доступ из одного репозитория к loopback IP-адресам другого, применяются только к контейнерам, работающим в сетевом пространстве имён хоста. Для production-сервисов используйтеrenet compose, который автоматически внедряетnetwork_mode: host. Для разовых контейнеров в оболочке передавайте--network hostявно.
Развёртывание
rdc repo upавтоматически монтирует том LUKS, если он не смонтирован, затем выполняетup()во всех Rediaccfile.rdc repo downвыполняетdown()и останавливает Docker-демон.rdc repo down --unmountтакже закрывает том LUKS (блокирует зашифрованное хранилище).- Форки (
rdc repo fork) создают CoW-клон (copy-on-write) с новым GUID и networkId за константное время, независимо от размера репозитория. BTRFS reflink дублирует метаданные образа, а не сами данные, поэтому репозиторий объёмом 100 ГБ форкается за те же несколько секунд, что и репозиторий объёмом 1 ГБ. Форк разделяет ключ шифрования родителя. - Takeover (
rdc repo takeover --name <fork> -m <machine>) заменяет данные grand-репозитория данными форка. Grand сохраняет свою идентичность (GUID, networkId, домены, автозапуск, цепочку резервных копий). Старые производственные данные сохраняются как резервный форк. Использование: тестировать обновление на форке, проверить, затем выполнить takeover в продакшн. Откатить с помощьюrdc repo takeover --name <backup-fork> -m <machine>. - Маршруты прокси становятся активными примерно через 3 секунды после развёртывания. Предупреждение «Proxy is not running» во время
repo upявляется информационным в средах ops/dev. rdc repo upиrdc repo fork --upвыводят шаблон URL в конце развёртывания для сервисов, помеченныхrediacc.service_port. Замените{service}на имя вашего открытого сервиса, чтобы получить точный URL. Сервисы безrediacc.service_port(базы данных, воркеры) не получают маршрутов и не отображаются.
Распространённые ошибки
- Использование
docker composeвместоrenet compose, контейнеры не получат сетевую изоляцию. - Политики перезапуска безопасны, renet автоматически удаляет их, watchdog обрабатывает восстановление.
- Использование
privileged: true, не нужно, renet вместо этого внедряет специальные capabilities для CRIU. - Жёсткое кодирование сырых IP-адресов в постоянных файлах конфигурации - используйте имена сервисов для соединений, чтобы сохранить изоляцию форков.
- Использование
rdc term connect -cкак обходного пути для неудачных команд, вместо этого сообщайте об ошибках. repo deleteвыполняет полную очистку, включая loopback IP-адреса и systemd-юниты. Запуститеrdc machine prune --name <name>для очистки остатков от устаревших удалений.