3.2.3 · блок 3
Пайплайн качества: lint, test, build, push
Пайплайн качества: lint, test, build, push
Зачем это нужно
Зелёный Jenkins — не самоцель. Цель — гарантировать, что каждый артефакт в registry прошёл согласованный набор проверок. Для ML-сервиса недостаточно «pytest прошёл»: нужны проверки контракта API, размера образа, smoke-тест predict и воспроизводимости зависимостей.
Этот урок собирает типовой quality pipeline, который вы повторите в практикуме модуля 3.2 и будете расширять до Helm и Argo CD.
Основные идеи
Lint — дешёвая первая линия. Статический анализ ловит опечатки, неиспользуемый код, нарушение стиля до запуска тестов. Для Python: ruff, flake8, mypy (по зрелости проекта). Stage должен быть быстрым (< 1 мин).
Test — поведение системы. Unit-тесты функций препроцессинга; интеграционные — API с TestClient FastAPI; для модели — фиксированный набор входов и ожидаемых форматов выхода (не обязательно точное совпадение float, но shape и dtype). Храните маленькие fixture-файлы в tests/fixtures/, не полный датасет.
Build — воспроизводимый образ. docker build с --pull периодически обновляет базовый образ (patch security). Тегируйте однозначно:
environment {
IMAGE = "registry.example.com/ml/scorer"
TAG = "${env.GIT_COMMIT.take(7)}-${env.BUILD_NUMBER}"
}
Не перезаписывайте тег latest без контроля — в prod деплоят immutable tags.
Push — только после успеха. Registry login через credentials; push в stage после test и build:
stage('Push') {
steps {
withCredentials([usernamePassword(
credentialsId: 'registry-creds',
usernameVariable: 'REG_USER',
passwordVariable: 'REG_PASS'
)]) {
sh '''
echo "$REG_PASS" | docker login registry.example.com -u "$REG_USER" --password-stdin
docker push ${IMAGE}:${TAG}
'''
}
}
}
Parallel stages. Независимые проверки (lint + unit tests) можно запускать параллельно — короче feedback.
Artifacts и отчёты. JUnit XML из pytest публикуют через junit 'reports/*.xml' — Jenkins показывает тренд тестов. Coverage — опционально, но полезно для кода inference (не для notebook DS).
Smoke после build. Лёгкий контейнерный тест: docker run --rm image curl localhost/health — ловит «образ собрался, но приложение не стартует».
Как это выглядит на практике
Полный Jenkinsfile для сервиса scoring:
| Stage | Команда | Gate |
|-------|---------|------|
| Lint | `ruff check .` | fail → stop |
| Test | `pytest -q --junitxml=reports/junit.xml` | fail → stop |
| Build | `docker build -t $IMAGE:$TAG .` | fail → stop |
| Smoke | run container + HTTP GET /health | fail → stop |
| Push | `docker push $IMAGE:$TAG` | только main |
В PR собирают и тестируют, push — только при merge в main (блок when { branch 'main' }).
Артефакт для следующих модулей: образ scorer:abc1234-57 в registry. Helm chart (3.4) будет ссылаться на этот тег через values.yaml. Jenkins не обязан делать kubectl apply — часто достаточно push + обновление values в Git для Argo CD.
Практикум модуля: добейтесь зелёного Jenkinsfile с минимум lint → test → build → push.
Что сделать после занятия
- [ ] Добавьте в свой репозиторий stage Lint и stage Test с JUnit-отчётом.
- [ ] Настройте push образа только для ветки
main. - [ ] Напишите smoke-тест: контейнер поднимается и
/healthвозвращает 200.