Проект 4. Production pipeline
Выполнять после: раздела 16
Опирается на разделы: 11, 12, 14, 15, 16
Ориентировочное время: 12 часов
Оценивание: rubric, проходной результат 70
Задача
Построить полный цикл доставки для стека из проекта 3: от коммита до развёрнутого образа, с возможностью откатиться.
Итоговый проект курса. Он не добавляет новых механизмов — он требует связать вместе всё, что было, и честно сообщить, что из проверок выполнилось, а что нет.
Последнее — главное содержательное требование проекта. Конвейер, у которого «не проверено» неотличимо от «пройдено», становится зелёным ровно тогда, когда проверять перестали.
Требования
Обязательные
| № | Требование | Проверяется |
|---|---|---|
| 1 | Логика в скриптах, а не в шагах YAML | Checklist 1 |
| 2 | Порядок этапов выведен, а не назначен | Checklist 2 |
| 3 | Три состояния этапа: пройдено, провалено, не проверено | Checklist 3 |
| 4 | Сканирование образа с отдельным кодом «не проверено» | Checklist 3 |
| 5 | SBOM; частичный состав помечен как частичный | Checklist 4 |
| 6 | Проверки применяются к собранному образу | Checklist 5 |
| 7 | Тег неизменяемый: SHA коммита, признак грязного дерева | Checklist 6 |
| 8 | Кэш сборки переносится между запусками | Checklist 7 |
| 9 | Развёртывание по digest; развёртывание по тегу запрещено | Checklist 8 |
| 10 | План отката — команда, а не пожелание | Checklist 8 |
| 11 | Скрипты конвейера покрыты тестами | Checklist 9 |
Требования, невыполнение которых снимает работу
- отсутствие сканера даёт зелёный конвейер;
- публикация происходит при непройденных проверках;
- образ развёртывается по перезаписываемому тегу;
- «план отката» не содержит выполнимой команды.
Архитектура
Три состояния вместо двух
| Код | Значение | Что делать |
|---|---|---|
| 0 | Проверено, чисто | Публиковать |
| 1 | Проверено, есть находки | Исправлять |
| 3 | Не проверено | Разобраться, почему инструмента нет |
Без третьего кода сканер, который не установился, неотличим от сканера, не нашедшего проблем (урок 16.4). Хуже того: конвейер становится зелёным именно в тот момент, когда перестал проверять.
Требование 3 распространяется на конвейер целиком: итоговая сводка обязана различать три исхода, а публикация — требовать код 0.
Логика в скриптах
.github/workflows/pipeline.yaml ← только вызовы и окружение
ci/lib.sh ← общие определения, коды возврата, теги
ci/lint.sh ci/test.sh ci/build.sh
ci/verify-image.sh ci/scan.sh ci/sbom.sh
ci/pipeline.sh ← порядок и сводка
ci/deploy.sh ci/rollback.sh
Следствий три, и каждое проверяемо:
| Следствие | Как проверить |
|---|---|
| Конвейер отлаживается локально | ci/pipeline.sh работает без CI |
| Перенос на другую платформу механический | Шаги YAML — только run: ci/*.sh |
| Те же скрипты проверяют образ в тестах | ci/verify-image.sh вызывается и оттуда |
Порядок этапов
Сортировка по время / вероятность отказа: вперёд то, что падает часто и стоит секунды.
линтер → секунды, падает часто
тесты → минуты, падает часто
сборка → минуты, падает редко
проверка образа → секунды, падает редко
сканирование → минуты, находки бывают
состав (SBOM) → секунды, не падает
Сканирование стоит после сборки не по времени, а по смыслу: проверяется образ, а не исходники. Между ними Dockerfile, и его ошибки исходниками не ловятся.
Теги и развёртывание
| Что | Правило |
|---|---|
| Тег | g<sha12> плюс -dirty, если дерево не чисто |
| Публикация | Только при коде 0 |
| Развёртывание | Только по digest |
| Откат | Записанный предыдущий digest |
«Развернуть предыдущую версию» — не план отката, а пожелание. Планом он становится, когда предыдущий digest записан и команда выполнима без раздумий.
Пошаговый план
Шаг 1. Общие определения
ci/lib.sh: три кода возврата, функции журналирования, вычисление тега.
Тонкость, о которую легко споткнуться: git diff не видит неотслеживаемых файлов, а они входят в контекст сборки.
Шаг 2. Этапы
Отдельный скрипт на этап. Каждый обязан различать «инструмента нет» и «проверка не прошла».
Опора: урок 16.1.
Шаг 3. Сводка
Итог по всем этапам с тремя состояниями и кодом возврата.
Шаг 4. Образ
Базовый образ по digest, метки прослеживаемости, числовой пользователь.
Шаг 5. Развёртывание и откат
Отказ при развёртывании по тегу. Запись предыдущего digest.
Опора: урок 14.4.
Шаг 6. Тесты конвейера
Скрипты — код, и проверяются как код. Иначе об ошибке в них сообщит только сломанная выкатка.
Критерии завершения
ci/pipeline.shвыполняется локально без CI.- Убрать сканер из
PATH— итог3, не0. - Сломать один тест — итог
1. - Все проверки проходят — итог
0. ci/deploy.sh образ:теготвергается;образ@sha256:…принимается.ci/rollback.shбез записанного digest отказывается работать.- Добавить неотслеживаемый файл — тег получает
-dirty. - Шаги в YAML не содержат логики: только
run: ci/*.shи окружение. - Тесты конвейера проходят при грязном рабочем дереве.
Девятый пункт неочевиден и важен: тест, зависящий от состояния репозитория, ломается от собственной правки.
Дополнительные задания
| № | Задание | Что добавляет |
|---|---|---|
| 1 | Подпись образа и проверка подписи | Урок 12.7 |
| 2 | Проверка воспроизводимости: две сборки — один digest | Урок 5.9 |
| 3 | Развёртывание в два окружения с разными порогами | Разные требования к одному образу |
| 4 | Автоматический откат при провале проб после выкатки | Связь конвейера и эксплуатации |
| 5 | Измерить, сколько даёт кэш между запусками | Число вместо предположения |
Ни одно не реализовано в эталонном решении — причины названы в его конце.
Навигация
Список проверок →
Эталонное решение → — открывать после собственной попытки
← Предыдущий проект: Multi-service stack
Вернуться к проектам
Главное оглавление