Как мне кэшировать шаги в действиях GitHub?

Скажем, у меня есть рабочий процесс действий GitHub с 2 шагами.

  1. Загрузите и скомпилируйте зависимости моего приложения.
  2. Скомпилируйте и протестируйте мое приложение

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

Можно ли сохранить результат первого шага, чтобы в будущем рабочий процесс мог пропустить этот шаг?

1 ответ

Кэширование теперь изначально поддерживается через действие cache. Он работает как с заданиями, так и с рабочими процессами в репозитории. См. Также: https://help.github.com/en/actions/automating-your-workflow-with-github-actions/caching-dependencies-to-speed-up-workflows.

Рассмотрим следующий пример:

name: GitHub Actions Workflow with NPM cache

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1

    - name: Cache NPM dependencies
      uses: actions/cache@v1
      with:
        path: ~/.npm
        key: ${{ runner.OS }}-npm-cache-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.OS }}-npm-cache-

    - name: Install NPM dependencies
      run: npm install

Где path а также key параметры cache действие используется для идентификации кеша.

Необязательный restore-keys используется для возможного возврата к частичному совпадению (т. е. если package-lock.json изменяет предыдущий кеш).

Добавление к ключу некоторого идентификатора (npm-cache в этом примере) полезен, когда restore-keysиспользуется резервный вариант, и существует несколько разных кешей (например, для пакетов JS и для системных пакетов). В противном случае один кеш может вернуться к другому несвязанному кешу. Точно так же префикс ОС полезен при использовании сборок матриц, чтобы кеши разных систем не смешивались.

Вы также можете создать свою собственную многоразовую логику кеширования с помощью @actions/cache, например:


Старый ответ:

Собственное кеширование в настоящее время невозможно, ожидается, что оно будет реализовано к середине ноября 2019 года.

Вы можете использовать артефакты (1, 2) для перемещения каталогов между заданиями (в пределах 1 рабочего процесса), как это предлагается на доске сообщества GH. Однако это не работает во всех рабочих процессах.

В cacheдействие может кэшировать только содержимое папки. Так что, если такая папка есть, вы можете выиграть время, кэшируя ее.

Например, если вы используете какой-то воображаемый package-installer (например, Python pip или virtualenv, или NodeJS' npmили что-нибудь еще, что помещает свои файлы в папку), вы можете выиграть время, сделав это следующим образом:

    - uses: actions/cache@v2
      id: cache-packages  # give it a name for checking the cache hit-or-not
      with:
        path: ./packages/  # what we cache: the folder
        key: ${{ runner.os }}-packages-${{ hashFiles('**/packages*.txt') }}
        restore-keys: |
          ${{ runner.os }}-packages-
    - run: package-installer packages.txt
      if: steps.cache-packages.outputs.cache-hit != 'true'

Итак, что здесь важно:

  1. Мы даем этому шагу имя, cache-packages
  2. Позже мы будем использовать это имя для условного выполнения: if, steps.cache-packages.outputs.cache-hit != 'true'
  3. Дайте действию кеширования путь к папке, которую вы хотите кэшировать: ./packages/
  4. Ключ кеширования: то, что зависит от хэша ваших входных файлов. То есть если естьpackages.txt файл изменяется, кеш будет перестроен.
  5. Второй шаг, установщик пакета, будет запущен только при отсутствии кеша.

Для пользователей virtualenv: если вам нужно активировать какое-то окружение оболочки, вы должны делать это на каждом этапе. Нравится:

- run: . ./environment/activate && command

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

Первый шаг:

Загрузите и скомпилируйте зависимости моего приложения.

Действия GitHub сами по себе не сделают этого за вас. Единственный совет, который я могу вам дать, - это следовать рекомендациям Docker, чтобы гарантировать, что если в действиях действительно используется кэширование Docker, ваше изображение можно будет использовать повторно, а не восстанавливать. Смотрите: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

При создании изображения Docker выполняет инструкции в вашем Dockerfile, выполняя каждое из них в указанном порядке. При рассмотрении каждой инструкции Docker ищет существующее изображение в своем кэше, которое он может использовать повторно, вместо создания нового (дублирующего) изображения.

Это также подразумевает, что базовая система GitHub Actions может / будет использовать кэширование Docker.

Однако при таких вещах, как компиляция, Docker не сможет использовать механизм кэширования, поэтому я советую вам очень хорошо подумать, если это то, что вам крайне необходимо. Альтернативой является загрузка скомпилированных / обработанных файлов из хранилища артефактов (Nexus, NPM, MavenCentral), чтобы пропустить этот шаг. Вы должны взвесить преимущества и сложность, которую вы добавляете в свою сборку.

Это в настоящее время изначально поддерживается с помощью: https://help.github.com/en/actions/automating-your-workflow-with-github-actions/caching-dependencies-to-speed-up-workflows.

Это достигается с помощью нового действия кеширования: https://github.com/actions/cache

Если вы используете Docker в своих рабочих потоках, как ответил @peterevans, GitHub теперь поддерживает кеширование с помощью действия кеширования, но имеет свои ограничения.

По этой причине вы можете найти это действие, чтобы обойти ограничения действий GitHub. Больше информации в этом сообщении блога.

Отказ от ответственности: я создал действие для поддержки кеша до того, как GitHub сделал это официально, и я до сих пор использую его из-за его простоты и гибкости.

В текущей версии GitHub Actions (23 августа 2019 г.) файл кэша невозможен. На circleCi это возможно.

Следующее, мои тесты:

Напишите файл на работу, попробуйте прочитать на следующем

Используется тестовый файл.

1) Запись на GITHUB_WORKSPACE
Мой путь: /home/runner/ работа /github-actions-test/github-actions-test)
Результаты: записываемые и читаемые на первом задании, но пустые на втором задании.

