GitHub Actions убивает вашу команду — и вот почему

Обложка: GitHub Actions убивает вашу команду — и вот почему

Автор этого текста — Иэн Данкан, один из первых инженеров CircleCI. За свою карьеру он перепробовал практически все CI-системы, которые существуют: Jenkins, Travis CI, CircleCI, Semaphore, Drone, Concourse, Wercker, TeamCity, Bamboo, GitLab CI, CodeBuild и другие, названия которых милосердно стёрлись из памяти. Его вердикт: GitHub Actions — это не хорошо. Даже не «нормально». У него есть доля рынка ровно по одной причине — он уже там, прямо в вашем репозитории. Как плесень на стенах съёмной квартиры: вы не выбирали её, но она идёт в комплекте.

Если вы используете Nix, присмотритесь к Garnix — он анализирует ваш flake, определяет, что нужно собрать, и делает это. Никакого YAML. Лучший CI-конфиг — это отсутствие CI-конфига. Но эта статья не для вас. Эта статья — для всех остальных.

Часть I: Нисхождение

Просмотрщик логов, или Куда уходит ваш день

Билд упал. Красный крестик. Вы нажимаете на него и попадаете... нет, не в логи. Вы попадаете на страницу Checks Summary. Оттуда — в Workflow Runs. Оттуда — в Jobs. Каждый шаг свёрнут. Каждая страница — это новый спиннер. Три-четыре клика, чтобы добраться до собственно ошибки. Это не отладка — это квест.

Просмотрщик логов, надо отдать ему должное, стабильно роняет браузер. Не один раз, не случайно — воспроизводимо, надёжно. Откройте лог длинного билда, попробуйте поискать текст — Chrome ляжет. Это не баг, это фича: система предлагает вам отдохнуть от мониторов.

На длинных логах скроллбар становится декоративным. Он есть, он выглядит как скроллбар, но прокрутить до конца вы не сможете. Приходится скачивать raw-логи и открывать в текстовом редакторе, как будто на дворе 2003 год и вы только что поставили Gentoo.

Кнопка «Назад» — это рулетка. Вы ожидаете вернуться на PR, но попадаете на случайную страницу GitHub Actions, которую видите впервые в жизни.

А теперь — отладка. Вы пушите коммит, ждёте, смотрите логи. Что-то падает. Добавляете run: env. Пушите снова. Ждёте. Двадцатиминутный цикл обратной связи ради однострочного изменения. Повторяете четырнадцать раз. Ваш вечер закончился.

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

Ловушка YAML

Любая CI-система рано или поздно сводится к «куче YAML-файлов». Но YAML в GitHub Actions — это нечто особенное. Свой язык выражений, своя объектная модель контекста, свои правила интерполяции строк. Это уже не конфигурация — это программирование. Только без отладчика, без типов и без чувства собственного достоинства.

Синтаксис ${{ }} — это танец. Неправильно поставили кавычку? Ждите четыре минуты, пока раннер запустится, чтобы узнать, что ваша строка была молча проглочена. Этот язык выражений «рос в темноте, без присмотра» — слишком сложный для конфига, слишком ограниченный для настоящего языка программирования.

«А как же маркетплейс!»

GitHub Actions Marketplace — это npm для CI. Комьюнити-экшены разного качества: shell-скрипты с Dockerfile и мечтой.

uses: some-stranger/cool-action@v2 — вы только что дали незнакомцу доступ к вашему репозиторию, секретам и среде сборки. Можно, конечно, пригвоздить версию к SHA. Никто этого не делает.

Энергетика ночного рынка: каждый лоток обещает решить вашу проблему, а некоторые продавцы преследуют совсем другие цели.

Вы не владеете своими вычислениями

Вы арендуете раннеры у Microsoft — медленные, ограниченные в ресурсах, не поддающиеся настройке. Это породило целую индустрию стартапов: Namespace, Blacksmith, Actuated, Runs-on, BuildJet — компании, которые существуют исключительно потому, что штатные раннеры GitHub Actions непригодны для продакшена.

Self-hosted раннеры решают проблему вычислений, но вы по-прежнему пишете YAML для GitHub Actions — это как поставить новый двигатель в машину, которая загорается каждый раз, когда вы включаете радио.

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

Мелочи, которые накапливаются

  • actions/cache — ключи кеша непонятные, промахи молчаливые, вытеснение непрозрачное.
  • Reusable workflows нельзя вкладывать друг в друга, и у них нет чистого доступа к контексту вызывающего воркфлоу.
  • GITHUB_TOKEN permissions — лабиринт. permissions: write-all — это кувалда, а fine-grained permissions — это пазл на 500 деталей без картинки на коробке.
  • Concurrency controls — топорные. Отменить текущий запуск? Одна строка. Что-нибудь более тонкое? Нет.
  • Секреты нельзя использовать в условиях if: — обоснованное ограничение безопасности, но с точки зрения DX — катастрофа.

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

