CI/CD позволяет разработчикам и организациям реализовывать циклы задач быстрее. Автоматизируя такие процессы, как сборка, тестирование и развертывание ПО, мы затрачиваем меньше времени на типовые задачи и можем уделить больше внимания работе над самими приложениями. Для удобства создания CI/CD заданий существуют решения вроде GitLab, CircleCI и GitHub.
Как правило, CI/CD задание должно выполняться в отдельном контейнере Docker, что дает нам воспроизводимую среду сборки. Например, можно использовать образ Node.js, размещенный на Docker Hub. Ваше задание будет выполняться в контейнере, основанном на выбранном образе. А в этом контейнере есть все зависимости Node, необходимые для сборки приложения.
В этом случае актуален девиз “меньше значит больше”. Нам ведь не нужны длительно выполняющиеся задания? Но при этом мы также не хотим жертвовать преимуществами платформы CI/CD.
В данной статье я поведаю один из способов ускорить конвейер, а для примеров кода буду использовать GitLab CI.
Уменьшение длительности задания CI/CD за счет уменьшения контейнера Docker
Обычно платформы CI/CD позволяют настраивать задания и конвейеры при помощи файлов YAML. В случае с GitLab CI нам в репозитории нужен файл .gitlab-ci-yml
. В данный момент нас интересует конкретно опция image
. Ключевое слово image
является именем образа, который Docker запускает для выполнения задач CI.
Наша первая попытка выглядит так:
default:
image: node:12.10.0
before_script:
- npm ci
Build:
script:
- npm run build
Run tests:
script:
- npm test
Lint project:
script:
- npm run lint
Вкратце рассмотрим эту конфигурацию:
- мы сообщаем GitLab по умолчанию использовать образ Node (версии 12.10.0);
- запускаем
npm ci
перед каждым заданием, устанавливая все зависимости; - у нас есть три задания. Одно отвечает за сборку, второе за линтовку проекта, а третье за его тестирование.
Конкретно плохого в этой конфигурации ничего нет. Тем не менее из логов выше видно, что на скачивание и подготовку образа Node ушло 33 секунды. Вроде бы и не очень долго, но это не окончательная цифра, и в итоге общее время окажется очень затратным, особенно с позиции оплачиваемых минут. Дело в том, что “полный” образ, подобный используемому в нашем примере, содержит ряд дополнительных компонентов вроде библиотек среды выполнения и программ для контроля версий.
Разобравшись с основами, можно попробовать добиться улучшения, взяв образ меньшего размера. В примере ниже я используя образ alpine-node. Alpine Linux намного меньше, чем большинство базовых образов дистрибутивов, что снижает общий размер образа. Помимо этого изменения, остальная конфигурация сохраняется.
Время загрузки и подготовки образа Node сократилось до 15 секунд, то есть больше, чем вдвое! Если учесть, что для этого потребовалось изменить всего одну строчку кода, то можно считать такой прирост очень существенным.
Наиболее совместимыми с небольшими образами Docker являются, в частности, фронтенд-проекты, так как им редко требуется что-либо кроме Node.
Недостатки малых образов Docker
Как бы то ни было, но иногда все же нужен именно полноценный образ. В примере ниже я попытался использовать alpine-node в проекте Express.js, который работает с библиотекой bcrypt. В логах видно, что образ alpine-node не отвечает всем требованиям для правильной установки зависимостей проекта. В связи с этим задание проваливается, и мы вынуждены использовать образ, соответствующий требованиям проекта.
Заключение
Как видите, очень легко попробовать другой образ, например alpine-node
, и оценить, подойдет ли он вам. Как правило, начинать лучше именно с небольших вариантов. Если же они не будут отвечать требованиям проекта, то можно без проблем переключиться на другой образ.
Читайте также:
- Как использовать Laravel Sail с бэкендом Docker Desktop на WSL 2
- Реализация GitHub Action в контейнере Docker
- Kubernetes избавляется от Docker
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Ali Kamalizade: Speed Up Your CI Pipeline With Smaller Docker Images