30 мая 2025 г.·8 мин чтения

Самостоятельные раннеры на bare metal против cloud VM для CI

Сравните самостоятельные раннеры на bare metal и cloud VM по стабильности очереди, ежемесячной стоимости и скорости восстановления, когда CI тормозит ежедневную работу.

Самостоятельные раннеры на bare metal против cloud VM для CI

Почему очереди CI начинают мешать команде

Очередь CI становится проблемой задолго до того, как сборки перестают запускаться совсем. Когда разработчики ждут по 10 или 15 минут только ради старта теста, они переключаются на другие задачи, теряют контекст и возвращаются к работе медленнее. Ревью затягиваются, потому что никто не хочет сливать код, который все еще стоит в очереди. Релизы тоже сдвигаются. Хуже всего с хотфиксами: исправление уже готово, а клиент все еще ждет раннер.

Не каждая задержка означает одно и то же. Какие-то пайплайны медленные, потому что сами задачи тяжелые: большие наборы тестов, объемные Docker-сборки или шаги, которые каждый раз заново скачивают одни и те же зависимости. У других команд задачи могли бы идти быстро, если бы стартовали вовремя, но слишком мало раннеров загоняют все в очередь. Это разные проблемы. Одной нужен разбор пайплайна. Другой — больше мощности раннеров, лучшее распределение нагрузки или и то и другое.

Сначала напряжение обычно проявляется в мелочах. Pull request'ы остаются открытыми дольше. Релизные ветки висят без слияния почти до конца дня. Хотфиксы соперничают с обычными тестами. Люди перезапускают задачи просто чтобы посмотреть, сдвинулась ли очередь.

Редкие всплески раздражают. Ежедневное трение выматывает команду. Backlog в понедельник утром после большого слияния — это нормально. Очередь, которая тормозит каждый ревью каждый день после обеда, — уже совсем другое дело. Люди начинают копить изменения, чтобы не запускать еще одну сборку, а значит, каждое слияние становится больше и рискованнее. Они тестируют реже. Откладывают мелкие исправления. За месяц такая привычка стоит дороже одного неудачного инцидента.

Именно поэтому стабильность очереди CI важнее, чем пиковая скорость в бенчмарке. Конфигурация раннеров может выглядеть дешевой или быстрой в коротких замерах и при этом мешать команде, если обычная работа превращается в ожидание. Именно это чаще всего и заставляет команды сравнивать самостоятельные раннеры на bare metal и cloud VM.

Что меняют раннеры на bare metal

Bare metal-раннеры обычно делают CI более предсказуемым. У вас каждый день один и тот же модель CPU, одна и та же скорость диска и один и тот же сетевой путь. Эта стабильность важнее, чем многие ожидают. Набор тестов, который в понедельник занимает 9 минут, гораздо вероятнее займет около 9 минут и в четверг, а не будет прыгать между 7 и 18 из-за шумного общего хоста VM.

Задачи обычно стартуют и быстрее, потому что раннер уже готов. Не нужно ждать, пока VM загрузится, подключит хранилище, прогреет кеши или заново подтянет базовый образ. Если команда пушит код весь день, такие мелкие задержки быстро складываются. Экономия даже 30–90 секунд на задачу может убрать заметную часть боли очереди еще до того, как вы поменяете хотя бы один тест.

Меняется и планирование мощности. На bare metal вы обычно покупаете или арендуете достаточно машин под нормальную нагрузку, а потом оставляете запас на самые загруженные часы. Если утром много слияний, а после обеда стартуют деплои и полные пайплайны, свободная мощность нужна еще до начала пика. Команды, которые рассчитывают раннеры только под среднюю нагрузку, быстро об этом жалеют.

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

Именно поэтому опытные команды держат один дополнительный раннер на готове и автоматизируют его настройку. Oleg Sotnikov часто говорит о lean infrastructure и аккуратном подборе мощности, и этот подход хорошо подходит bare metal. Предсказуемые машины — это отлично, но только если вы можете быстро заменить их, когда одна выходит из строя.

Что меняют cloud VM-раннеры

Cloud VM-раннеры решают другую задачу. Они сильно упрощают добавление мощности, когда очередь внезапно растет. Если за час приходит десять pull request'ов, вы можете поднять еще раннеры вместо того, чтобы ждать, пока одна фиксированная машина разгребет backlog. Именно эта гибкость — главная причина, по которой многие команды сначала переносят CI на VM.

Но здесь легко не заметить подвох. Больше мощности не всегда означает быстрый старт.

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

Маленькие команды замечают это быстро. Набор тестов, который на теплом раннере занимает 6 минут, может занять 9 или 10 минут на новой VM, если ей надо снова скачать все с нуля. Если разработчики пушат часто, эти дополнительные минуты накапливаются, и очередь все равно кажется медленной, даже если машин стало больше.

