Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

Один файл, одна команда: как мы упростили запуск dev-окружения с помощью Runium

Дата публикации: 24-07-2026 14:18:59

Локальный запуск dev-окружения в крупном проекте может превратиться в отдельный квест: несколько процессов, Docker-контейнеры, переменные окружения, порядок старта, ожидание готовности сервисов и отличия между ОС. Даже если у вас есть подобный опыт, это может быть неудобно, долго и утомительно. Новичку же обычно не обойтись без длинной подробной инструкции.Привет, Хабр! На связи Сергей Зверьков, старший разработчик в «Лаборатории Касперского». Хочу рассказать, как мы решили эту проблему, написав собственный open-source-инструмент — Runium. Суть его в том, что он позволяет описать dev-окружение в JSON-файле. После этого проект можно запускать, останавливать и проверять одной командой.В статье расскажу, из какой боли вырос Runium, как он устроен, сравню его с другими решениями и покажу пример использования на простом веб-проекте. Приступим! Читать далее

Основное содержимое страницы с новостью.

Локальный запуск dev-окружения в крупном проекте может превратиться в отдельный квест: несколько процессов, Docker-контейнеры, переменные окружения, порядок старта, ожидание готовности сервисов и отличия между ОС. Даже если у вас есть подобный опыт, это может быть неудобно, долго и утомительно. Новичку же обычно не обойтись без длинной подробной инструкции.

Привет, Хабр! На связи Сергей Зверьков, старший разработчик в «Лаборатории Касперского». Хочу рассказать, как мы решили эту проблему, написав собственный open-source-инструмент — Runium. Суть его в том, что он позволяет описать dev-окружение в JSON-файле. После этого проект можно запускать, останавливать и проверять одной командой.

В статье расскажу, из какой боли вырос Runium, как он устроен, сравню его с другими решениями и покажу пример использования на простом веб-проекте. Приступим!

ПредысторияЧасть 1. Боль

2024 год, «Лаборатория Касперского»

В наших командах, разрабатывающих крупный веб-проект, все острее становилась проблема удобного и быстрого запуска dev-окружения. Нужно было поддерживать несколько типов поставок продукта, а это приводило к ситуации, когда набор настроек и запускаемых элементов мог сильно различаться.

Например, для поставки типа А был нужен один набор переменных окружения и N локально запускаемых элементов. Для поставки типа B — тот же набор переменных окружения, дополнительные значения, N локально запускаемых элементов и M элементов, запускаемых в Docker. И так далее.

На практике это означало, что нам приходилось вручную редактировать разные конфигурации, запускать несколько терминалов в разных каталогах, помнить порядок запуска и переключаться между типами поставок. Кто-то пытался решить эту задачу по-своему: Python-скриптами для iTerm, tasks.json для VS Code и другими способами. Единого решения у нас не было, а отдельные подходы были не универсальными.

Часть 2. Krun

Конец 2024 года, «Лаборатория Касперского»

С этой ситуацией нужно было что-то делать. Нам поставили задачу реализовать инструмент, который унифицирует запуск dev-окружения для разных типов поставок и в буквальном смысле позволит «запускать все одной командой». Мне выпало проработать концепцию и заложить основу для нового инструмента, а позже к разработке подключились коллеги.

В результате появился Krun — внутренний инструмент, решающий проблемы запуска.

Если описать коротко, Krun был реализован в виде npm-пакета, потому что органично вписывался в экосистему веб-проекта. Все запускаемые элементы и их конфигурация описывались в одном JSON-файле. Процессы запускались локально, контейнеры — через Docker Compose. Все окружение поднималось одной командой:

yarn krun run some-project.json
Часть 3. Ожидание vs. Реальность

2025 год, «Лаборатория Касперского»

Инструмент внедрили, и свою задачу он решал.

В командах Krun встретили по-разному: многие отметили, что он заметно упрощает жизнь, и пополнили ряды поклонников; некоторые не увидели особых улучшений и остались верны собственным решениям; кто-то в принципе не понял сути инструмента и разочаровался.

