12k
All articles

5 альтернатив GitHub Actions для фронтенд-команд

Сравните пять альтернатив GitHub Actions для frontend-команд: CircleCI, Buildkite, Jenkins, Woodpecker CI и Dagger. Примеры настройки и рекомендации.

OpenReplay Team
OpenReplay Team
5 альтернатив GitHub Actions для фронтенд-команд

Для фронтенд-команд лучшие альтернативы GitHub Actions таковы: CircleCI — полностью облачный CI; Buildkite — облачная управляющая плоскость (control plane), которая запускает задачи на облачных или собственных агентах; Jenkins и Woodpecker CI — полностью self-hosted CI; Dagger — пайплайны в виде кода, которые одинаково работают и на ноутбуке, и в любой CI-системе.

Обычно к поиску замены подталкивает одно из трёх: счёт, раздутый минутами раннеров, pull request, застрявший в очереди, или workflow, который падает только на раннерах GitHub и никогда — на вашей машине. Предполагается, что вы уже знакомы с моделью workflow в GitHub Actions. В статье пять вариантов сравниваются по трём критериям: кому каждый из них подходит, где выполняются задачи и как выглядит задача установки зависимостей, линтинга, тестирования и сборки для фронтенда на Node.

Основные выводы

  • Если каждая CI-задача лишь вызывает npm ci, npm run lint, npm test и npm run build, то смена CI-инструмента сводится к правке нескольких строк YAML, а не к переписыванию логики пайплайна.
  • Buildkite берёт оркестрацию на себя, а задачи выполняются на агентах: облачных Linux-агентах Buildkite, облачных macOS-агентах Buildkite на платных тарифах или на машинах вашей команды.
  • CircleCI — облачный CI, который настраивается в .circleci/config.yml и поддерживает self-hosted раннеры на всех тарифах, включая Free.
  • Jenkins и Woodpecker разворачиваются на собственной инфраструктуре. Вместо поминутной оплаты вы платите за серверы и их обслуживание.
  • Dagger — не CI-сервис, а код пайплайна, который работает локально и внутри любой CI-системы, которую вы уже используете.

Почему фронтенд-команды ищут альтернативы GitHub Actions?

Обычно фронтенд-команды уходят с GitHub Actions по одной из четырёх причин: минуты облачных раннеров обходятся слишком дорого, облачные раннеры простаивают в очереди, нужно запускать агенты на собственном железе или не получается воспроизвести CI/CD-пайплайн локально. Прежде чем мигрировать, проверьте вторую причину. Если единственная проблема — очередь к облачным раннерам, её можно решить с помощью self-hosted раннеров GitHub Actions, не меняя инструмент. GitLab CI/CD стоит рассматривать в первую очередь, если вы готовы перенести туда и репозитории; его настройка описана в статье GitLab CI/CD pipelines.

Чтобы сравнение было честным, вынесите логику сборки в package.json, тогда каждый CI-инструмент будет вызывать одни и те же скрипты:

{
  "scripts": {
    "lint": "eslint .",
    "test": "vitest run",
    "build": "vite build"
  }
}

Подставьте команды своего фреймворка. Во всех примерах ниже конфигурация CI делает только одно: запускает npm ci, а затем эти три скрипта.

Buildkite

Buildkite подходит командам, которым нужна облачная оркестрация, но важен контроль над машинами, на которых выполняются задачи. Buildkite поддерживает обе модели: агенты, которые вы запускаете сами, и агенты, которые Buildkite размещает за вас. Облачные Linux-агенты Buildkite доступны на всех тарифах, включая Free, где можно использовать только машины минимальной конфигурации. Облачные macOS-агенты Buildkite требуют тарифа Pro или Enterprise. Self-hosted агенты сами опрашивают Buildkite на наличие задач, поэтому открывать входящие порты не нужно. Для начала работы Buildkite предлагает бесплатный аккаунт.

# .buildkite/pipeline.yml
steps:
  - label: "Install, lint, test, build"
    commands:
      - npm ci
      - npm run lint
      - npm test
      - npm run build
    plugins:
      - docker#v5.14.0:
          image: "node:<your-node-version>"

Docker-плагин выполняет команды внутри образа Node, поэтому агенту нужен только Docker. Если Node уже установлен на агенте, блок plugins можно убрать.

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

CircleCI

