Архитектура

Citeck Launcher – единый бинарный файл на Go (~24 МБ) без внешних зависимостей (pure Go, без CGO). Он совмещает в себе CLI-клиент и фоновый демон, взаимодействующий с Docker Engine для управления контейнерами платформы.

Общая схема

+------------------+       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-запросы к демону:

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.

Жизненный цикл контейнеров

Каждое приложение проходит через состояния:

READY_TO_PULL --> PULLING --> DEPS_WAITING --> STARTING --> RUNNING
     ^              |                             |
     |              v                             v
     |         PULL_FAILED                   START_FAILED
     |                                            |
     +--------------------------------------------+
               (reconciler retry: 1m -> 30m)

Описание состояний:

Состояние

Описание

READY_TO_PULL

Начальное состояние, готово к загрузке образа

PULLING

Загрузка Docker-образа

PULL_FAILED

Ошибка загрузки образа

DEPS_WAITING

Ожидание запуска зависимостей (например, postgres перед keycloak)

STARTING

Контейнер создан и запускается

RUNNING

Контейнер работает, liveness-проверка пройдена

START_FAILED

Контейнер не смог запуститься

STOPPED

Контейнер остановлен

При сбое запуска реконсилер автоматически повторяет попытку с экспоненциальным backoff: 1 минута, 2 минуты, 4 минуты, …, до максимума 30 минут.

Порядок запуска

Приложения запускаются с учётом зависимостей:

Фаза 1:  postgres
Фаза 2:  keycloak, zookeeper, rabbitmq
Фаза 3:  Веб-приложения (eapps, emodel, gateway, ...)
Фаза 4:  proxy

Каждое приложение ожидает готовности своих зависимостей (состояние DEPS_WAITING), прежде чем начать запуск.

Порядок остановки – обратный:

Фаза 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. Только изменённые контейнеры пересоздаются – неизменённые продолжают работать без прерывания.

Примечание

Стабильность функции GetHashInput является жёстким контрактом совместимости между версиями лончера. Изменение алгоритма хеширования требует миграции.

Обновление CLI и демона

Установку CLI и демона обновляет тот же install.sh, что и первичная установка – он определяет факт наличия предыдущей версии и переключается в режим обновления:

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.

Старый демон                     Новый демон
+-----------+                    +-----------+
| 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-приложения дольше).

Примечание

Чтобы заранее узнать, какие приложения будут пересозданы, после обновления бинарника выполните citeck reload --dry-run. Команда покажет список контейнеров с изменённым hash до того, как вы их фактически перезапустите.

Если обновление прошло неудачно, используйте откат:

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:

# Статус сервиса
systemctl status citeck

# Логи демона через journald
journalctl -u citeck -f

# Перезапуск (контейнеры сохраняются)
systemctl restart citeck

Предупреждение

Не используйте 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:

reconciler:
  interval: 60
  livenessPeriod: 30000
  livenessEnabled: true