Со временем от коллег начала приходить обратная связь: идеи по улучшению, пожелания, критика. Что-то было важно и объективно, что-то относилось скорее к субъективным предпочтениям. Стало понятно, что нужны доработки.

Часть 4. Новый взгляд

После внедрения Krun у меня остался небольшой осадок: значительная часть идей, которые мы рассматривали при проработке концепции, не была реализована, так и оставшись идеями. Маленький перфекционист внутри головы не давал заснуть по ночам: сожалел о невоплощенных идеях и подкидывал все больше новых. Долго так продолжаться не могло, поэтому в свободное от работы время я начал экспериментировать с новой концепцией инструмента.

Конец 2025 года, секретная лаборатория где-то у меня дома

Эксперименты перешли в активную осознанную разработку, новый инструмент начал обретать очертания. Появилось понимание, как реализовать все задуманное. Впереди было много работы.

Начало 2026 года, та же секретная лаборатория

Первая версия инструмента готова. Многие недостатки Krun устранены: новый инструмент стал гибче, функциональнее и получил большой потенциал для развития. Нет, это не Krun и даже не Krun 2.0. Это Runium, и он открыт для всех.

Runium. Что это?

Runium («ру́ниум», от англ. rune — «руна») — кросс-платформенный open-source-инструмент для централизованного управления запуском процессов и приложений.

Он позволяет описать множество запускаемых элементов — команд, утилит, приложений, контейнеров и так далее — в одном формализованном JSON-файле, а затем запускать их одной командой единообразно, независимо от среды и операционной системы: Linux, Windows или macOS.

Когда проект или окружение состоит из множества запускаемых элементов, со временем появляется набор типичных проблем: разрозненные shell- и batch-скрипты, отдельные конфигурации запуска, несогласованные пути к файлам и зависимостям, разная логика запуска для каждого элемента, неявные зависимости, сложность управления порядком запуска и остановки, ручные действия при изменениях и сбоях, проблемы переносимости между различными ОС и средами, а также отсутствие единой точки управления и наблюдаемого состояния.

Runium решает эти проблемы, переводя управление запуском в единую декларативную конфигурацию.

Инструмент будет полезен разработчикам, тестировщикам и platform/DevOps-инженерам, когда нужно воспроизводимо запускать набор связанных процессов.

Для работы нужна Node.js 22 и выше.

Runium устанавливается как npm-пакет:

npm install -g @runium/cli

Или через yarn:

yarn global add @runium/cli
Основные понятия

Перед примером разберем базовые сущности Runium. Они нужны, чтобы понять, как в одном JSON-файле описываются отдельные процессы, зависимости между ними, условия запуска, реакции на события и динамические значения в конфигурации.

Проект в Runium — это формализованное описание всех запускаемых элементов и их взаимосвязей, представленное в виде JSON-файла. По сути, проект является единой декларативной конфигурацией: все запускаемые элементы и их параметры описываются в одном месте.

Такой подход делает конфигурацию читаемой, формализованной и удобной для хранения в репозитории. За счет этого упрощается переносимость между машинами и средами, становится меньше «локальной магии» и ручных инструкций, а сама конфигурация начинает работать как документация процесса запуска.

JSON выбран сознательно из-за широкой поддержки, JSON Schema и предсказуемого синтаксиса.

Да, JSON многословнее YAML и не поддерживает комментарии «из коробки». Это осознанный компромисс в пользу строгости и инструментальной поддержки. Дублирование при этом может быть минимизировано средствами самого инструмента: плагином для наследования конфигураций и динамическими подстановками с помощью макросов. При желании поддержку других форматов можно добавить плагином.

Основная часть проекта — это задача, или task. Задача содержит полное описание того, что запускать, как запускать, когда запускать, с какими параметрами и как реагировать на изменения состояния.

8408316dc1f7de76aad016790f6ef2b5.png

