Источник: Nuances of Programming
Распространенный сценарий: команда разработчиков поддерживает множество Jenkinsfile, каждый из которых соответствует требованиям проекта. Однако эти сценарии непрерывной интеграции (CI) непригодны для повторного использования в другом хранилище. Причина заключается в том, что каждый проект обладает собственным технологическим стеком, версией, зависимостями для инструментов и т. д.
В таком случае многоэтапные сборки в docker— идеальное решение.
Эта технология уже давно известна, однако многие пользователи не осознают мощности ее потенциала.
Идея заключается в объединении нескольких Dockerfiles в один Dockerfile. Каждый файл будет выполнять определенную задачу в процессе разработки.
Рассмотрим на примере. Для демонстрации передовых концепций я добавил несколько сложных структур. Для начала ознакомьтесь с официальной документацией, чтобы узнать о возможностях CI.
Начнем с тестирования sonar:
Наконец переходим к последней стадии, которая будет отражена в результирующем образе. На этой стадии используется базовый образ и присутствуют лишь необходимые артефакты:
Jenkinsfile значительно упрощается (пример для Jenkins на Kubernetes):
Этот способ можно использовать практически для каждого проекта!
Основные преимущества:
- Возможность повторного использования из одной системы CI в другую (например, переход с Jenkins на действия GitHub). Идеально подходит для open source проектов.
- Тестирование можно выполнить локально с помощью команды docker build.
- Все, что относится к созданию и тестированию исходного кода, находится в Dockerfile. Следовательно, сценарии CI хранятся отдельно от исходного кода.
- Меньше возможностей для совершения ошибок: каждый шаг осуществляется в непривилегированном контейнере docker. Избежать docker daemon можно с помощью таких инструментов, как Kaniko.
Таким образом, все детали проекта изолированы, а сценарии CI можно использовать повторно в разных хранилищах, что упрощает инфраструктуру и повышает поддерживаемость.
Примечания
Пропуск шагов
К примеру, я использовал стадию переноса сгенерированной документации в области памяти (bucket) на S3. Этот шаг необходим в том случае, если сборка выполняется в системе CI, в которой предоставлены учетные данные для записи в этой области памяти.
Для этого устанавливаем аргумент build с командой ARG. По умолчанию установлено значение false, однако на своем CI-сервере я запустил docker build --build-arg push-docs=true, после которого выполняется команда aws s3 cp.
Экспорт отчета о тестировании и других артефактов
Главное условие при работе в docker build заключается в том, что артефакты хранятся в промежуточных образах docker. Например, результаты тестирования удобно хранить в рабочем пространстве Jenkins для генерирования статистики.
Любой артефакт можно с легкостью извлечь из любой промежуточной стадии с помощью меток.
Я отметил вторую стадию с помощью stage=test. Таким образом, после docker build можно запустить небольшой сценарий для получения файла test-results.xml
docker cp $(docker image ls --filter label=stage=test -q | head -1):/usr/src/app/tests-results.xml .
docker image ls используется для получения ID образа этой стадии, а docker cp для копирования файла.
Лучшее решение — это использование большого количества МЕТОК для фильтрации определенной сборки от других подобных сборок.
И последний совет: используйте BuildKit 😉
Читайте нас в телеграмме и vk
Перевод статьи Ignacio Millán: Shift your CI scripts to docker build