Прямой ответ
Артефакт сборки — готовый к развёртыванию результат: Docker-образ, wheel-пакет, исполняемый файл, статический бандл. Главное правило: артефакт собирается один раз и продвигается по окружениям без пересборки. Если для тестового и продакшен-окружения выполняются разные сборки, проверенный код и работающий код — не одно и то же.
Типы хранилищ:
| Артефакт | Хранилище |
|---|---|
| Docker-образ | Реестр образов: Docker Hub, GHCR, Harbor, Nexus |
| Python-пакет | Индекс пакетов: PyPI, приватный devpi или Nexus |
| Бинарник, архив | Хранилище артефактов CI, объектное хранилище |
| Helm-чарт | Реестр чартов или OCI-реестр |
Версионирование — ключевая часть. Варианты меток и их свойства:
| Метка | Свойства |
|---|---|
latest |
Изменяемая, не указывает на конкретную версию; непригодна для выкатки |
v1.4.2 |
Человекочитаемая, но требует дисциплины версионирования |
| Идентификатор коммита | Однозначно связывает артефакт с кодом |
Дайджест (sha256:...) |
Неизменяемый, криптографически проверяемый |
Практика: тег для людей, дайджест для машин. Развёртывание по дайджесту исключает ситуацию, когда тег перезаписан и в окружение попала другая сборка.
# сборка с двумя метками и получение дайджеста
docker build -t registry.example.test/billing:1.4.2 \
-t registry.example.test/billing:$(git rev-parse --short HEAD) .
docker push --all-tags registry.example.test/billing
docker inspect --format '{{index .RepoDigests 0}}' registry.example.test/billing:1.4.2
Неизменяемость важна: если тег можно перезаписать, невозможно утверждать, что развёрнутая версия совпадает с проверенной. В реестрах настраивают запрет перезаписи существующих тегов и хранение по дайджесту.
Практика: организация хранения и продвижения
1. Один артефакт на все окружения. Различия между окружениями задаются конфигурацией, а не содержимым артефакта. Если для продакшена нужна отдельная сборка, различие следует вынести во внешние параметры.
2. Связь артефакта с ревизией кода. По артефакту должно быть возможно определить коммит, из которого он собран. Практика — метка с идентификатором коммита и запись в метаданных образа.
3. Срок хранения и очистка. Реестр без политики очистки растёт неограниченно. Правило: хранить все версии последних N релизов, промежуточные сборки — ограниченное время, артефакты веток — до слияния.
# политика хранения (пример для реестра образов)
retention:
keep_tags_matching: ["v*"] # релизы — бессрочно
keep_last_n_per_repo: 30 # промежуточные сборки
delete_untagged_after_days: 14
4. Скан безопасности перед продвижением. Проверка зависимостей в образе выполняется один раз при сборке, а результат привязывается к дайджесту. О практике аудита зависимостей — в статье про аудит зависимостей.
5. Продвижение, а не повторение. Переход из тестового окружения в продакшен — это изменение ссылки на уже существующий артефакт. Такой подход делает откат быстрым: переключение на предыдущий дайджест вместо пересборки.
6. Размер артефакта влияет на скорость выкатки. Многослойный образ с историей сборки тянет лишние данные; многоэтапная сборка уменьшает размер — см. оптимизацию Docker-образов.
Рекомендации:
- Запретите перезапись тегов для релизов. Изменяемая метка делает невозможным воспроизведение развёртывания.
- Храните метаданные вместе с артефактом. Коммит, время сборки, версия базового образа, результат проверок — по ним восстанавливается контекст.
- Не храните секреты в артефакте. Ключи и пароли, попавшие в слой образа, извлекаются из любого скачанного артефакта.
- Свяжите артефакт с пайплайном. Артефакт, собранный вручную, не имеет ни проверок, ни связи с ревизией; такие сборки стоит запретить — о пайплайне в статье про CI/CD.
- Версионируйте по принятой схеме. Семантическое версионирование помогает понять характер изменения; детали — в статье про версии и релизы.
Практический сценарий: откат занял сорок минут вместо минуты
Контекст: после неудачной выкатки потребовался возврат к предыдущей версии. Процесс занял сорок минут и потребовал участия трёх человек.
- Что происходило. Откат выполнялся пересборкой образа из тега предыдущего релиза. За прошедшие две недели базовый образ обновился, поэтому пересборка дала другой набор системных библиотек и потребовала повторного прогона тестов.
- Причина 1. Развёртывание шло по тегу, а не по дайджесту, поэтому невозможно было точно указать прежнюю сборку.
- Причина 2. Политики хранения не было: старые образы удалялись автоматически, и нужный пришлось восстанавливать из резервной копии реестра.
- Действия. (а) Перешли на развёртывание по дайджесту; (б) релизные образы помечали неизменяемыми тегами и исключили из автоматической очистки; (в) откат реализовали как переключение ссылки на предыдущий дайджест; (г) добавили проверку, что выкатываемый дайджест соответствует прошедшему проверки.
- Результат. Следующий откат занял около минуты и выполнялся одним человеком; повторный прогон тестов не потребовался, потому что артефакт уже был проверен.
Вывод: скорость отката определяется не качеством пайплайна, а тем, сохраняется ли проверенный артефакт в неизменном виде. Хранение и версионирование артефактов — это страховка, стоимость которой заметна только в момент инцидента.
FAQ
Чем артефакт отличается от исходного кода? Артефакт — собранный результат, готовый к запуску. Код определяет, что должно получиться, но две сборки из одного кода могут отличаться из-за версий зависимостей и базовых образов. Поэтому развёртывают артефакт, а не код.
Нужно ли хранить все сборки? Релизные версии — да, в течение срока, необходимого для воспроизведения и отката. Промежуточные сборки веток хранят ограниченное время: их ценность заканчивается после слияния.
Можно ли использовать latest в продакшене?
Нет. Тег latest указывает на последнюю отправленную сборку и может измениться в любой момент, поэтому поведение развёртывания становится непредсказуемым. Для автомата нужен дайджест или неизменяемый тег.
Где хранить артефакты фронтенда? В том же реестре или объектном хранилище с версионированием по коммиту. Ключевое требование то же: выкладываемый бандл должен быть тем же файлом, который прошёл проверки, а не пересобираться на этапе публикации.
Источники: Docker Registry docs, Python Packaging User Guide, GitHub Actions docs (artifacts) — ссылки в шапке.