CircleCI подходит командам, которым нужен полностью облачный сервис с минимумом инфраструктуры. CircleCI изначально ориентирован на облако, но также предлагает self-hosted раннеры на всех тарифах, включая Free. По умолчанию ваш код выполняется на инфраструктуре CircleCI. В вводном руководстве по конфигурации CircleCI актуальной указана версия 2.1.

# .circleci/config.yml
version: 2.1

jobs:
  build:
    docker:
      - image: cimg/node:<full.node.version>
    steps:
      - checkout
      - run: npm ci
      - run: npm run lint
      - run: npm test
      - run: npm run build

workflows:
  ci:
    jobs:
      - build

Зафиксируйте в cimg/node полную версию Node, используемую в проекте. CircleCI поддерживает и кеширование зависимостей, но здесь оно опущено ради краткости примера. Ошибки в YAML — частая причина того, что первый пуш в CircleCI завершается неудачей, поэтому имеет смысл прогнать файл через валидатор YAML от OpenReplay, чтобы отловить синтаксические ошибки до коммита.

Вердикт: CircleCI — наиболее близкая замена GitHub Actions по принципу «один в один». Он оправдан, если проблема в минутах и очередях, но поддерживать серверы вы по-прежнему не хотите.

Jenkins

Jenkins подходит командам со строгими требованиями к on-premises-развёртыванию и с человеком, у которого есть время его поддерживать. Jenkins разворачивается только на собственной инфраструктуре. Сам он бесплатный и с открытым исходным кодом, но затраты смещаются с поминутной оплаты на серверы, плагины и обновления, которые обслуживает ваша команда. Пайплайны описываются в файле Jenkinsfile с использованием декларативного синтаксиса Pipeline:

pipeline {
    agent any
    stages {
        stage('Install') { steps { sh 'npm ci' } }
        stage('Lint')    { steps { sh 'npm run lint' } }
        stage('Test')    { steps { sh 'npm test' } }
        stage('Build')   { steps { sh 'npm run build' } }
    }
}

agent any предполагает, что Node установлен на любом агенте, который возьмёт задачу.

Вердикт: выбирайте Jenkins, только если self-hosting — жёсткое требование. Для большинства фронтенд-команд затраты на его поддержку превышают экономию на минутах.

Woodpecker CI

Woodpecker CI подходит небольшим командам, которым нужен лёгкий self-hosted CI с привычным YAML. Woodpecker CI разворачивается на собственной инфраструктуре, и каждый шаг выполняет свои команды внутри контейнера, указанного в этом шаге, как описано в синтаксисе workflow. Workflow можно размещать в каталоге .woodpecker/, по одному на файл.

# .woodpecker/ci.yaml
steps:
  - name: install
    image: node:<your-node-version>
    commands:
      - npm ci
  - name: lint
    image: node:<your-node-version>
    commands:
      - npm run lint
  - name: test
    image: node:<your-node-version>
    commands:
      - npm test
  - name: build
    image: node:<your-node-version>
    commands:
      - npm run build

Разделение работы на четыре шага не означает четырёхкратной установки зависимостей. По умолчанию шаги выполняются последовательно, а рабочее пространство с извлечённым кодом монтируется в каждый шаг, поэтому каталог node_modules, созданный на шаге install, остаётся доступным и на шаге build. Если установлены woodpecker-cli и поддерживаемый бэкенд, можно запустить workflow локально командой woodpecker-cli exec перед пушем.

Вердикт: для self-hosting Woodpecker CI проще, чем Jenkins. Минус — сервер и агентов придётся поддерживать самостоятельно.

Dagger: пайплайны как код, а не CI-сервис

Dagger — не облачный CI-сервис и не заменяет его. Вы пишете пайплайн в виде кода с помощью Dagger SDK, и один и тот же код работает на ноутбуке и внутри любой CI-системы, включая GitHub Actions. Документация по SDK охватывает Go, Python, TypeScript, Java, PHP и Elixir, а также Dang — собственный скриптовый язык Dagger. Вот та же задача на TypeScript в модуле, созданном командой dagger init --sdk=typescript --name=frontend-ci:

import { dag, Directory, object, func } from "@dagger.io/dagger"

