GitHub Actions на своих серверах · Часть 1

Платим за сборки,
а не за простой

Сервер появляется, когда нужно собрать приложение, и удаляется после работы. GitHub остаётся привычным. Основные расходы — в рублях.

Игорь / Poliklot8 минут

Минуты закончились.
Как платить дальше?

Пока проект небольшой, GitHub Actions почти не замечаешь. Отправил код — запустились тесты, собралось приложение. Бесплатных минут хватает, всё удобно.

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

Можно арендовать сервер у российского провайдера. Но зачем держать его включённым весь месяц, если сборки нужны лишь несколько часов в день?

Оставляем GitHub Actions.
Серверы берём только на время работы.

В этой статье — смысл, устройство и расчёт. Во второй — настройка на живом примере.

Двадцать минут на сборку.
Аренда — на весь месяц?

Возьмём условную команду с Android-приложением на Flutter. Одна сборка занимает 20 минут. За день её запускают 20 раз: проверить изменения, исправить ошибку, отдать версию тестировщику.

20сборок в день20минут на сборку20рабочих дней
В месяце 720 часов. Сборкам нужны примерно 133.
Постоянный сервер720 ч аренды
133 ч сборок587 ч простоя
Временные серверыТолько когда нужны

Те же сборки. Без аренды на всё остальное время.

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

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

Что происходит после отправки кода

GitHub умеет запускать задачи не только на своих машинах. На ваш сервер устанавливается программа-исполнитель — runner. Она получает задачу и выполняет команды сборки.

Мы используем одноразового исполнителя: одна задача — одна свежая машина. В документации это называется ephemeral runner.

  1. GitHub создаёт сервер

    Короткая подготовительная задача обращается к API Timeweb Cloud. Новая машина подключается к GitHub и ждёт свою сборку.

    На машине GitHub
  2. Приложение собирается

    На временной машине выполняются тесты и сборка. Готовый APK и нужные журналы сохраняются снаружи — они не должны исчезнуть вместе с сервером.

    В Timeweb Cloud
  3. GitHub удаляет сервер

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

    На машине GitHub

Для разработчика всё знакомо: отправил изменения, открыл вкладку Actions, дождался проверки, скачал приложение. Вручную включать сервер не нужно.

А почему не запускать сервер по уведомлению GitHub?

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

Здесь выбираем более простую отправную точку: три задачи provision → build → cleanup внутри GitHub Actions. Для каждой сборки нужна уникальная метка исполнителя, чтобы параллельные запуски не забирали чужие машины. Подробнее — в документации GitHub.

Не устанавливать Flutter четыреста раз

Машина новая, но не пустая. Заранее готовим образ — шаблон с Flutter, Android SDK, Java и исполнителем GitHub. Иначе перед каждой сборкой будем ждать установки одних и тех же инструментов.

Образ регулярно обновляем. Постоянные ключи в него не кладём, конфигурацию для одной задачи передаём при запуске. Кэш зависимостей продумываем отдельно: локальные файлы удалятся вместе с машиной.

Пример — для Android. Для сборки iOS по-прежнему нужны macOS и Xcode: Linux-сервер их не заменяет.

Теперь — к деньгам

За серверы — в рублях.
Без поиска иностранной карты.

Основную работу оплачиваем российскому провайдеру. У Timeweb Cloud есть СБП, банковские карты и оплата по счёту.

Для наших 8 000 минут сравним три варианта. У GitHub возьмём Linux-машину с четырьмя ядрами, у Timeweb — Cloud-80 с 4 vCPU и 8 ГБ памяти.

Пример на 400 сборок по 20 минут
Вариант и расчётСтоимость*
На машинах GitHubLinux 4-core
8 000 мин × $0,012
≈8 100 ₽$96 при условных 84 ₽/$
На постоянном сервереTimeweb Cloud-80
Аренда на весь месяц
1 800 ₽
На временных серверахТот же Cloud-80
133⅓ ч × ≈2,50 ₽
≈333 ₽Только время сборок

*Тарифы проверены 26 сентября 2026. Курс 84 ₽/$ взят для примера. 333 ₽ — базовая оценка, не полный счёт. Ставка ≈2,50 ₽/ч получена делением 1 800 ₽ на 720 часов; правила списания нужно подтвердить для выбранной конфигурации.

Почему это ещё не итоговый счёт? Серверу нужно загрузиться, подготовиться и удалиться. Есть округление оплаты, хранение образа и результатов, возможная плата за IP. А одинаковое число ядер не гарантирует одинаковую скорость сборки.

Что ещё учесть в расчёте

Если подготовка и удаление добавят по 3 минуты на каждый из 400 запусков, это ещё 20 часов. При пропорциональной оплате оценка вырастет до ≈383 ₽. Если же каждый запуск округляется до полного часа, четыреста коротких запусков обойдутся уже примерно в 1 000 ₽. Это два расчётных сценария, не утверждение о правилах Timeweb.

Linux 4-core у GitHub относится к увеличенным машинам — larger runners. Они доступны организациям на GitHub Team и Enterprise Cloud; включённые минуты на них не действуют. Для обычных машин и другой нагрузки результат будет иным.

По текущей документации использование собственных исполнителей бесплатно. Объявленную плату $0,002 за минуту GitHub отложил. Но подготовка и очистка на машинах GitHub расходуют минуты, а хранение тоже может быть платным. Если бесплатная квота закончится и способа оплаты нет, запуск этой схемы остановится.

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

Посчитайте свою нагрузку

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

Параметры сборок и аренды
Тарифы, подготовка и округление

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

Интерактивный расчёт загружается при просмотре этого блока. Без JavaScript доступна таблица примера выше.

400 сборок, 153,3 ч оплачиваемого времени. Постоянный сервер: 1 800 ₽. Временные серверы: 383 ₽. Временные дешевле на 1 417 ₽.

По умолчанию добавлены 3 минуты на подготовку и удаление каждой машины: получается около 383 ₽, а не 333 ₽ без накладного времени. Хранение, IP, операции на машинах GitHub и обслуживание не включены. Сравнение предполагает одинаковую скорость сборок и достаточную мощность постоянного сервера.

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

Сборка упала.
Сервер не должен остаться.

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

Например, отменили сборку посередине

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

Срок выбираем с запасом под нормальную сборку. Удаляем только явно помеченные сборочные машины и ненужные связанные ресурсы, а не «все старые серверы».

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

Проверка внутри GitHub не поможет во время недоступности самого GitHub. Для этого нужна очистка вне платформы. И сервер в РФ не означает, что все данные в РФ: код, журналы и результаты могут оставаться в GitHub.

А может, ничего не менять?

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

Если Kubernetes уже есть, посмотрите на Actions Runner Controller: он управляет исполнителями в кластере. Но заводить отдельный кластер только ради нескольких сборок в день необязательно.

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

Часть 2 · Готовится

Соберём приложение.
А потом специально всё сломаем.

Подготовим образ, соединим GitHub с Timeweb Cloud и получим первый APK. Затем сломаем сборку и отменим другой запуск посередине — проверим, не остались ли платные машины.

  • Рабочий пример в открытом репозитории
  • Скриншоты настройки без секретов
  • Фактическое время запуска и расходы

Цель — не просто зелёная галочка. А понятный ответ: сколько стоит сборка и кто уберёт сервер, если что-то пойдёт не так.