Cloud VM-раннеры также дают больше разброса в скорости задач. Вы не контролируете физический хост, поэтому одна и та же сборка может идти с разной скоростью в разное время дня. Один запуск заканчивается за 7 минут, следующий — за 8,5, даже без изменений в коде. На это влияют общее железо, производительность хранилища и сетевой шум. Такой разброс быстро утомляет, когда команде нужна стабильная обратная связь.

И потом есть счет. Compute — это только часть расходов. Хранилище для дисков раннеров и кешированных образов тоже стоит денег. Сетевой трафик растет, если задачи каждый раз тянут большие контейнеры или загружают крупные артефакты. Конфигурация, которая на час выглядит дешевой, к концу месяца может стоить намного дороже, если раннеры часто стартуют с нуля и гоняют много данных.

Cloud VM-раннеры лучше всего работают там, где нагрузка сильно меняется, а быстрое восстановление важнее, чем идеально ровное время сборки. Они дают запас для роста, но лучше всего раскрываются у команд, которые аккуратно управляют образами, кешами и размером артефактов.

Стабильность очереди под реальной нагрузкой

Команды редко ощущают боль CI в спокойное утро. Очередь начинает мешать, когда за короткий промежуток прилетает много merge request'ов, обычно перед обедом, перед релизом или после того, как длинную ветку наконец разделили на более мелкие изменения. Именно тогда разница между bare metal и cloud VM становится очевидной.

При ровном ежедневном трафике обе схемы на бумаге могут выглядеть нормально. Команда, которая запускает 20 сборок, разбросанных по дню, может увидеть похожее среднее время ожидания в обоих вариантах. Проблемы начинаются с всплесками. Если 12 разработчиков пушат в течение 15 минут, фиксированные bare metal-раннеры часто держат очередь предсказуемее, потому что машины уже есть, уже теплые и уже держат те же кеши.

Cloud VM-раннеры могут сгладить пик, но только после того, как появятся новые рабочие машины. Звучит очевидно, но многие команды забывают про задержку на старте. Автоскейлер видит очередь, просит еще VM, ждет, пока они загрузятся, подтягивает образ раннера, скачивает базовые контейнеры и только потом запускает задачу. К этому моменту пик может уже идти на спад, а люди все равно ждали.

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

На фиксированном железе эти затраты не исчезают, но они выравниваются. Локальные кеши остаются горячими. Образы лежат на диске. Сетевые пути привычны. Время в очереди кажется стабильнее, потому что каждая задача стартует из известного состояния, а не пересобирает одну и ту же настройку снова и снова.

Это не значит, что bare metal всегда выигрывает на пике. Если всплеск намного больше обычного, фиксированный пул упирается в жесткий потолок. Cloud VM-раннеры особенно полезны, когда всплески длятся достаточно долго, чтобы оправдать время запуска, или когда нагрузка меняется так сильно, что держать простаивающие машины кажется расточительством.

Лучше всего оценивать реальное поведение по p50 и p95 времени в очереди, а не только по среднему времени сборки. Если большинство задач стартует быстро, но каждый день после обеда часть из них ждет по 6–10 минут, автоскейлер реагирует слишком поздно. Если теплый bare metal-пул удерживает задержку ближе к 1–2 минутам, команда будет чувствовать разницу каждый день.

Как меняется стоимость за месяц

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

Ежемесячная стоимость CI редко совпадает с ценой, указанной на сервере или VM. Удобнее думать о ней как о стоимости одной успешной сборки. Раннер, который на бумаге выглядит дешевым, может стать дорогим, если учитывать неудачные запуски, повторы и часы ожидания людей.

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

Cloud VM-раннеры двигаются в другую сторону. Спокойные недели могут быть недорогими. Неделя релиза может быстро взлететь по расходам. Команды часто закладывают только compute и забывают про дополнительные расходы вокруг него: хранилище, snapshot'ы, кеши, хранение логов, время простоя, повторы и админскую работу по исправлению образов раннеров или неудачных startup-скриптов.

У bare metal есть и свои скрытые статьи. Если одна машина несет почти всю нагрузку, вам может понадобиться вторая коробка или хотя бы запасные диски и RAM на полке. Этот резерв тоже стоит денег, даже если простаивает. Если диск умирает и команда теряет полдня, эту потерю тоже нужно включать в расчет.

У cloud есть другая ловушка. Команды радуются гибкости, а потом оставляют более крупные VM включенными на всякий случай. Snapshot'ы хранилища продолжают расти. Cache volume'ы не удаляются. Появляются расходы на egress, когда сборки много тянут или отправляют артефакты между регионами. Ни один из этих пунктов сам по себе не выглядит драматичным, но вместе они легко съедают экономию от отказа от железа.

