7 способов ускорить GitLab CI/CD при использовании Docker

Данная статья является переводом статьи автора Wes Cossick из Sparksuite.

При работе с любой системой непрерывной интеграции огромное значение имеет скорость выполнения задач интеграции и развертывания. Некоторое время назад мы начали рефакторинг процессов CI, чтобы сделать их максимально быстрыми. Вы cможете сделать то же самое, следуя нашим советам.

Создайте свой собственный исполнитель GitLab CI

Решение SaaS от GitLab предоставляет пользователям разделяемые исполнители CI. Мы выяснили, что эффективней всего для оптимизации сборок иметь собственный исполнитель. Основной проблемой для нас была сеть, а не ресурсы CPU или RAM. На частном облачном сервере сеть значительно быстрее. На выделенном исполнителе GitLab CI мы заметили, что скорость сборки увеличилась вдвое как на DigitalOcean, так и на Google Cloud Platform.

Скорость сети особенно важна для сборки и развертывания. Сборка требует загрузки библиотек, зависимостей, образов Docker и др., для развертывания требуется загрузка ресурсов в отдельное место. Когда на разделяемых исполнителях GitLab сеть становится перегруженной, выполнение этапов сборки кажется бесконечным.

Хорошая новость в том, что довольно легко можно настроить собственный исполнитель! Можно быстро запустить серверы от DigitalOcean, AWS, или GCP и установить исполнитель GitLab в Linux с помощью нескольких команд. Просто следуйте официальным инструкциям.

Заранее установите зависимости

Это важно. Можно тратить время и устанавливать зависимость каждый раз при запуске задачи CI. А можно использовать для задач CI Docker-образы, в которых уже есть все необходимые зависимости.

Если вы не можете найти образ со всеми необходимыми зависимостями, создайте его заранее и сохраните в реестр образов, к которому GitLab исполнитель имеет доступ. Нам нравится реестр для контейнеров, встроенный в GitLab.

Используйте мини-дистрибутивы Linux для образов CI

При любой возможности используйте мини-дистрибутив Linux для образов, используемых для задач CI. Alpine Linux, вероятно, самый популярный вариант, но есть и другие.

Почему? Скорее всего, вам не нужен раздутый дистрибутив, например, Ubuntu, чтобы запустить несколько тестов или выполнить некоторые команды сборки. Не стоит тратить время на загрузку образа, который может быть в 30-40 раз больше.

Используйте драйвер хранилища overlay2

Единственным и самым простым способом ускорить выполнение конвейера задач CI является использование драйвера хранилища Docker overlay2 вместо драйвера vfs, используемого по умолчанию (читайте подробнее). Это можно сделать, добавив две строки в начало файла .gitlab-ci.yml:

variables:
  DOCKER_DRIVER: overlay2

Убедитесь, что вы указали overlay2, а не overlay, т.к. по нашим наблюдениям, overlay2 позволяет сэкономить на несколько секунд больше, по сравнению с overlay.

Как вариант, если вы настроили свой исполнитель и у вас есть доступ к файлу config.toml, вы можете подключить этот драйвер для каждого проекта автоматически, добавив следующую строку в секцию [[runners]] (читайте подробнее):

environment = ["DOCKER_DRIVER=overlay2"]

Используйте кэшированный образ Docker

Docker умен – он использует кэш сборки и пересобирает только изменившиеся слои, тем самым существенно ускоряя сборку всего образа. Но если Docker не может найти предыдущую сборку (что возможно, если каждый раз вы запускаете задачу CI “с чистого листа”), вам придется заново собирать образы.

Чтобы это исправить, просто сообщите Docker’у, где находится предыдущий собранный образ, с помощью --cache-from (добавлено в Docker v1.13). Читайте об этом подробнее о параметрах docker build.

Тщательно продумайте Dockerfile

Говоря о кэше сборки Docker’а, необходимо знать, как он работает. Если кратко, то каждая инструкция – это слой, а каждый слой пересобирается только, если он был изменен, или если предыдущий слой был изменен. Суть “изменения” зависит от типа инструкции, подробнее можно узнать здесь.

Важно, что Docker не будет запускать инструкции, которые фактически не изменились, если кэш находится в актуальном состоянии. Например, если ваш контейнер устанавливает NGINX с помощью инструкции:

RUN apt-get -y update && apt-get -y install nginx

Вы не должны указывать инструкцию для копирования исходных файлов в контейнер перед ней:

COPY source/ /usr/share/nginx/html

Если вы не последуете этому совету, то Docker будет переустанавливать NGINX каждый раз при изменении исходных файлов в source/, поскольку это обнуляет кэш.

Используйте кэш GitLab

Если в процессе выполнения задачи требуется динамически установить определенные зависимости, и по каким-то причинам нет возможности предварительно собрать их в образ CI, подумайте об использовании кэширования в GitLab между выполнением задач. Взгляните на следующий пример, который показывает, как между сборками кэшируется каталог NPM node_modules:

example-job:
  stage: example
  script:
    - npm install
  cache:
    paths:
      - node_modules/

Читайте подробнее о настройке кэширования в GitLab.

Если вам понравилась статья, поделитесь ей с друзьями.