В процессе функционирования задача переходит из одного состояния в другое. Именно состояние задачи используется дальше в зависимостях, обработчиках и других механизмах Runium.

Зависимость, или dependency, — это правило, определяющее условие для отложенного запуска задачи. Зависимости позволяют организовать запуск задач на основе изменения состояния других задач. Например, можно запустить задачу A только после успешного завершения задачи B.

По умолчанию Runium запускает задачи в порядке их определения в конфигурации проекта. Если у задачи есть зависимости, ее запуск будет отложен до момента, пока все они не будут удовлетворены. При этом Runium автоматически обнаруживает циклические зависимости и предотвращает запуск в случае их наличия.

Кроме зависимостей, в Runium есть действия, или actions. Действие — это внутренняя команда, позволяющая изменять состояние проекта и его элементов: запустить задачу, остановить задачу, перезапустить задачу, остановить проект или инициировать внутреннее событие проекта. Действия могут выполняться в рамках обработчиков и триггеров.

Обработчик, или handler, — это правило для автоматического выполнения действий при изменении состояния задачи. Например, обработчик может запустить задачу B, если текущая задача завершилась ошибкой. Условие выполнения определяется на основе состояния текущей задачи, а у каждой задачи может быть несколько обработчиков с различными условиями вызова.

Триггер, или trigger, работает похожим образом, но реагирует не на изменение состояния задачи, а на события. Это правило для автоматического выполнения действий в ответ на события. Срабатывание триггера может быть инициировано по таймеру, интервалу или внутренним событием проекта.

Еще одна важная сущность Runium — макрос, или macro. Макрос — это специальная конструкция, которая позволяет динамически подставлять значения в конфигурацию проекта. Он может использоваться в любой части конфигурации и позволяет динамически подставлять значения переменных окружения, дату и время, пути к файлам и каталогам, случайные значения вроде uuid или чисел, содержимое файлов, а также значения, зависящие от условий.

Если возможностей Runium «из коробки» недостаточно, недостающую функциональность можно добавить через плагины. Плагин, или plugin, — это элемент, расширяющий функциональность приложения.

Технически плагин представляет собой JavaScript-модуль, который позволяет добавлять новые команды, триггеры и действия, новые типы задач и макросы, расширять возможности конфигурации проекта, а также добавлять обработчики жизненного цикла приложения и проектов.

Система плагинов, вероятно, одна из ключевых возможностей инструмента: она позволяет адаптировать Runium под специфические процессы, инфраструктуру и рабочие практики. Runium предоставляет набор готовых плагинов, но при необходимости можно создать собственный.

Пример

Достаточно теории. Посмотрим, как Runium можно применить в реальной ситуации.

Представим простой типичный веб-проект. В нем есть фронтенд — приложение на Vite + React, бэкенд — HTTP-сервер на Node.js + Fastify, база данных PostgreSQL, которая запускается в Docker, и кэш Redis, который тоже запускается в Docker.

Структура проекта выглядит так:

project/
  frontend/   # Vite-приложение
  backend/    # Fastify-сервер

Фронтенд взаимодействует с бэкендом через API и использует переменную окружения VITE_API_URL.

Бэкенд использует переменные окружения для подключения к базе данных DATABASE_URL и кэшу REDIS_URL.

При запуске PostgreSQL необходимы переменные окружения POSTGRES_USER, POSTGRES_PASSWORD и POSTGRES_DB.

Нам нужно запустить все элементы для разработки в правильном порядке и с правильными переменными окружения.

Без Runium

Без Runium, чтобы поднять dev-окружение, нужно выполнить несколько шагов.

Сначала запускаем PostgreSQL и Redis в Docker:

docker run -d \
  --name dev-postgres \
  -e POSTGRES_USER=user \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=appdb \
  -p 5432:5432 \
  postgres:16-alpine

docker run -d \
  --name dev-redis \
  -p 6379:6379 \
  redis:7-alpine