Небольшой пример хорошо показывает смысл. Допустим, команда тратит $500 в месяц на два bare metal-раннера, запасные детали и электричество и получает 8,000 успешных сборок. Это примерно $0.06 за одну успешную сборку. Cloud-конфигурация может показать $380 на compute, потом еще $140 на хранилище, snapshot'ы и сетевые расходы, плюс более высокий процент повторов в часы пик. В таком случае cloud-счет уже не выглядит дешевле.

Ровная ежедневная нагрузка обычно выгоднее для bare metal. Неровная нагрузка чаще лучше переносится cloud. Неправильный выбор становится дорогим, когда команды смотрят только на цену сервера и игнорируют все, что вокруг.

Что происходит при сбоях и как команды восстанавливаются

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

Те же проблемы встречаются почти в любом пуле раннеров. Диски забиваются кешами, слоями Docker и старыми артефактами. Плохие образы ломают каждую свежую задачу одинаковым образом. Застрявшие задания держат слот по 30 или 40 минут. Один сбой хоста может убрать сразу несколько раннеров.

Bare metal и cloud VM-раннеры ломаются по-разному. На bare metal один мощный хост часто запускает много исполнителей. Это снижает стоимость, но один сбой хоста может за раз снести большую часть пула. Если команда разместила восемь раннеров на одной машине, одна проблема с ядром, питанием или неудачным обновлением способна превратить здоровую очередь в полный стоп.

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

Команды восстанавливаются быстрее, когда используют простые правила и не отступают от них. Настройте алерты на низкое место на диске, долгое ожидание в очереди и задачи, которые идут намного дольше обычного. Держите логи раннеров в одном месте, чтобы люди могли сравнивать ошибки, а не гадать. Заранее решите окно замены до того, как что-то сломается: перезапуск через 5 минут, пересборка через 15, failover через 30.

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

Одна привычка помогает сильнее, чем ожидают многие команды. Не допускайте, чтобы один сбой сразу стал большим. Разнесите bare metal-раннеры хотя бы по двум хостам. Изменения образов VM сначала выкатывайте на один canary-раннер, а уже потом расширяйте. Очень часто именно это отделяет один упавший пайплайн от целого дня красных сборок.

Простой пример для растущей команды

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

Представьте команду из 20 разработчиков, которые пушат код весь день, в основном между 9 утра и 6 вечера. Их CI-задачи не маленькие. Каждый pull request запускает unit-тесты, integration-тесты, Docker-сборку и несколько проверок, которые обращаются к базам данных и тестовым сервисам. В загруженные часы они создают всплески по 10–15 задач сразу.

Теперь сравним две конфигурации для одной и той же нагрузки. Первая использует два bare metal-хоста в офисе или в арендованной стойке. Вторая — autoscaled-пул cloud VM-раннеров, который растет в часы пик и уменьшается ночью.

Метрика2 bare metal-хостаAutoscaled cloud VM-пул
Среднее время в очереди3–6 мин2–5 мин
Пиковое время в очереди в обед и поздним днем12–18 мин5–10 мин
Среднее время сборки18–22 мин22–28 мин
Неудачных повторов в месяц8–124–8
Ежемесячные расходы$1,200–$1,800$1,900–$3,200

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

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

Восстановление после сбоев — это место, где компромисс становится еще понятнее. Если один bare metal-хост умирает, команда сразу теряет половину мощности раннеров. Время в очереди может вырасти с 5 минут до 30, пока кто-то не починит хост или не перераспределит задачи. На cloud VM один сбой раннера бьет слабее, потому что пул быстро заменяет его. Но у cloud-пулов есть свои слабые места: плохие образы, ограничения квот или сломанные startup-скрипты могут ударить сразу по многим раннерам.

Для такой команды выбор должен зависеть от формы нагрузки, а не от моды. Если нагрузка ровная и предсказуемая, два мощных bare metal-хоста часто дают лучшую цену за одну сборку. Если трафик сильно скачет в течение дня и команда не может терпеть пики очереди, VM-пул может стоить дороже, но зато удержит работу в движении.

Частые ошибки, которые делают очереди хуже

Bare metal или cloud
Сравните оба варианта с учетом вашей нагрузки, всплесков очереди и ежемесячных расходов.

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

Одна частая ошибка — покупать более мощные машины вместо того, чтобы убрать медленные шаги тестов. Если задачи с нуля ставят зависимости, каждый раз заново собирают одни и те же артефакты или запускают огромные тестовые наборы на каждый commit, более быстрый раннер просто тратит больше денег. Сама работа все еще раздутa.

Сначала измерьте, куда уходят минуты, а уже потом тратьте деньги. У одной команды 12 минут может уходить на подготовку и только 3 — на сами тесты. Устранение дублирующей подготовки часто помогает сильнее, чем удвоение CPU или памяти.

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

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

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