«Просто напиши баш-скрипты»

Искушение велико: просто засунуть всё в run: и написать большой shell-скрипт.

И это работает! А потом скрипт растёт. Условия, функции, парсинг аргументов, второй скрипт, обработка ошибок, логирование, «ну и чуть-чуть параллелизма».

Проходит три месяца — и вот у вас 800 строк баша, которые переизобретают параллельное выполнение задач при помощи wait и PID-файлов.

Race condition в cleanup-trap только на ядре Linux 6.x, вы в отпуске, телефон звонит.

Вы не избежали CI. Вы построили CI-систему. Просто она хуже.

Bash хорош как клей. Но он не система сборки. Не тестовый фреймворк. Не оркестратор. Каждый раз, когда кто-то говорит «просто напиши баш-скрипт», где-то в мире рождается ещё один 800-строчный ci.sh.

Часть II: Выход

Просмотрщик логов, который не убивает браузер

У Buildkite просмотрщик логов — это веб-страница, которая показывает логи и не падает. Звучит как минимальное требование к продукту, но после GitHub Actions это ощущается как роскошь.

  • ANSI-цвета работают — вывод тестового фреймворка приходит в первозданном виде, а не в виде кашицы из escape-последовательностей.
  • Аннотации — богатый Markdown-вывод прямо на странице билда.
  • Отладка: агент крутится на вашем железе, вы можете зайти на машину по SSH. Как нормальный человек, а не как археолог, расшифровывающий логи по слоям.

YAML, который знает своё место

YAML в Buildkite описывает пайплайн: шаги, команды, плагины. Это структура данных, а не язык программирования. Когда нужна логика — пишите скрипт на нормальном языке. Запускайте локально. Как человек, у которого есть достоинство.

Оркестрацию — в конфиг, логику — в код. Buildkite уважает эту границу.

Вы владеете своими вычислениями

Агент Buildkite — это один бинарник на ваших машинах. Ваш облачный провайдер, ваш дата-центр, ваше странное кастомное железо.

Никакой побочной индустрии «Buildkite, только быстрее» — просто поставьте машины помощнее.

GitHub Actions выдаст вам стандартную Ubuntu-виртуалку с эмоциональной теплотой зала ожидания в районной поликлинике.

Динамические пайплайны

Шаги пайплайна — это данные. Вы можете генерировать их динамически в рантайме.

Скрипт смотрит на монорепо, определяет, что изменилось, и загружает именно те шаги, которые нужны. Никаких захардкоженных матриц, никаких спагетти из if: contains(...).

			#!/bin/bash
# Определяем, какие сервисы изменились
CHANGED=$(git diff --name-only HEAD~1 | cut -d/ -f1 | sort -u)

# Генерируем шаги пайплайна
echo "steps:"
for svc in $CHANGED; do
  if [ -f "$svc/pipeline.yml" ]; then
    echo "  - label: \":rocket: Build $svc\""
    echo "    command: cd $svc && make build"
  fi
done | buildkite-agent pipeline upload
		

По поводу плагинов

Честно говоря, структурно плагины Buildkite похожи на маркетплейс GitHub Actions.

Но: тонкие shell-хуки вместо целых Docker-образов, меньше поверхности атаки. И главное — всё запускается на вашем железе, так что радиус поражения — под вашим контролем.

Маленькие радости

В Buildkite можно поставить кастомные эмодзи рядом с шагами пайплайна — :parrot:, :docker:, что угодно.

Объективно — бесполезная мелочь. Но она рассказывает вам о людях, которые создали этот продукт.

GitHub Actions — это продукт, спроектированный комитетом, который ни разу не задал вопрос: «А пользователю от этого радостно?»

Заключение

GitHub Actions победил не потому, что он хорош, а потому что он стоит по умолчанию. Internet Explorer от мира CI.

Если у вас маленькая команда и простое приложение — он сойдёт. Серьёзно, не переезжайте ради принципа.

Но если у вас продакшен-системы, монорепо, билды дольше пяти минут — присмотритесь к Buildkite.

GitHub Actions — это самая простая CI-система для старта. Buildkite — это лучшая CI-система для жизни.

Если ваш CI воюет с вами больше, чем помогает — проблема не в вас. Проблема в инструменте.

Это литературный перевод и адаптация статьи Иэна Данкана (Ian K. Duncan) GitHub Actions is Killing Your Team. Мнение автора оригинала может не совпадать с мнением редакции.