После этого нужно дождаться готовности базы данных. Это важный момент: PostgreSQL стартует не мгновенно, и если запустить бэкенд раньше, это может привести к ошибкам подключения.

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

cd backend

DATABASE_URL=postgresql://user:secret@localhost:5432/appdb \
REDIS_URL=redis://localhost:6379 \
PORT=3001 \
npm run dev

И наконец запускаем фронтенд — еще в одном терминале:

cd frontend

VITE_API_URL=http://localhost:3001 \
npm run dev

Конечно, переменные окружения могут быть заданы альтернативным способом, например в .env-файлах.

Итог: несколько шагов, несколько терминалов, переменные окружения разбросаны по командной строке или разным файлам, правильный порядок запуска нужно держать в голове, а для завершения всех процессов требуется выполнить несколько отдельных действий.

Такая ситуация требует документации и внимательности, особенно при подключении новых разработчиков.

С использованием Runium

С Runium тот же самый запуск можно описать централизованно.

Чтобы поднять dev-окружение, сначала создаем файл проекта. То же самое окружение описывается в одном файле, например project.json: запускаемые элементы, переменные окружения, зависимости и порядок запуска — все находится в одном месте.

С помощью зависимостей организуем последовательность запуска: Redis и PostgreSQL стартуют сразу, затем запускается бэкенд, затем фронтенд.

Отдельно учитываем важный момент — ожидание готовности базы данных. Контейнер dev-postgres запускается сразу, но сама БД еще не готова принимать подключения. Для проверки готовности добавляем задачу database-ready.

Пример ниже актуален для Linux. Команда проверки готовности БД для Windows должна выглядеть иначе.

{
  "id": "my-app-dev",
  "tasks": [
    {
      "id": "postgres",
      "type": "docker",
      "options": {
        "image": "postgres:16-alpine",
        "containerName": "dev-postgres",
        "ports": ["5432:5432"],
        "env": {
          "POSTGRES_USER": "user",
          "POSTGRES_PASSWORD": "secret",
          "POSTGRES_DB": "appdb"
        }
      }
    },
    {
      "id": "redis",
      "type": "docker",
      "options": {
        "image": "redis:7-alpine",
        "containerName": "dev-redis",
        "ports": ["6379:6379"]
      }
    },
    {
      "id": "database-ready",
      "options": {
        "command": "until docker exec dev-postgres pg_isready; do sleep 1; done"
      },
      "dependencies": [
        {
          "taskId": "postgres",
          "condition": {
            "status": "started"
          }
        }
      ]
    },
    {
      "id": "backend",
      "options": {
        "command": "npm",
        "arguments": ["run", "dev"],
        "cwd": "./backend",
        "env": {
          "DATABASE_URL": "postgresql://user:secret@localhost:5432/appdb",
          "REDIS_URL": "redis://localhost:6379",
          "PORT": "3001"
        }
      },
      "dependencies": [
        {
          "taskId": "database-ready",
          "condition": {
            "status": "completed"
          }
        },
        {
          "taskId": "redis",
          "condition": {
            "status": "started"
          }
        }
      ]
    },
    {
      "id": "frontend",
      "options": {
        "command": "npm",
        "arguments": ["run", "dev"],
        "cwd": "./frontend",
        "env": {
          "VITE_API_URL": "http://localhost:3001"
        }
      },
      "dependencies": [
        {
          "taskId": "backend",
          "condition": {
            "status": "started"
          }
        }
      ]
    }
  ]
}

Для запуска Docker-контейнеров здесь используется плагин docker.

После этого проект можно запустить одной командой:

runium project start -f project.json

Runium запустит PostgreSQL и Redis, дождется готовности БД, запустит бэкенд, а затем фронтенд. Именно в таком порядке и именно с теми переменными, которые указаны в конфигурации.

Итог: запуск выполняется одной командой, все запускаемые элементы, переменные окружения и зависимости указаны в одном месте, а завершение работы происходит централизованно.

