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

Мы перевели статью Мэтью Фронтона, которая поможет решить эту непростую задачу. Автор пробовал разные варианты на своих хост-машинах, в раннерах и проектах, а по итогу экспериментов составил краткое визуальное руководство.

Предисловие: кэш и артефакты

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

  1. Если текущее задание не зависит от предыдущего, то есть может выполняться самостоятельно, но в присутствии контента работа будет идти быстрее, используйте кэш.
  2. Если текущее задание действительно зависит от результатов предыдущего, то есть не может выполняться само по себе, используйте артефакты и зависимости.

Помните: кэш ускоряет работу, но его может не быть, так что не полагайтесь на него. Эта статья о кэше.

Простая модель кэширования

Возьмем простое представление конвейера Gitlab CI и забудем, что задания могут выполняться на любых раннерах и любых хостах. Так проще разобраться.

Допустим, у нас один проект, два раннера Docker и три ветви.

Локальный кэш: том Docker

Если хотите установить общий локальный кэш для всех заданий на одном и том же раннере, задайте инструкцию cache в файле .gitlab-ci.yml.

default:
 cache:
   path:
      - relative/path/to/folder/*.ext
      - relative/path/to/another_folder/
      - relative/path/to/file

Можно привязать кэш к конкретной ветви, установив предопределенную переменную «CI_COMMIT_REF_NAME» в качестве кэш-ключа (cache key).

default:
 cache:
   key: $CI_COMMIT_REF_NAME
   path:
     - relative/path/to/folder/*.ext
     - relative/path/to/another_folder/
     - relative/path/to/file

Предопределенная переменная «CI_JOB_NAME» в качестве кэш-ключа привязывает кэш к определенному заданию.

Локальный кэш: монтирование связей (технология Bind Mount)

Если том Docker не планируется использовать для кэширования, то при регистрации раннера установите опцию «монтирования связей» (bind mount). В этом случае уже не нужно задавать инструкцию cache в файле .gitlab-ci.yml.

#!/bin/bash

gitlab-runner register                             \
  --name="Bind-Mount Runner"                       \
  --docker-volumes="/host/path:/container/path:rw" \
...

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

#!/bin/bash

gitlab-runner register                             \
  --name="Bind-Mount Runner"                       \
  --docker-volumes="/host/path:/container/path:rw" \
...

gitlab-runner register                                 \
  --name="Bind-Mount Runner Y"                         \
  --docker-volumes="/host/path:/container/alt/path:rw" \
...

Распределенный кэш

Чтобы использовать общий кэш между всеми заданиями на нескольких раннерах и хостах, создайте раздел [runner.cache] в файле конфигурации config.toml.

[[runners]]
 name = "Distributed-Cache Runner"
...
 [runners.cache]
   Type = "s3"
   Path = "bucket/path/prefix"
   Shared = true
   [runners.cache.s3]
     ServerAddress = "s3.amazonaws.com"
     AccessKey = "<changeme>"
     SecretKey = "<changeme>"
     BucketName = "foobar"
     BucketLocation = "us-east-1"

Предопределенная переменная «CI_COMMIT_REF_NAME» в качестве кэш-ключа привязывает кэш к определенной ветви между несколькими раннерами и хостами.

Использование в реальном мире

Мы рассмотрели упрощенную модель, в которой заранее известно, на каком раннере/хосте выполняется задание. Это позволяет понять концепцию, а иногда даже использовать ее в реальной жизни в таком виде, например, регистрировать локальные раннеры, выбирать тегами нужные и настраивать их.

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

Для развлечения вот вам небольшое упражнение.

Необходимо установить кэш для всех заданий конкретного этапа, которые выполняются на любом раннере и на любых хостах, но только в одинаковых ветвях: