Всем привет! Меня зовут Сергей, и я Backend Kotlin разработчик в компании занимающейся разработкой систем повышающую безопасность дорожного движения. И я расскажу, как мы с помощью Jetpack Compose и GitLab API упростили процесс деплоя на 100+ распределённых серверов, повысив при этом удобство и предсказуемость процесса.

В ежедневной работе нашей команды стоит задача регулярного деплоя обновлений на большое количество серверов - их на данный момент уже более сотни. Рутинные операции через веб-интерфейс GitLab отнимали много времени и были подвержены человеческим ошибкам. Вариант внедрения Argo CD нам не подходил, так как мы используем Docker Compose и переходить на Kubernetes не планировали. Из-за привязки серверов к определённым трассам деплой должен осуществляться не сразу на все сервера, а группами по согласованию с ответственными лицами с возможностью группировки по направлениям. Мы задумались об автоматизации, но хотели не просто скрипт, а удобный, наглядный и надёжный инструмент. И мы его создали, использовав, казалось бы, неожиданную технологию - Jetpack Compose.

Проблема: Деплой как головная боль

Представьте себе:

  • Масштаб: 100+ серверов, разделенных на несколько стейджинг‑окружений и продакшен‑кластеров.

  • Процесс: Зайти в GitLab CI/CD → найти нужный пайплайн → найти нужный джоб → нажать «Run» → выбрать ветку → повторить 100 раз.

  • Риски: Легко запустить деплой не на том сервере, перепутать ветку, пропустить ошибку в логах из‑за усталости.

Наш старый подход был неэффективен, медленен и деморализующий для инженеров. Нужно было решение, которое предоставит:

  1. Единую точку входа для управления всеми деплоями.

  2. Визуализацию статуса каждого сервера в реальном времени.

  3. Минимизацию ручных действий до нескольких кликов.

  4. Возможность отбора серверов для деплоя по группам

  5. Надёжность и защиту от случайных ошибок.

Выбор технологий: Почему Jetpack Compose?

Когда зашла речь о UI, классические варианты были очевидны: Electron (JS/TS), Qt (C++/Python), JavaFX. Но у меня был опыт разработки Android приложений, и мы обратили внимание на Jetpack Compose for Desktop.

Наши аргументы в его пользу:

  • Скорость разработки: Декларативный подход Compose позволяет быстро итеративно строить сложные и отзывчивые интерфейсы. «Что видишь, то и получаешь».

  • Современный и родной Kotlin: Вся логика приложения и UI пишутся на одном языке. Это уменьшает контекстные переключения и упрощает поддержку. Kotlin — это основной язык для разработки backend и Android приложений в нашем проекте.

  • Производительность: В отличие от Electron, приложение на Compose for Desktop — это нативное исполняемое файлы с минимальными overhead. Оно быстро запускается и не жрет память.

  • Экосистема Kotlin: Мы могли использовать мощные корутины (kotlinx.coroutines) для асинхронных вызовов GitLab API и богатую экосистему библиотек (Ktor для сетевых запросов, jackson для парсинга JSON и Yaml).

Сердце системы: GitLab API

Вторая ключевая технология — GitLab API. Мы использовали библиотеку gitlab4j‑api. Оно предоставляет программный доступ ко всему, что умеет делать веб-интерфейс:

  • Авторизация через Private-Token

  • Запуск, отмена, перезапуск джобов

  • Получение логов пайплайнов в реальном времени

  • Получение списка проектов, веток

Наше приложение стало умной прослойкой между инженером и GitLab CI/CD.

Архитектура нашего решения

Архитектуру приложения мы решили не усложнять, чтобы не затаскивать в проект дополнительные библиотеки, поэтому оставили в нём два основных слоя:

UI Layer (Compose for Desktop):

  • Отвечает за отрисовку всего интерфейса

  • Отображает список серверов (проектов) с их текущим статусом

  • Реагирует на действия пользователя и отправляет команды в слой логики

Data Layer (GitLab API):

  • Репозиторий, который инкапсулирует все сетевые запросы

  • Использует GitLab REST API для выполнения операций

  • Авторизация через Private-Token

  • Преобразует JSON-ответы от GitLab в доменные модели Kotlin (data class Pipeline, data class Job)

Внешний вид приложения
Внешний вид приложения
fun GitLabApi.getLastBranch(project: Project) =
    repositoryApi.getBranchesStream(project.id, "prod-")
        .asSequence()
        .sortedByDescending { it.name.toNumber() }
        .firstOrNull()

fun GitLabApi.getLastPipeline(project: Project, tagName: String): Pipeline? =
    pipelineApi.getPipelinesStream(
        project.id,
        PipelineFilter().withRef(tagName).withScope(Constants.PipelineScope.TAGS)
    ).asSequence().minByOrNull { it.committedAt }

fun GitLabApi.getJobsForPipeline(project: Project, pipelineId: Long) =
    jobApi.getJobsStream(project.id, pipelineId)

Ключевые фичи готового приложения

  • ЕдиныйDashboard: Все 100+ серверов на одном экране. Цветовые индикаторы сразу показывают общую картину

  • Массовый деплой: Возможность выбрать группу серверов (например, все сервера «стейджинга») и запустить деплой на всех одной кнопкой

  • «Ленивый» мониторинг: Приложение в фоне периодически опрашивает GitLab API и автоматически обновляет статусы деплоев. Пользователь видит прогресс в реальном времени

  • Возможность перейти из приложения для деплоя непосредственно в пайплайн Gitlab

Выводы и результаты

Спустя несколько месяцев активного использования мы можем подвести итоги. Что мы получили:

  • Скорость: Время затрачиваемое на проведение деплоя уменьшилось в разы благодаря удобства работы с новым интерфесом

  • Надежность: Количество ошибок, связанных с «человеческим фактором», стремится к нулю

  • Удобство: Инструмент получился настолько удобным, что большую часть выкатки релиза передана непосредственно продакт‑менеджеру

  • Технический долг: Мы не только решили бизнес‑задачу, но и освоили перспективную технологию (Compose for Desktop), которая может пригодиться и для других внутренних инструментов

Комментарии (0)