Ответ
В DevOps-практике процесс сборки (Build) — это не просто компиляция кода, а создание неизменяемого, версионируемого и готового к развертыванию артефакта, чаще всего Docker-образа. Вот как это выглядит в моем опыте.
Цель: Преобразовать исходный код из Git-репозитория в артефакт, который можно предсказуемо развернуть в любом окружении (stage, prod).
Ключевые этапы пайплайна сборки:
-
Инициализация и получение кода:
- CI-раннер (GitLab Runner, GitHub Actions runner) запускается на подходящем хосте (с Docker, большим объемом RAM).
- Клонируется репозиторий с определенным тегом или коммитом. Важно использовать
git clone --depth 1для скорости.
-
Восстановление зависимостей и кэширование:
- Устанавливаются зависимости языка (например,
go mod download,npm ci,pip install -r requirements.txt). - Критически важно: Кэширование зависимостей между запусками пайплайна для значительного ускорения. В GitLab CI это выглядит так:
cache: key: "$CI_COMMIT_REF_SLUG" paths: - node_modules/ - .npm/
- Устанавливаются зависимости языка (например,
-
Статический анализ и проверка качества кода:
- Линтинг: Запускаются
golangci-lint,eslint,hadolint(для Dockerfile). - Security Scanning: Инструменты SAST, такие как
gosec,bandit(Python), или интеграция с Trivy/Snyk для поиска уязвимостей в зависимостях. - Этап "fail fast": если линтер или сканер безопасности находят критичные проблемы, сборка прерывается сразу, экономя время и ресурсы.
- Линтинг: Запускаются
-
Сборка Docker-образа (основной артефакт):
- Используется многоступенчатая сборка (multi-stage build) для создания минимальных образов.
# Dockerfile FROM golang:1.21-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -o /myapp
FROM gcr.io/distroless/static-debian12 COPY --from=builder /myapp /myapp USER nonroot:nonroot ENTRYPOINT ["/myapp"]
* Сборка запускается с явным тегом, включающим хэш коммита и номер сборки. ```bash docker build -t my-registry.com/myapp:${CI_COMMIT_SHA:0:8} -t my-registry.com/myapp:latest . - Используется многоступенчатая сборка (multi-stage build) для создания минимальных образов.
-
Запуск юнит- и интеграционных тестов:
- Тесты запускаются внутри только что собранного образа или в специальной тестовой среде.
test: stage: test script: - docker run --rm my-registry.com/myapp:${CI_COMMIT_SHA:0:8} go test ./... -v
- Тесты запускаются внутри только что собранного образа или в специальной тестовой среде.
-
Пуш артефакта в registry и создание отчетов:
- Успешно собранный и протестированный образ пушится в приватный registry (Harbor, GitLab Container Registry, ECR).
- Генерируются и сохраняются отчеты о тестировании (JUnit XML), покрытии кода (coverage) и сканировании безопасности для отображения в интерфейсе CI/CD.
Пример полной стадии build в .gitlab-ci.yml:
build:
stage: build
image: docker:24
services:
- docker:24-dind
variables:
DOCKER_TLS_CERTDIR: ""
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
# Сборка с кэшированием слоев
- docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
# Также проставляем тег 'latest' для master-ветки (осторожно!)
- |
if [[ "$CI_COMMIT_BRANCH" == "main" ]]; then
docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
docker push $CI_REGISTRY_IMAGE:latest
fi
cache:
key: docker-layer-cache
paths:
- $HOME/.cache/docker
artifacts:
reports:
junit: report.xml
expire_in: 1 week
Итог: На выходе этапа сборки мы получаем не просто бинарник, а версионированный Docker-образ, прошедший базовые проверки безопасности и качества, готовый для продвижения по следующим стадиям пайплайна (развертывание в staging, нагрузочное тестирование, деплой в production).