Перейти к основному содержанию Перейти к навигации Перейти к нижнему колонтитулу

Правила Rediacc

Основные правила и соглашения для разработки приложений на платформе Rediacc. Охватывает Rediaccfile, compose, сетевую конфигурацию, хранение, CRIU и развёртывание.

Правила 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_ID6336Идентификатор сетевой изоляции
REDIACC_REPOSITORYabc123-...GUID репозитория
{SVCNAME}_IPHEARTBEAT_IP=127.0.24.195Loopback 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_IDID сетевой изоляции

Именование сервисов и маршрутизация

  • Имя сервиса в 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-root Docker находится по пути {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> для очистки остатков от устаревших удалений.