Сервисы
Если вы не уверены, какой инструмент использовать, см. rdc vs renet.
На этой странице описывается развертывание и управление контейнеризированными сервисами: Rediaccfile, сетевое взаимодействие сервисов, запуск/остановка, массовые операции и автозапуск.
Rediaccfile
Rediaccfile, это Bash-скрипт, определяющий, как ваши сервисы запускаются и останавливаются. Он должен называться Rediaccfile или rediaccfile (регистр не имеет значения) и размещаться внутри смонтированной файловой системы репозитория.
Rediaccfile обнаруживается в двух местах:
- В корне пути монтирования репозитория
- В поддиректориях первого уровня пути монтирования (не рекурсивно)
Скрытые директории (имена начинаются с .) пропускаются.
Функции жизненного цикла
Rediaccfile содержит до двух функций:
| Функция | Когда выполняется | Назначение | Поведение при ошибке |
|---|---|---|---|
up() | При запуске | Запуск сервисов (например, renet compose -- up -d) | Ошибка корневого Rediaccfile, критическая (останавливает всё). Ошибки в поддиректориях, некритические (логируются, продолжение к следующему) |
down() | При остановке | Остановка сервисов (например, renet compose -- down) | Максимальные усилия, ошибки логируются, но все Rediaccfile всегда обрабатываются |
Обе функции необязательны. Если функция не определена в Rediaccfile, она тихо пропускается.
Порядок выполнения
- Запуск (
up): Сначала корневой Rediaccfile, затем поддиректории в алфавитном порядке (от A до Z). - Остановка (
down): Поддиректории в обратном алфавитном порядке (от Z до A), затем корневой последним.
Переменные окружения
При выполнении функции Rediaccfile доступны следующие переменные окружения:
| Переменная | Описание | Пример |
|---|---|---|
REDIACC_WORKING_DIR | Путь монтирования репозитория | /mnt/rediacc/mounts/abc123 |
REDIACC_REPOSITORY | GUID репозитория | a1b2c3d4-e5f6-... |
REDIACC_NETWORK_ID | Идентификатор сети (целое число) | 2816 |
DOCKER_HOST | Docker-сокет для изолированного демона данного репозитория | unix:///var/run/rediacc/docker-2816.sock |
{SERVICE}_IP | Loopback IP для каждого сервиса, определенного в .rediacc.json | POSTGRES_IP=127.0.11.2 |
Переменные {SERVICE}_IP автоматически генерируются из .rediacc.json. Соглашение об именовании преобразует имя сервиса в верхний регистр с заменой дефисов на подчеркивания, а затем добавляет _IP. Например, listmonk-app становится LISTMONK_APP_IP.
Предупреждение: Не используйте
sudo dockerв Rediaccfile. Командаsudoсбрасывает переменные окружения, из-за чего теряетсяDOCKER_HOSTи команды Docker обращаются к системному демону вместо изолированного демона репозитория. Это нарушает изоляцию контейнеров и может вызвать конфликты портов. Rediacc автоматически блокирует выполнение при обнаруженииsudo dockerбез-E.Используйте
renet composeв ваших Rediaccfile, он автоматически обрабатываетDOCKER_HOST, внедряет сетевые метки для обнаружения маршрутов и настраивает сетевое взаимодействие сервисов. Подробнее о том, как сервисы предоставляются через обратный прокси, см. в разделе Сетевое взаимодействие. Если вы вызываете Docker напрямую, используйтеdockerбезsudo, функции Rediaccfile уже запускаются с достаточными привилегиями. Если необходимо использовать sudo, применяйтеsudo -E dockerдля сохранения переменных окружения.
Пример
#!/bin/bash
up() {
echo "Starting services..."
renet compose -- up -d
}
down() {
echo "Stopping services..."
renet compose -- down
}
Важно: Всегда используйте
renet compose --вместоdocker compose. Обёрткаrenet composeобеспечивает host-сеть, распределение IP-адресов и метки обнаружения сервисов, необходимые для renet-proxy. Возможности CRIU checkpoint/restore добавляются к контейнерам с меткойrediacc.checkpoint=true. Прямое использованиеdocker composeотклоняется валидацией Rediaccfile. Подробнее см. в разделе Сетевое взаимодействие.
Пример с несколькими сервисами
Для проектов с несколькими независимыми группами сервисов используйте поддиректории:
/mnt/rediacc/mounts/my-app/
├── Rediaccfile # Корневой: общая настройка
├── docker-compose.yml
├── database/
│ ├── Rediaccfile # Сервисы базы данных
│ └── docker-compose.yml
├── backend/
│ ├── Rediaccfile # API-сервер
│ └── docker-compose.yml
└── monitoring/
├── Rediaccfile # Prometheus, Grafana и т.д.
└── docker-compose.yml
Порядок выполнения для up: корневой, затем backend, database, monitoring (A-Z).
Порядок выполнения для down: monitoring, database, backend, затем корневой (Z-A).
Сетевое взаимодействие сервисов (.rediacc.json)
Каждый репозиторий получает подсеть /26 (64 IP-адреса) в loopback-диапазоне 127.x.x.x. Сервисы привязываются к уникальным loopback IP-адресам, что позволяет им работать на одних и тех же портах без конфликтов.
Файл .rediacc.json
Сопоставляет имена сервисов с номерами слотов. Каждый слот соответствует уникальному IP-адресу в подсети репозитория.
{
"services": {
"api": {"slot": 0},
"postgres": {"slot": 1},
"redis": {"slot": 2}
}
}
Автоматическая генерация из Docker Compose
Вам не нужно создавать .rediacc.json вручную. При выполнении rdc repo up Rediacc автоматически:
- Сканирует все директории, содержащие Rediaccfile, на наличие compose-файлов (
docker-compose.yml,docker-compose.yaml,compose.ymlилиcompose.yaml) - Извлекает имена сервисов из секции
services: - Назначает следующий доступный слот каждому новому сервису
- Сохраняет результат в
{repository}/.rediacc.json
Вычисление IP-адресов
IP-адрес сервиса вычисляется из идентификатора сети репозитория и слота сервиса. Идентификатор сети распределяется по второму, третьему и четвёртому октетам loopback-адреса 127.x.y.z. Каждый сервис получает смещение slot + 2 (смещения 0 и 1 зарезервированы).
| Offset | Address | Purpose |
|---|---|---|
| .0 | 127.0.11.0 | Network address (reserved) |
| .1 | 127.0.11.1 | Gateway (reserved) |
| .2 – .62 | 127.0.11.2 – 127.0.11.62 | Services (slot + 2) |
| .63 | 127.0.11.63 | Broadcast (reserved) |
Пример для идентификатора сети 2816 (0x0B00), базовый адрес 127.0.11.0:
| Сервис | Слот | IP-адрес |
|---|---|---|
| api | 0 | 127.0.11.2 |
| postgres | 1 | 127.0.11.3 |
| redis | 2 | 127.0.11.4 |
Каждый репозиторий поддерживает до 61 сервиса (слоты от 0 до 60).
Использование IP-адресов сервисов в Docker Compose
Поскольку каждый репозиторий работает с изолированным Docker-демоном, renet compose автоматически настраивает network_mode: host для всех сервисов. Ядро прозрачно перезаписывает вызовы bind() на назначенный loopback IP-адрес сервиса, поэтому сервисы могут привязываться к 0.0.0.0 или localhost без конфликтов. Для подключения к другим сервисам используйте имя сервиса — renet внедряет каждое имя сервиса как имя хоста, которое всегда разрешается в правильный IP, даже в форках:
services:
postgres:
image: postgres:16
environment:
PGDATA: /var/lib/postgresql/data
POSTGRES_PASSWORD: secret
# Явный listen_addresses не нужен -- ядро перезаписывает bind на правильный loopback IP
api:
image: my-api:latest
environment:
DATABASE_URL: postgresql://postgres:secret@postgres:5432/mydb # использовать имя сервиса
LISTEN_ADDR: 0.0.0.0:8080 # ядро перезаписывает на IP сервиса
Имена сервисов для подключений: Используйте имя сервиса (например,
postgres,redis) для подключения к другим сервисам — renet автоматически сопоставляет каждое имя сервиса с его loopback IP через/etc/hosts. Встраивание${POSTGRES_IP}в строки подключения, хранящиеся в базах данных или файлах конфигурации, зафиксирует необработанный IP, что нарушит изоляцию форков и является ошибкой валидации. Переменные${SERVICE_IP}по-прежнему доступны для явного использования, но привязка обрабатывается автоматически ядром.
Примечание: Не добавляйте
network_mode: hostвручную,renet composeвнедряет его автоматически. Политики перезапуска (например,restart: always) безопасны для использования, renet автоматически удаляет их для совместимости с CRIU, а watchdog маршрутизатора управляет восстановлением контейнеров.
Восстановление контейнеров и политика перезапуска
renet и Docker намеренно расходятся во мнениях о том, как обрабатывать перезапуски контейнеров. Понимание этого разделения важно при диагностике причин, по которым контейнер вернулся или не вернулся.
Трансляция политики перезапуска. Когда вы пишете restart: always (или unless-stopped, или on-failure) в файле compose, renet удаляет её при синтезировании фактического compose-развертывания и заменяет на restart: no. Исходное значение сохраняется в .rediacc.json репозитория под services.<name>.restart_policy. Это предотвращает вмешательство автоматического перезапуска на уровне Docker-демона в работу CRIU checkpoint/restore (перезапуск, управляемый демоном, возобновился бы с устаревшего состояния до checkpoint).
Применение watchdog. Watchdog маршрутизатора периодически запускается на каждой машине. При каждом тике:
- Читает
.rediacc.jsonдля каждого репозитория и находит сервисы с восстанавливаемойrestart_policy. - Перечисляет все контейнеры для демона этого репозитория, определяет остановленные и перезапускает их согласно сохранённой политике. Льготный период 30 секунд предотвращает конфликт с оператором, который только что выполнил
docker stop. - Та же петля также обрабатывает
/var/run/rediacc/cold-backup-<guid>.running.json(см. семантику cold backup). Перечисленные контейнеры перезапускаются независимо от сохранённой политики, поскольку sidecar означает “renet намеренно остановил их и обязан оператору перезапуском.”
Почему on-failure может выглядеть сломанным. Политика on-failure Docker перезапускается только когда контейнер завершается с ненулевым кодом. Штатная остановка (exit 0) от docker stop или завершения демона не является “сбоем” и НЕ запускает перезапуск ни по нативной логике Docker, ни по пути сохранённой политики watchdog. Cold backup sidecar является страховочной сетью: любой контейнер, который мы остановили намеренно, перезапускается независимо от его политики.
Как интерпретировать состояние во время выполнения:
docker inspect <container>→RestartPolicy.Name: всегда будетnoдля контейнеров, управляемых renet. Не полагайтесь на это для семантической политики..rediacc.jsonв корне монтирования репозитория →services.<name>.restart_policy: реальное намерение.docker ps --format '{{.Status}}': состояние во время выполнения.
Как исправить расхождение. Если сохранённая политика контейнера в .rediacc.json неверна (например, потому что вы изменили compose, но никогда не пересоздавали контейнер), повторно запустите rdc repo up --name <repo> -m <machine>. Контейнер будет пересоздан с записанной обновлённой политикой.
Экспериментально: Восстановление на основе cold backup sidecar и флаг
--sync-certsвrdc machine queryпоявились в renet 0.9+. Более старые версии полностью полагаются на сохранённуюrestart_policyдля восстановления watchdog, что может оставить контейнерыon-failureзависшими после cold backup.
Сетевой мост Docker отключён для демонов, управляемых rediacc. Каждый демон репозитория настроен с
"bridge": "none"и"iptables": false. Обычныйdocker run <image>внутри оболочки репозитория всё равно запустится, но контейнер получит только loopback-интерфейс и не будет иметь DNS или исходящего сетевого подключения. Это сделано намеренно, поскольку изоляция loopback между репозиториями обеспечивается eBPF cgroup-хуками, которые обойдёт контейнер в режиме bridge. Для production-сервисов используйтеrenet compose(который сам внедряет host-сеть); для разовой отладки передавайте--network hostявно:docker run --rm --network host -it ubuntu bash.
Примечание: Форк-репозитории получают автоматические маршруты под поддоменом родителя:
{service}-fork-{tag}.{repo}.{machine}.{baseDomain}. Пользовательские домены для форков пропускаются.
Запуск сервисов
Смонтируйте репозиторий и запустите все сервисы:
rdc repo up --name my-app -m server-1
| Опция | Описание |
|---|---|
--skip-router-restart | Пропустить перезапуск сервера маршрутов после операции |
Последовательность выполнения:
- Монтирование LUKS-зашифрованного репозитория (автоматически, если не смонтирован)
- Запуск изолированного Docker-демона
- Автоматическая генерация
.rediacc.jsonиз compose-файлов - Выполнение
up()во всех Rediaccfile (в алфавитном порядке)
После развертывания в выводе отображается раздел PROXY ROUTES с фактическими URL для каждого сервиса. Сервисы с пользовательскими метками Traefik показывают свои пользовательские домены в качестве основных URL:
HTTP services (accessible via proxy after ~3s):
gitlab-server:
HTTPS: https://gitlab.example.com (custom)
Auto: https://gitlab-server.gitlab.server-1.example.com
IP: 127.0.11.130
Остановка сервисов
rdc repo down --name my-app -m server-1
| Опция | Описание |
|---|---|
--unmount | Размонтировать зашифрованный репозиторий после остановки сервисов. Если это не вступит в силу, используйте rdc repo unmount отдельно. |
--skip-router-restart | Пропустить перезапуск сервера маршрутов после операции |
Последовательность выполнения:
- Выполнение
down()во всех Rediaccfile (в обратном алфавитном порядке, максимальные усилия) - Остановка изолированного Docker-демона (если указан
--unmount) - Размонтирование и закрытие LUKS-зашифрованного тома (если указан
--unmount)
Массовые операции
Запуск или остановка всех репозиториев на машине одновременно:
rdc repo up -m server-1
| Опция | Описание |
|---|---|
--include-forks | Включить форкнутые репозитории |
--mount-only | Только смонтировать, не запускать контейнеры |
--dry-run | Показать, что будет выполнено |
--parallel | Выполнять операции параллельно |
--concurrency <n> | Максимальное количество параллельных операций (по умолчанию: 3) |
--skip-router-restart | Пропустить перезапуск сервера маршрутов после операции |
Автозапуск при загрузке
По умолчанию репозитории необходимо вручную монтировать и запускать после перезагрузки сервера. Автозапуск настраивает репозитории на автоматическое монтирование, запуск Docker и выполнение Rediaccfile up() при загрузке сервера.
Как это работает
При включении автозапуска для репозитория:
- Генерируется случайный LUKS-ключевой файл размером 256 байт и добавляется в LUKS-слот 1 репозитория (слот 0 остается для пользовательской парольной фразы)
- Ключевой файл сохраняется по пути
{datastore}/.credentials/keys/{guid}.keyс правами0600(только root) - Устанавливается systemd-сервис (
rediacc-autostart), который при загрузке монтирует все включенные репозитории и запускает их сервисы
При завершении работы или перезагрузке системы сервис корректно останавливает все сервисы (Rediaccfile down()), останавливает Docker-демоны и закрывает тома LUKS.
Примечание по безопасности: Включение автозапуска сохраняет LUKS-ключевой файл на диске сервера. Любой пользователь с root-доступом к серверу может смонтировать репозиторий без парольной фразы. Оцените это с учетом вашей модели угроз.
Включение
rdc repo autostart enable --name my-app -m server-1
Вам будет предложено ввести парольную фразу репозитория.
Включение для всех репозиториев
rdc repo autostart enable -m server-1
Отключение
rdc repo autostart disable --name my-app -m server-1
Эта команда удаляет ключевой файл и деактивирует LUKS-слот 1.
Обновление ключевого файла при развертывании
Когда автозапуск включён, rdc repo up проверяет ключевой файл LUKS-слота 1.
Если ключевой файл на диске всё ещё совпадает со слотом LUKS, изменения не вносятся.
После переноса репозитория между машинами через repo push / repo pull
ключевой файл на новой машине не совпадёт. В этом случае repo up автоматически
перегенерирует ключевой файл и обновит LUKS-слот 1. Вы увидите следующие сообщения в журнале:
Refreshing keyfile credential for <guid>
Killing LUKS slot 1: /mnt/rediacc/repositories/<guid>
Adding keyfile to LUKS slot 1: /mnt/rediacc/repositories/<guid>
Это безопасно — слот 0 (парольная фраза) никогда не изменяется. Если автозапуск не включён, проверка тихо пропускается. Сбои не критичны и не блокируют развертывание.
Список статусов
rdc repo autostart list -m server-1
Полный пример
Этот пример развертывает веб-приложение с PostgreSQL, Redis и API-сервером.
1. Настройка
curl -fsSL https://www.rediacc.com/install.sh | bash
rdc config init --name production --ssh-key ~/.ssh/id_ed25519
rdc config machine add --name prod-1 --ip 203.0.113.50 --user deploy
rdc config machine setup --name prod-1
rdc repo create --name webapp -m prod-1 --size 10G
2. Монтирование и подготовка
rdc repo mount --name webapp -m prod-1
3. Создание файлов приложения
Внутри репозитория создайте:
docker-compose.yml:
services:
postgres:
image: postgres:16
volumes:
- ./data/postgres:/var/lib/postgresql/data
environment:
POSTGRES_DB: webapp
POSTGRES_USER: app
POSTGRES_PASSWORD: changeme
redis:
image: redis:7-alpine
api:
image: myregistry/api:latest
environment:
DATABASE_URL: postgresql://app:changeme@postgres:5432/webapp
REDIS_URL: redis://redis:6379
LISTEN_ADDR: 0.0.0.0:8080
Rediaccfile:
#!/bin/bash
up() {
mkdir -p data/postgres
renet compose -- up -d
echo "Waiting for PostgreSQL..."
for i in $(seq 1 30); do
if renet compose -- exec postgres pg_isready -q 2>/dev/null; then
echo "PostgreSQL is ready."
return 0
fi
sleep 1
done
echo "Warning: PostgreSQL did not become ready within 30 seconds."
}
down() {
renet compose -- down
}
4. Запуск
rdc repo up --name webapp -m prod-1
5. Включение автозапуска
rdc repo autostart enable --name webapp -m prod-1