Build: Этап, на котором код становится чем-то рабочим

Вы только что запушили свои последние изменения. Пайплайн подхватывает их, чекаутит код и подготавливает окружение. Что дальше? Следующий шаг — убедиться, что этот код действительно может где-то выполняться. Это и есть этап сборки (build).

Многие новички в пайплайнах думают, что сборка — это просто компиляция. Если вы пишете на Java, вы компилируете в байт-код. Если на Go — компилируете в бинарник. Это часть процесса, но сборка — понятие более широкое. Любая работа по доставке ПО требует этапа сборки, даже если на выходе не бинарный файл.

Что на самом деле означает сборка

Код в том виде, в котором его пишут разработчики, обычно не готов к запуску на сервере. Его нужно преобразовать в то, что целевая система сможет выполнить. Для Java-приложения это означает компиляцию исходного кода в байт-код и упаковку в JAR или WAR-файл. Для Node.js-приложения сборка может включать запуск бандлера, минификатора или транспилятора, чтобы код был готов к продакшену. Для Go-приложения сборка означает компиляцию в самодостаточный бинарник.

Но сборка нужна не только для прикладного кода. Базы данных тоже требуют этапа сборки. SQL-код, хранимые процедуры и схемы баз данных необходимо компилировать или валидировать. Результат — не бинарник. Это набор файлов миграций, готовых к выполнению на целевой базе данных в правильном порядке. Сборка для баз данных обычно создает проверенные SQL-команды, прошедшие проверку синтаксиса и упорядочивания зависимостей.

Вот как может выглядеть этап сборки в конфигурации пайплайна для двух распространенных типов приложений:

build-nodejs:
  stage: build
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/

build-go:
  stage: build
  script:
    - go build -o app .
  artifacts:
    paths:
      - app

Инфраструктура тоже проходит процесс сборки. Terraform-файлы, CloudFormation-шаблоны и Ansible-плейбуки нуждаются в проверке синтаксиса, валидации, а иногда и в компиляции в более развертываемое представление. Результатом сборки инфраструктуры может быть валидированный конфигурационный файл, проверенный шаблон или даже предварительно собранный образ машины.

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

Диаграмма ниже показывает, как сборка преобразует различные типы исходного кода в готовые к запуску артефакты:

flowchart TD A[Исходный код] --> B{Этап сборки} B --> C[Приложение: Бинарник / Пакет / Образ контейнера] B --> D[База данных: Проверенные скрипты миграций] B --> E[Инфраструктура: Валидированный конфиг / План] C --> F[Артефакт с метаданными] D --> F E --> F F --> G[Следующий этап: Тестирование и сканирование]

Что должна давать хорошая сборка

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

Хорошо структурированный результат сборки включает:

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

Без этого нельзя доверять тому, что пайплайн передает на следующий этап.

Сборка должна быть воспроизводимой

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

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

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

Сборка — это первый шлюз

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

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

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

Сборка для разных типов работ

Давайте посмотрим, как сборка работает для каждой основной области.

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

Базы данных. Сборка для баз данных означает проверку синтаксиса SQL, проверку правильности порядка файлов миграций, а иногда и пробный прогон на копии схемы. Результат — набор проверенных скриптов миграций, готовых к выполнению.

Инфраструктура. Сборка для инфраструктуры означает валидацию конфигурационных файлов, проверку синтаксиса, а иногда и генерацию плана, показывающего, что изменится. Для таких инструментов, как Terraform, этап сборки может включать запуск terraform plan для создания предварительного просмотра изменений.

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

Краткий чек-лист сборки

Прежде чем считать этап сборки завершенным, проверьте эти пункты:

  • Сборка создает проверяемый артефакт (бинарник, образ, файл миграции, конфиг)
  • Сборка детерминирована: один и тот же код — один и тот же результат, каждый раз
  • Сборка выполняется менее чем за пять минут
  • Сборка падает быстро и выдает понятные сообщения об ошибках
  • Результат сборки включает версию, коммит и контрольную сумму в метаданных
  • Внешние зависимости зафиксированы до конкретных версий
  • Окружение сборки чистое и консистентное от запуска к запуску

Что дальше

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

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