Как избежать переустановки зависимостей для каждой работы в Gitlab CI
Я использую Gitlab CI 8.0 с gitlab-ci-multi-runner 0.6.0. У меня есть файл .gitlab-ci.yml
, похожий на следующий:
before_script:
- npm install
server_tests:
script: mocha
client_tests:
script: karma start karma.conf.js
Это работает, но это означает, что зависимости устанавливаются независимо перед каждым тестовым заданием. Для большого проекта со многими зависимостями это создает значительные накладные расходы.
В Jenkins я бы использовал одно задание для установки зависимостей, затем TAR их и создав артефакт сборки, который затем копируется на последующие задания. Будет ли что-то подобное работать с Gitlab CI? Есть ли рекомендуемый подход?
Ответы
Ответ 1
В наши дни лучше использовать artifacts.
В следующем примере каталог node_modules/
сразу доступен для задания lint
после успешного завершения этапа build
.
build:
stage: build
script:
- npm install -q
- npm run build
artifacts:
paths:
- node_modules/
expire_in: 1 week
lint:
stage: test
script:
- npm run lint
Ответ 2
Обновить. Теперь я рекомендую использовать artifacts
с коротким expire_in
. Это превосходит cache
, потому что он должен только писать артефакт один раз для каждого конвейера, тогда как кеш обновляется после каждой работы. Кроме того, кэш предназначен для каждого бегуна, поэтому, если вы выполняете свои задания параллельно на нескольких бегунах, он не гарантирует, что он будет заполнен, в отличие от артефактов, которые хранятся централизованно.
Gitlab CI 8.2 добавляет кеширование бегунов, которое позволяет повторно использовать файлы между сборками. Однако я нашел это очень медленным.
Вместо этого я реализовал свою собственную систему кеширования, используя немного скриптов оболочки:
before_script:
# unique hash of required dependencies
- PACKAGE_HASH=($(md5sum package.json))
# path to cache file
- DEPS_CACHE=/tmp/dependencies_${PACKAGE_HASH}.tar.gz
# Check if cache file exists and if not, create it
- if [ -f $DEPS_CACHE ];
then
tar zxf $DEPS_CACHE;
else
npm install --quiet;
tar zcf - ./node_modules > $DEPS_CACHE;
fi
Это будет выполняться перед каждым заданием в .gitlab-ci.yml
и только устанавливать зависимости, если package.json
изменилось или файл кэша отсутствует (например, первый запуск или файл был удален вручную). Обратите внимание: если на разных серверах есть несколько бегунов, каждый из них будет иметь свой собственный файл кеша.
Вы можете очистить файл кэша на регулярной основе, чтобы получить последние зависимости. Мы делаем это со следующей записью cron:
@daily find /tmp/dependencies_* -mtime +1 -type f -delete
Ответ 3
Я предпочитаю использовать кеш, потому что удаляет файлы после завершения конвейера.
пример
image: node
stages:
- install
- test
- compile
cache:
key: modules
paths:
- node_modules/
install:modules:
stage: install
cache:
key: modules
paths:
- node_modules/
after_script:
- node -v && npm -v
script:
- npm i
test:
stage: test
cache:
key: modules
paths:
- node_modules/
policy: pull
before_script:
- node -v && npm -v
script:
- npm run test
compile:
stage: compile
cache:
key: modules
paths:
- node_modules/
policy: pull
script:
- npm run build
Ответ 4
Я думаю, что это не рекомендуется, потому что все задания одной и той же стадии могут выполняться параллельно.
- Сначала все задания сборки выполняются параллельно.
- Если все задания сборки успешно завершены, тестовые задания выполняются параллельно.
- Если все задания теста завершены успешно, задания развертывания выполняются параллельно.
- Если все задания развертывания успешно завершены, фиксация отмечена как успешная.
- Если какое-либо из предыдущих заданий выходит из строя, коммит отмечен как сбой, и никакие задания более позднего этапа не выполняются.
Я читал, что здесь:
http://doc.gitlab.com/ci/yaml/README.html
Ответ 5
Из документов:
-
cache
: используется для временного хранения зависимостей проекта. Не полезно для хранения промежуточных результатов сборки, таких как файлы jar
или apk
. Кэш-память была разработана для ускорения вызовов последующих запусков заданного задания, сохраняя такие вещи, как зависимости (например, пакеты npm, пакеты Go-вендора и т.д.), Чтобы их не нужно было повторно загружать из общедоступного Интернета. Хотя кэш-память может использоваться для передачи промежуточных результатов сборки между этапами, могут быть случаи, когда артефакты лучше подходят.
-
artifacts
: используйте для результатов этапа, которые будут передаваться между этапами. Артефакты были разработаны для загрузки некоторых скомпилированных/сгенерированных битов сборки, и они могут быть выбраны любым числом одновременных бегунов. Они гарантированно доступны и предназначены для передачи данных между заданиями. Они также могут быть загружены из пользовательского интерфейса. Артефакты могут существовать только в каталогах, относящихся к каталогу сборки, и указание путей, которые не соответствуют этому правилу, приводит к появлению неинтуитивного и нелогичного сообщения об ошибке (расширение обсуждается на https://gitlab.com/gitlab-org/gitlab-ce/issues./15530). Артефакты должны быть загружены в экземпляр GitLab (не только GitLab Runner), прежде чем запускать задания следующего этапа, поэтому вам необходимо тщательно оценить, позволяет ли ваша пропускная способность получать прибыль от распараллеливания с этапами и общими артефактами, прежде чем тратить время в изменениях в настройках.
Итак, я использую cache
. Когда не нужно обновлять де-кеш (например, создавать папку в тестовом задании), я использую policy: pull
(см. Здесь).