2) Запись на /github/home
Мой путь: /github/home
Результаты: cannot access '/github/home/ Действие ссылка

3) Запись на /home
Мой путь: / домой
Результаты: touch: cannot touch '/home/myFile.txt': Permission denied
Действие ссылка

Заключение

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

Я резюмирую два варианта:

  1. Кеширование
  2. Докер

Кеширование

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

За кулисами GitHub загружает zip-архив вашего каталога в собственное хранилище AWS github. Они удаляют все, что старше недели или если вы достигли ограничения в 2 ГБ.

Некоторые недостатки этого метода заключаются в том, что он сохраняет только каталоги. Так что если вы установили в /usr/bin, вам придется это кешировать! Это было бы неловко. Вместо этого вы должны установить в $home/.local и использовать echo set-env, чтобы добавить это в свой путь.

Докер

Docker немного сложнее, и это означает, что вам нужно иметь учетную запись dockerhub и теперь управлять двумя вещами. Но он намного мощнее. Вместо того, чтобы сохранять только каталог, вы сохраните весь компьютер! Что вы сделаете, так это создадите Dockerfile, в котором будут все ваши зависимости, такие как строки apt-get и python pip или даже длинная компиляция. Затем вы создадите этот образ докеры и опубликуете его на dockerhub. Наконец, ваши тесты настроены для запуска на этом новом образе докера, а не, например, на ubuntu-latest. И с этого момента вместо установки зависимостей он будет просто загружать образ.

Вы можете автоматизировать это дальше, сохранив этот Dockerfile в том же репозитории GitHub, что и проект, а затем написать задание с шагами, которые загрузят последний образ докера, при необходимости перестроят только измененные шаги, а затем загрузят в dockerhub. А затем задание, которое "нуждается" в этом и использует изображение. Таким образом, ваш рабочий процесс будет как обновлять образ докера, если необходимо, так и использовать его.

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


Я думаю, что у каждого есть свои плюсы и минусы. Кеширование подходит только для действительно простых вещей, таких как компиляция в.local. Если вам нужно что-то более обширное, Docker - самый мощный.

Кеширование теперь возможно с помощью actions / cache. См. Полный список примеров в репозитории.

например, узел - npm

- uses: actions/cache@v1
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

Также есть примечание об ограничениях кеша.

Размер отдельных кешей ограничен 400 МБ, а в репозитории может быть до 2 ГБ кешей. Как только будет достигнут предел в 2 ГБ, старые кеши будут исключены в зависимости от того, когда кеш был последний раз доступен. Кеши, к которым не было доступа в течение последней недели, также будут выселены.

Другие вопросы по тегам