Как повысить скорость конвейера CI / CD с помощью кеширования и образов Docker

В настоящее время наличие CI в проекте просто необходимо. В большинстве случаев нам приходится платить за время, необходимое для установки зависимостей, сборки проекта, тестов, развертывания. Если вы считаете, что это ваш случай, я поделюсь своим опытом, как значительно улучшить производительность CI приложения Angular (и не только) и сократить расходы на выставление счетов в разы.

Улучшения конвейера

Установка зависимостей

Практически каждый конвейер начинается с установки зависимостей. Чтобы справиться с этим, обычно мы используем простую команду npm install или yarn. В нашей ситуации, когда мы запускаем его как часть CI, мы проверяем package-lock. Если у него те же версии, что и package.json, он установит все из файла блокировки. Но если package.json имеет более новые версии, он повторно сгенерирует файл блокировки пакета.

npm ci вместо npm install

Эта команда: npm ci похожа на npm install, за исключением того, что ее предпочтительно использовать в автоматизированных средах, таких как непрерывная интеграция. Он может быть значительно быстрее обычного npm install, если пропустить некоторые ориентированные на пользователя функции. Кроме того, у него есть супер классная функция, он вылетает с ошибкой, если package.json обновляется без package-lock. Так что вы можете быть уверены, что у вас всегда будут одни и те же версии зависимостей между сборками. Обычная установка npm в таком случае может установить более новую версию и сгенерировать новый package-lock.json.

npm ci с кешем

Кеш Npm находится в ~/.npm, но в большинстве CI вы можете кэшировать только вещи внутри своего рабочего каталога.

Что мы можем сделать, чтобы этого избежать, так это изменить каталог кеша на локальную папку в вашем проекте с помощью npm set cache .npm. Кэш NPM теперь находится в ./.npm, поэтому теперь он кэшируется между заданиями CI.

Например, мы используем Gitlab CI, где нам нужно настроить кеширование в .gitlab-ci.yml.

cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .npm/

После этого мы можем установить зависимости с помощью следующей команды:

npm ci — cache .npm — prefer-offline

Теперь наш CI использует кеш и делится им с нашими следующими запусками конвейера.

Скорость тестов Angular может быть выше до 3 раз (пока ошибка Angular не существует, проблема актуальна 14 декабря 2020 г.)

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

Автор предоставил временный обходной путь, как решить эту проблему до официального исправления.

Вам нужно просто добавить в свой проект несколько строк кода:

В проекте CLI откройте test.ts и добавьте следующие строки:

import { ɵDomSharedStylesHost } from ‘@angular/platform-browser’;
afterEach(() => {
   getTestBed().inject(ɵDomSharedStylesHost).ngOnDestroy();
});

Удивительно, но это работает! Поделитесь в комментариях, вам это помогло?

Улучшения докера

Согласно опросу разработчиков Jetbrains 2020 года, 44% разработчиков сейчас используют ту или иную форму CI и CD с контейнерами Docker. Так что я хотел бы поделиться некоторыми общими лучшими практиками. Каждый из них улучшит производительность любого приложения NodeJS, и неважно, используете ли вы Angular, React, Vue или vanilla js.

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

Если вы создадите приложение Angular или простой SSR, достаточно использовать образы Docker меньшего размера, такие как модификации Slim и Alpine Linux. Это сократит продолжительность построения, проталкивания и вытягивания изображений на вашем CI.

# base node image
FROM node:12-slim

Используйте кеш для восстановления ваших изображений и повторного запуска конвейеров

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

  1. установить модули перед копированием исходных файлов
  2. не используйте ярлыки LABEL build_number=”123"
# base node image
FROM node:12.20.0-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci

Используйте явную версию изображения вместо последней.

Когда вы используете последнюю / стабильную ссылку в качестве базового образа, вы не можете быть уверены, какая именно версия будет последней / стабильной. Так что лучше использовать точную версию базового изображения.

FROM node:12.20.0-alpine3.10 as builder

Разместите свой собственный CI / CD runner

Собственный раннер, в первую очередь, может повысить скорость сети. GCP / AWS / Digital Ocean имеет гораздо лучшую пропускную способность сети, чем встроенные бегуны, поэтому вы сэкономите время на установке зависимостей.
Во-вторых, если вам нужно, вы можете использовать машины с лучшим ЦП / ОЗУ, это будет быстрее, но не уверен, что это может сэкономить ваши деньги 😉.

Не устанавливайте все зависимости при каждом запуске

Вы можете сэкономить много времени, если используете Docker с предустановленными зависимостями. По крайней мере, вы можете предварительно установить в образе Docker глобальные зависимости, такие как CLI. Но если вы работаете с проектом, в котором зависимости редко получают обновления. Это может быть хорошим выбором - предварительно установить все зависимости и скопировать исходники в правильную папку. После этого вы можете запускать любую команду без установки зависимостей.

Вот и все. С помощью этих простых рекомендаций вы сможете значительно сэкономить время и деньги.

Спасибо за чтение! Если вы заинтересованы в создании SEO-ориентированного приложения на Angular, возможно, вам будет полезно прочитать мою предыдущую статью.