Для завершения всех запущенных процессов достаточно выполнить команду:

runium project stop -f project.json

Фактически конфигурация запуска Runium сама является документацией и описанием процесса запуска. Расположение всех элементов в одном месте позволяет легко и прозрачно конфигурировать и поддерживать запускаемое окружение.

Особенности

Теперь обзорно рассмотрим несколько важных особенностей Runium, которые помогают не просто запускать окружение, а делать это предсказуемо и управляемо.

Валидация

Перед запуском проекта Runium валидирует его конфигурацию. Валидация реализована на базе JSON Schema и позволяет определить:

  • корректность структуры JSON;

  • отсутствие обязательных полей;

  • некорректные значения;

  • циклические зависимости задач.

При написании конфигурации ее можно валидировать с помощью команды:

runium project validate -f project.json

Это полезно не только перед запуском, но и в процессе поддержки конфигурации: ошибка в структуре или зависимостях обнаруживается заранее, а не в момент, когда окружение уже должно было стартовать.

Текущее состояние

Runium позволяет просматривать текущее состояние проекта и его задач.

Первый вариант — указать флаг --output при запуске проекта. В этом случае в терминале будет динамически отображаться состояние проекта и задач при их изменении:

runium project start -f project.json --output

Пример вывода:

ℹ

Второй вариант — использовать команду просмотра состояния. В этом случае будет выведено состояние проекта и задач на момент запуска команды:

runium project status -f project.json --all

Это удобно, когда нужно быстро понять, какие задачи уже запущены, какие завершились, а какие находятся в другом состоянии.

Логи

Runium позволяет записывать логи запущенных задач в отдельные файлы. Важный момент: инструмент не добавляет собственные записи при логировании, а просто перенаправляет потоки вывода запущенных процессов — stdout и stderr — в файлы.

Для включения логирования в опции задачи добавляется свойство log:

{
  "id": "some-task",
  "options": {
    "command": "some-command",
    "arguments": ["arg1", "arg2"],
    "log": {
      "stdout": "./logs/some-task.out.log",
      "stderr": "./logs/some-task.err.log"
    }
  }
}

Так можно централизованно описать, куда складывать вывод каждой задачи, и не искать потом логи по разным терминалам или временным файлам.

Производительность и накладные расходы

Runium запускает процессы и наблюдает за их состоянием, но не встает между ними в рантайме: stdout и stderr просто перенаправляются, а трафик приложений через Runium не проходит.

Поэтому на скорость работы самих процессов инструмент практически не влияет. Накладные расходы сводятся к разовому парсингу и валидации конфигурации при старте и легкому мониторингу состояний.

Runium написан на JavaScript и распространяется как npm-пакет, поэтому для работы нужен установленный Node.js. Для типичных dev-окружений с десятками задач это несущественно. Для сценариев с сотнями задач специфических нагрузочных замеров пока не проводилось.

Сравнение с другими решениями

Runium пересекается сразу с несколькими классами инструментов: command runner’ами, менеджерами процессов, Docker/Kubernetes dev-tooling и IDE-конфигурациями запуска. Поэтому корректнее сравнивать его не с одним «аналогом», а с группами инструментов.

Его основная ниша — координация разнородных задач в локальном или проектном окружении: контейнеров, фронтенд- и бэкенд-процессов, скриптов, утилит и вспомогательных команд.

Инструмент

Для чего подходит

Чем отличается Runium

Docker Compose

Запуск набора контейнеров

Комбинирует контейнеры, локальные процессы, команды и приложения в одном проекте

PM2

Управление Node.js-процессами

Не привязан к Node.js, поддерживает зависимости между разнородными задачами

Make

Автоматизация команд

Описывает не только команды, но и состояние задач, зависимости, обработчики и триггеры

npm scripts

Быстрый запуск команд внутри JS-проекта

Дает единую конфигурацию для набора связанных задач, не только для JS

Procfile / foreman / overmind

Параллельный запуск процессов по описанию в Procfile

