Режимы отказа конвейера

Что это такое

Конвейер отказывает двумя способами. Первый честный: стадия сообщает о настоящей проблеме, и изменение исправляют. Второй разъедающий: конвейер сообщает о том, что проблемой не является, или пропускает ту, что является, и люди перестают ему верить. Хронические режимы отказа — нестабильные тесты, медленные сборки, секреты в логах, ненадёжная основная ветка — все относятся ко второму виду.

Почему это важно

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

Ключевые идеи

Нестабильные тесты берут в карантин или чинят, но не перезапускают

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

тест падает -> разбираем причину нестабильности (состояние, время, seed, сеть)
            -> чиним её либо отправляем тест в карантин и заводим тикет
повторный запуск         -> вердикт конвейера становится шумом

Медленный конвейер — это падающий конвейер

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

Секреты утекают через логи, а не только через код

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

Развёртывания должны быть обратимыми, а не просто зелёными

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

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

Права — часть зоны поражения

Конвейер, который может развернуть в продакшен, хранит учётные данные, способные развернуть в продакшен. Всё, что может изменить конвейер, тем самым может изменить продакшен, поэтому определение конвейера заслуживает такого же просмотра, как приложение, а pull request из форков никогда не должен получать секреты.

Практика

Отправьте нестабильный тест в карантин и измерьте его

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

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

Докажите путь отката

Возьмите конвейер, развёртывающий версию, и добавьте стадию, которая разворачивает предыдущую версию. Запустите откат намеренно.

Готово, когда: откат завершается без ручного шага, а работающая версия — предыдущая.

Частые ошибки

  • Перезапуск упавших задач до прохождения — вердикт конвейера превращается в шум; исправить: чините или отправляйте нестабильный тест в карантин.
  • Неконтролируемый рост времени сборки — люди группируют изменения, и страдает ревью; исправить: кэшируйте зависимости и параллельте задачи.
  • Вывод конфигурации при провалах — секреты попадают в лог, который может прочитать кто угодно; исправить: маскируйте секреты и держите их вне отладочного вывода.
  • Отсутствие стадии отката — каждое плохое развёртывание требует ручного вмешательства; исправить: добавьте откат и отрепетируйте его.
  • Доступ pull request из форка к секретам — недоверенное изменение может развернуть что угодно; исправить: разделите недоверенный путь и требуйте ревью для прогонов с секретами.

Что читать дальше