@object()
class FrontendCi {
  @func()
  async check(source: Directory, nodeVersion: string): Promise<string> {
    return await dag
      .container()
      .from(`node:${nodeVersion}`)
      .withMountedDirectory("/src", source)
      .withWorkdir("/src")
      .withExec(["npm", "ci"])
      .withExec(["npm", "run", "lint"])
      .withExec(["npm", "test"])
      .withExec(["npm", "run", "build"])
      .stdout()
  }
}

Локально модуль запускается командой dagger call check --source=. --node-version=<your-node-version>. Существующая CI-задача после этого выполняет ту же самую команду — и больше ничего. Если локальный запуск прошёл успешно, в CI выполнятся идентичные шаги в контейнере. Цена — ещё один SDK и движок, которые команде придётся освоить.

Эти команды относятся к Dagger 0.x. В Dagger 1.0, бета-версия которого анонсирована в октябре 2026 года, они переименованы: модуль создаётся командой dagger module init, а dagger call превращается в dagger api call. Сам код на TypeScript остаётся прежним.

Как выбрать альтернативу GitHub Actions?

Правильный выбор зависит от того, где вы хотите выполнять задачи:

  • Если нужен полностью облачный CI без какой-либо эксплуатации — используйте CircleCI. Его конфигурация близка к той, что у вас уже есть.
  • Если нужна облачная оркестрация на собственных машинах или машинах вендора — используйте Buildkite, особенно если требуются сборки под macOS.
  • Если self-hosting обязателен и есть люди для поддержки — используйте Jenkins.
  • Если self-hosting обязателен, а нужно что-то компактное — используйте Woodpecker CI.
  • Если настоящая проблема — «локально работает, в CI падает» — добавьте Dagger, а в качестве раннера оставьте любой из перечисленных инструментов или сам GitHub Actions.
  • Если проблема только во времени ожидания в очереди — сначала попробуйте self-hosted раннеры GitHub Actions.

Docker-бэкенду Woodpecker и Dagger требуется контейнерная среда выполнения. Если Docker Desktop не подходит для ваших машин, Dagger также работает с Podman и nerdctl, а Woodpecker можно запускать в Kubernetes или напрямую на хосте с помощью локального бэкенда.

Какой бы инструмент вы ни выбрали, начните с переноса всей логики сборки в npm-скрипты. Затем испытайте замену на одной ветке параллельно с GitHub Actions и в течение недели сравнивайте результаты, прежде чем окончательно переключиться.

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

Взимает ли GitHub поминутную плату за self-hosted раннеры в GitHub Actions?

Нет. GitHub не берёт поминутную плату за использование self-hosted раннеров, поэтому вы платите только за машины, на которых они работают. В декабре 2025 года GitHub объявил о введении платформенного сбора в размере 0,002 доллара США за минуту для self-hosted раннеров с 1 марта 2026 года, но затем отложил его, чтобы пересмотреть подход. Прежде чем строить сравнение затрат на любой из этих цифр, сверьтесь с документацией GitHub по тарификации Actions.

Можно ли запустить задачу CircleCI локально перед пушем?

Да, по одной задаче за раз. CircleCI CLI запускает отдельную задачу внутри Docker на вашей машине с помощью команды circleci local execute. Workflow локально не запускаются, machine executor не поддерживается. Для конфигурации версии 2.1 сначала экспортируйте обработанную конфигурацию командой circleci config process, а затем передайте этот файл в circleci local execute с флагом -c и именем задачи.

Работает ли Woodpecker CI с репозиториями на GitHub?

Да. Woodpecker поддерживает GitHub, включая GitHub Enterprise, а также GitLab, Gitea, Forgejo и Bitbucket Cloud. Вы регистрируете OAuth-приложение на платформе и передаёте его client ID и secret серверу Woodpecker через переменные окружения, например WOODPECKER_GITHUB_CLIENT и WOODPECKER_GITHUB_SECRET. Репозитории остаются на GitHub, Woodpecker отправляет туда статус пайплайнов, а на вашей инфраструктуре работают только сервер и агенты.

Как запустить функцию Dagger из существующего workflow GitHub Actions?

Добавьте после actions/checkout шаг с официальным action dagger/dagger-for-github. Этот action устанавливает Dagger CLI, запускает Dagger Engine на раннере и вызывает вашу функцию. Укажите verb со значением call и передайте те же аргументы, что и при локальном запуске, например check с каталогом исходников и версией Node. Логика пайплайна остаётся в модуле, поэтому при последующем отказе от GitHub Actions изменится только эта тонкая обёртка.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.