Это ухудшает ситуацию и на bare metal, и на cloud VM-раннерах. Медленный общий кеш может тянуть вниз каждую задачу. Почти заполненный диск может превратить хороший раннер в непредсказуемый.

Команды также увеличивают число раннеров, не измеряя реальную параллельность. Добавить еще шесть раннеров звучит безопасно, но это не поможет, если по-настоящему могут двигаться только две задачи, потому что все ждут одну и ту же базу данных, registry пакетов или длинный integration-test.

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

Хороший CI ощущается скучным. Задачи стартуют быстро, деплои не мешают друг другу, а новые раннеры появляются только тогда, когда данные говорят, что они действительно нужны.

Быстрые проверки и следующие шаги

Когда команды сравнивают самостоятельные раннеры на bare metal и cloud VM, они часто пропускают самые простые цифры. Начните с данных очереди за последние две недели, а не с цен вендора или характеристик железа.

Посмотрите, в какие часы задачи накапливаются. Конфигурация раннеров может выглядеть нормально утром, но все равно тормозить всех после обеда, когда одновременно приходят слияния, тесты и релизные сборки. Проверьте, как часто задачи ждут более 3–5 минут до старта. Разбейте это ожидание по типам задач: unit-тесты, integration-тесты, Docker-сборки и деплои. Измерьте, сколько времени нужно свежему раннеру, чтобы стать полезным, а не только сколько времени он создается. И честно ответьте, кто будет вовлечен, когда раннеры перестанут принимать работу.

Третий показатель важнее, чем кажется. Если cloud VM-раннер стартует за 90 секунд, но ему нужно еще 4 минуты, чтобы подтянуть образы, прогреть кеши и нормально зарегистрироваться, запас мощности на всплеск слабее, чем выглядит. Если bare metal-раннер уже теплый, но ломается раз в неделю и никто не отвечает за исправление, очередь все равно проигрывает.

Назначьте цену задержке. Если шесть инженеров каждый день дважды теряют по 10 минут на ожидание CI, это уже два часа в день. За месяц такая цена может превысить экономию на более дешевом железе раннеров или на низких spot VM.

Небольшой пилот обычно дает больше, чем долгий спор. Перенесите сначала один самый загруженный workflow. Задайте цели для среднего времени в очереди, p95 времени в очереди, ежемесячных расходов на раннеры и времени восстановления после одного принудительного сбоя раннера. Держите пилот достаточно долго, чтобы поймать хотя бы один напряженный релизный день.

Потом специально проведите один тест отказа. Остановите раннер, сломайте регистрацию или удалите cache volume. Посмотрите, сколько времени команде нужно, чтобы заметить проблему, перенаправить задачи и вернуться к нормальной пропускной способности. Если за этот процесс никто не отвечает, назначьте владельца прямо сейчас.

Если команде нужен второй взгляд, Oleg на oleg.is помогает стартапам и малому бизнесу с настройкой CI/CD, подбором инфраструктуры и восстановлением после сбоев в рамках fractional CTO и advisory work. Полезная часть — не список инструментов. Полезно получить четкие цифры о том, где именно очередь мешает, и сначала исправить то, что тормозит ежедневную работу.

Часто задаваемые вопросы

Когда очередь CI становится настоящей проблемой?

Это становится реальной проблемой не из-за редкого всплеска, а когда люди начинают ждать постоянно. Если задания стоят по 10 минут, прежде чем вообще стартовать, разработчики переключаются на другие задачи, ревью замедляются, а мелкие исправления накапливаются.

Медленные сборки и длинная очередь — это одно и то же?

Нет. Медленная сборка означает, что сама задача выполняется слишком долго. Длинная очередь означает, что задача могла бы закончиться быстро, но у нее нет достаточно раннеров, чтобы стартовать вовремя.

Почему bare metal-раннеры часто кажутся быстрее?

Bare metal-раннеры остаются теплыми и предсказуемыми. У них одинаковое железо, локальные кеши и образы на диске, поэтому задачи обычно стартуют быстрее и завершаются стабильнее.

Когда cloud VM-раннеры имеют больше смысла?

Cloud VM хорошо подходят командам с резкими скачками нагрузки. Если за короткое время прилетает много pull request'ов или нагрузка сильно меняется в течение дня, дополнительные VM лучше сглаживают такой пик, чем фиксированный пул.

Что нужно измерять кроме среднего времени сборки?

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

Bare metal обычно дешевле за месяц?

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

Почему cloud-раннеры все равно кажутся медленными после автоскейлинга?

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

Как команде лучше реагировать на сбои раннеров?

Заранее задайте понятные правила восстановления. Быстро перезапускайте, быстро пересобирайте и убирайте нестабильные раннеры из пула, вместо того чтобы надеяться, что они сами поправятся.

Какие ошибки чаще всего ухудшают очередь CI?

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

Как протестировать bare metal и cloud, не делая полную миграцию?

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