Поддерживает зависимости, условия и порядок запуска, а не только «поднять все сразу»; управляет состоянием и реагирует на события

Task / just

Замена Make с YAML или более удобным синтаксисом

Ориентирован на длительно живущие процессы и их координацию, а не только на выполнение команд-таргетов; отслеживает состояние задач

Runium стоит рассматривать как слой координации поверх привычных инструментов. Он не отменяет Docker Compose, npm scripts или другие решения. Его задача связать их в один воспроизводимый сценарий, если запуск проекта уже стал слишком разрозненным.

Когда Runium не нужен

Runium не стоит добавлять в проект «на всякий случай». Если запуск окружения уже прост и прозрачен, отдельный слой координации может оказаться лишним. Например, если весь проект состоит из нескольких Docker-контейнеров, полностью описан в docker-compose.yml, а запуск сводится к одной команде, то Runium, скорее всего, не даст заметной пользы. То же самое относится к небольшим проектам, где достаточно пары npm scripts.

Если команда понимает, как запускать проект, порядок действий очевиден, а дополнительные зависимости, обработчики и триггеры не требуются, лучше оставить существующую схему.

Runium становится полезен там, где запуск расползается по нескольким инструментам: часть окружения живет в Docker, часть запускается локально, часть требует ожидания готовности, а порядок действий уже приходится документировать отдельно.

Заключение

Runium — молодой инструмент, поэтому перед внедрением стоит учитывать несколько ограничений.

Формат конфигурации и API плагинов еще могут развиваться. Базовые сценарии уже поддерживаются, но документация пока покрывает не все возможные варианты использования.

Для production-сценариев нужно отдельно оценивать требования к надежности, мониторингу, рестартам и управлению жизненным циклом процессов.

Runium решает конкретную прикладную задачу: помогает описывать и запускать сложное локальное окружение как единый проект. Он полезен там, где одного docker compose up или пары npm scripts уже недостаточно: есть локальные процессы, контейнеры, зависимости, ожидание готовности сервисов и ручные шаги в инструкции.

Инструмент не претендует на роль универсального оркестратора и не заменяет другие инструменты. Его задача проще: собрать разрозненный запуск в один воспроизводимый сценарий, который можно хранить в репозитории, проверять, изменять и запускать одной командой.

Сейчас мы в наших командах переходим с Krun на Runium. Пилотный запуск дал положительную обратную связь. Я планирую и дальше развивать Runium по мере возможностей: есть еще нереализованные идеи, и они появляются постоянно.

Подробнее о возможностях Runium, плагинах, примерах конфигурации, дальнейших планах и многом другом можно узнать на сайте https://runium.thebeastapp.ru.

Исходный код доступен на GitHub и GitVerse.

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
1GitLab Runners: полное руководство от shell до Kubernetes5716-07-2026
2GitFlic CI/CD: первый конвейер с нуля — от коммита до деплоя0707-07-2026
3Harness engineering: как за год собрать фабрику из десятка конвейеров05.8224-07-2026
4Ты не найдёшь эту ошибку. Потому что её нет в твоём коде. Как Self-describing API спасает от чужих рефакторингов5807-07-2026
5460 ГБ, свободно 14: археология диска разработчика011.7524-07-2026
6Что сломается в вашем сервисе завтра, если сегодня вы запустите контейнеры без проверки образов06.3724-07-2026
7Мобильная разработка за неделю #636 (22 — 28 июня)5728-06-2026
8Как я создаю «Черный ящик»: почему разработчику не подходят Jira, Битрикс24 и другие трекеры «для маркетологов»5722-06-2026
9Две недели я делал народную карту заправок. Написать код оказалось самой скучной частью работы0507-07-2026
106 pro-фишек FluxCD. Выжимаем все соки из GitOps2606-07-2026

Классификация: Мнения. Схожих патентов: 0. Схожих новостей: 10. Тональность: 0. Информативность: 12.11. Источник: habr.com.