.. _server_architecture: Архитектура ============ Citeck Launcher -- единый бинарный файл на Go (~24 МБ) без внешних зависимостей (pure Go, без CGO). Он совмещает в себе CLI-клиент и фоновый демон, взаимодействующий с Docker Engine для управления контейнерами платформы. .. contents:: :local: :depth: 2 Общая схема ------------- .. code-block:: text +------------------+ Unix socket +------------------+ | | ----------------------> | | | CLI (citeck) | HTTP API | Daemon | | | <---------------------- | (HTTP server) | +------------------+ +--------+---------+ | Docker SDK | +--------v---------+ | | | Docker Engine | | | +--------+---------+ | +------------------------------------------+ | | | +------v------+ +------v------+ +----------v--+ | postgres | | keycloak | | eapps | +-------------+ +-------------+ +-------------+ | zookeeper | | rabbitmq | | emodel | +-------------+ +-------------+ +-------------+ | proxy | | pgadmin | | uiserv | +-------------+ +-------------+ +-------------+ **Компоненты:** - **CLI** -- Cobra-команды, форматирование вывода (текст/JSON), интерактивные TUI-промпты - **Daemon** -- HTTP-сервер на Unix-сокете, обслуживающий REST API и SSE-поток событий - **Docker SDK** -- прямое взаимодействие с Docker Engine через официальный Go SDK - **Контейнеры** -- Docker-контейнеры с компонентами платформы Citeck Взаимодействие CLI и демона ---------------------------- CLI и демон общаются через **Unix-сокет** (``/run/citeck/daemon.sock``). Все команды CLI отправляют HTTP-запросы к демону: .. code-block:: text citeck status -> GET /api/v1/namespace citeck start -> POST /api/v1/namespace/start citeck stop -> POST /api/v1/namespace/stop citeck reload -> POST /api/v1/namespace/reload citeck logs -> GET /api/v1/apps/{name}/logs Для мониторинга в реальном времени (``citeck status --watch``, ``citeck start``) используется **SSE** (Server-Sent Events), а не WebSocket. Жизненный цикл контейнеров ---------------------------- Каждое приложение проходит через состояния: .. code-block:: text READY_TO_PULL --> PULLING --> DEPS_WAITING --> STARTING --> RUNNING ^ | | | v v | PULL_FAILED START_FAILED | | +--------------------------------------------+ (reconciler retry: 1m -> 30m) **Описание состояний:** .. list-table:: :widths: 25 75 :header-rows: 1 * - Состояние - Описание * - ``READY_TO_PULL`` - Начальное состояние, готово к загрузке образа * - ``PULLING`` - Загрузка Docker-образа * - ``PULL_FAILED`` - Ошибка загрузки образа * - ``DEPS_WAITING`` - Ожидание запуска зависимостей (например, postgres перед keycloak) * - ``STARTING`` - Контейнер создан и запускается * - ``RUNNING`` - Контейнер работает, liveness-проверка пройдена * - ``START_FAILED`` - Контейнер не смог запуститься * - ``STOPPED`` - Контейнер остановлен При сбое запуска реконсилер автоматически повторяет попытку с экспоненциальным backoff: 1 минута, 2 минуты, 4 минуты, ..., до максимума 30 минут. Порядок запуска ---------------- Приложения запускаются с учётом зависимостей: .. code-block:: text Фаза 1: postgres Фаза 2: keycloak, zookeeper, rabbitmq Фаза 3: Веб-приложения (eapps, emodel, gateway, ...) Фаза 4: proxy Каждое приложение ожидает готовности своих зависимостей (состояние ``DEPS_WAITING``), прежде чем начать запуск. Порядок остановки -- обратный: .. code-block:: text Фаза 1: proxy Фаза 2: Веб-приложения Фаза 3: keycloak, zookeeper, rabbitmq Фаза 4: postgres Deployment hash ---------------- При команде ``reload`` лончер использует механизм, аналогичный ``docker-compose up``: 1. Для каждого приложения вычисляется **deployment hash** на основе: - Docker-образа (image + tag) - Переменных окружения - Смонтированных томов - Портов - Лимитов ресурсов - Зависимостей 2. Hash сравнивается с hash работающего контейнера. 3. **Только изменённые контейнеры** пересоздаются -- неизменённые продолжают работать без прерывания. .. note:: Стабильность функции ``GetHashInput`` является жёстким контрактом совместимости между версиями лончера. Изменение алгоритма хеширования требует миграции. Обновление CLI и демона ------------------------ Установку CLI и демона обновляет тот же ``install.sh``, что и первичная установка -- он определяет факт наличия предыдущей версии и переключается в режим обновления: .. code-block:: bash curl -fsSL https://github.com/Citeck/citeck-launcher/releases/latest/download/install.sh | bash При обновлении бинарного файла лончера: 1. Создаётся резервная копия текущего бинарного файла (``/usr/local/bin/citeck.bak``). 2. Демон останавливается в режиме **detach**: процесс демона завершается, но контейнеры Docker продолжают работать. 3. Новый бинарный файл копируется в ``/usr/local/bin/citeck``. 4. Запускается новый демон, который **подхватывает** работающие контейнеры через сравнение deployment hash. .. code-block:: text Старый демон Новый демон +-----------+ +-----------+ | daemon v1 | --detach--> | daemon v2 | +-----------+ (containers +-----------+ | stay running) | +----v----+ +----v----+ | Docker | =================> | Docker | | Engine | (контейнеры | Engine | +---------+ сохранены) +---------+ **Что происходит с приложениями** зависит от того, изменился ли их ``deployment hash`` (см. раздел «Smart regenerate» выше): - **Hash приложения не изменился** (новая версия CLI не меняет формат generator-а для этого типа приложения) -- контейнер продолжает работать без перезапуска. *Это типичный сценарий zero-downtime-обновления*. - **Hash приложения изменился** (например, новая версия добавила переменную окружения в generator, сменился формат volume mount, обновилась версия образа в бандле) -- соответствующие контейнеры пересоздаются. Ожидаемое время простоя по каждому такому приложению -- от 1 до 5 минут (зависит от типа сервиса; Java-приложения дольше). .. note:: Чтобы заранее узнать, какие приложения будут пересозданы, после обновления бинарника выполните ``citeck reload --dry-run``. Команда покажет список контейнеров с изменённым hash до того, как вы их фактически перезапустите. Если обновление прошло неудачно, используйте откат: .. code-block:: bash citeck install --rollback Это восстановит бинарный файл из ``.bak`` и перезапустит демон. Контейнеры Docker не затрагиваются. Интеграция с systemd --------------------- Лончер автоматически создаёт systemd-сервис при установке: **Unit-файл:** ``/etc/systemd/system/citeck.service`` Основные характеристики: - **Restart=on-failure** -- автоматический перезапуск при сбое демона - Контейнеры Docker продолжают работать при перезапуске демона - Новый экземпляр демона подхватывает работающие контейнеры через hash matching - При обновлении используется runtime drop-in (``/run/systemd/system/citeck.service.d/no-restart.conf``), чтобы systemd не перезапустил старый демон в момент замены бинарного файла **Управление через systemd:** .. code-block:: bash # Статус сервиса systemctl status citeck # Логи демона через journald journalctl -u citeck -f # Перезапуск (контейнеры сохраняются) systemctl restart citeck .. warning:: Не используйте ``systemctl stop citeck`` для остановки платформы. Это остановит только демон, но не контейнеры. Используйте ``citeck stop --shutdown``. Управление секретами --------------------- Секреты хранятся с шифрованием **AES-256-GCM** в директории ``/opt/citeck/conf/secrets/``. **Типы секретов:** - **Системные** -- генерируются автоматически: - JWT-ключ для подписи токенов - OIDC client secret для интеграции с Keycloak - Пароль администратора — для пользовательского входа (ecos-app realm) - Пароль сервисной УЗ ``citeck`` — для внутренних операций с Keycloak - Пароли для RabbitMQ и PgAdmin - **Пользовательские** -- задаются через ``citeck setup``: - Пароль SMTP - Secret key для S3 - Учётные данные Docker-реестра Каждый секрет шифруется отдельно. Мастер-пароль используется для вывода ключей шифрования (PBKDF2-HMAC-SHA256). Реконсилер ----------- Реконсилер -- фоновый процесс, работающий в демоне, который обеспечивает соответствие желаемого и фактического состояния контейнеров: 1. **Периодическая проверка** (по умолчанию каждые 60 секунд): сравнивает конфигурацию с реальным состоянием Docker. 2. **Liveness-проверки** (по умолчанию каждые 30 секунд): выполняет HTTP-запрос к health endpoint приложения. После 3 последовательных неудач -- перезапуск. 3. **Автовосстановление**: при обнаружении упавшего контейнера инициирует повторный запуск с экспоненциальным backoff. Настройка через ``/opt/citeck/conf/daemon.yml``: .. code-block:: yaml reconciler: interval: 60 livenessPeriod: 30000 livenessEnabled: true