Кэширование пакетов APT в рабочем процессе GitHub Actions

9

Я использую следующий рабочий процесс Github Actions для своего C-проекта. Рабочий процесс завершается через ~ 40 секунд, но более половины этого времени уходит на установкуvalgrind пакета и его зависимостей.

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

name: C Workflow

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1

    - name: make
      run: make

    - name: valgrind
      run: |
        sudo apt-get install -y valgrind
        valgrind -v --leak-check=full --show-leak-kinds=all ./bin

Запуск sudo apt-get install -y valgrindустанавливает следующие пакеты:

  • gdb
  • gdbserver
  • libbabeltrace1
  • libc6-dbg
  • libipt1
  • valgrind

Я знаю, что действия поддерживают кэширование определенного каталога (и уже есть несколько ответов на SO вопросы и статьи по этому поводу), но я не уверен, где все различные пакеты, установленные apt, заканчиваются. Я предполагаю /bin/или /usr/bin/не единственные каталоги, затронутые установкой пакетов.

Существует ли элегантный способ кэширования установленных системных пакетов для будущих рабочих процессов?

natiiix
источник

Ответы:

5

Цель этого ответа - показать, как можно выполнять кэширование с помощью действий GitHub. Не обязательно показывать, как кешировать valgrind, что он показывает, но также показывать, что не все можно / нужно кэшировать, и нужно учитывать компромиссы кэширования и восстановления кеша по сравнению с переустановкой зависимости.


Вы будете использовать actions/cache действие, чтобы сделать это.

Добавьте его как шаг (перед тем, как вам нужно будет использовать valgrind):

- name: Cache valgrind
  uses: actions/cache@v1.0.3
  id: cache-valgrind
  with:
      path: "~/valgrind"
      key: ${{secrets.VALGRIND_VERSION}}

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

- name: Install valgrind
  env:
    CACHE_HIT: ${{steps.cache-valgrind.outputs.cache-hit}}
    VALGRIND_VERSION: ${{secrets.VALGRIND_VERSION}}
  run: |
      if [[ "$CACHE_HIT" == 'true' ]]; then
        sudo cp --verbose --force --recursive ~/valgrind/* /
      else
        sudo apt-get install --yes valgrind="$VALGRIND_VERSION"
        mkdir -p ~/valgrind
        sudo dpkg -L valgrind | while IFS= read -r f; do if test -f $f; then echo $f; fi; done | xargs cp --parents --target-directory ~/valgrind/
      fi

объяснение

Установите VALGRIND_VERSIONсекрет, чтобы быть результатом:

apt-cache policy valgrind | grep -oP '(?<=Candidate:\s)(.+)'

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

dpkg -L valgrindиспользуется для отображения списка всех файлов, установленных при использовании sudo apt-get install valgrind.

Теперь мы можем скопировать все зависимости в нашу папку кеша:

dpkg -L valgrind | while IFS= read -r f; do if test -f $f; then echo $f; fi; done | xargs cp --parents --target-directory ~/valgrind/

более того

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

  • libc6
  • libgcc1
  • GCC-8-база

Чтобы скопировать все эти зависимости, вы можете использовать тот же синтаксис, что и выше:

for dep in libc6 libgcc1 gcc-8-base; do
    dpkg -L $dep | while IFS= read -r f; do if test -f $f; then echo $f; fi; done | xargs cp --parents --target-directory ~/valgrind/
done

Стоит ли вся эта работа с трудом, когда все, что требуется для установки, valgrind- это просто запустить sudo apt-get install valgrind? Если ваша цель состоит в том, чтобы ускорить процесс сборки, то вам также необходимо учитывать время, которое требуется для восстановления (загрузки и извлечения) кэша, а не просто повторного запуска команды для установки valgrind.


И, наконец, чтобы восстановить кеш, предполагая, что он хранится в /tmp/valgrind, вы можете использовать команду:

cp --force --recursive /tmp/valgrind/* /

Который будет в основном копировать все файлы из кэша в корневой раздел.

В дополнение к процессу выше, у меня также есть пример «кэширования valgrind» путем его установки и компиляции из исходного кода. Размер кэша теперь составляет около 63 МБ (сжатого), и все еще необходимо отдельно установить, libcкакой тип поражения цели.


Ссылки:

smac89
источник
О, я вижу, это гениально. Я понятия не имел, что вы можете безопасно взять все установленные файлы и просто переместить их в другой каталог, не ломая что-либо. Я не уверен, что это работает, хотя Я запускал рабочий процесс 3 раза и всегда уходил Cache not found for input keys: ***.. Я добавил VALGRIND_VERSIONсекрет в Настройки> Секреты, это правда?
natiiix
Мне удалось получить попадание в кеш, но я получаю следующую ошибку от valgrind:--2906-- Reading syms from /lib/x86_64-linux-gnu/ld-2.27.so --2906-- Considering /lib/x86_64-linux-gnu/ld-2.27.so .. --2906-- .. CRC mismatch (computed 1b7c895e wanted 2943108a) --2906-- object doesn't have a symbol table
natiiix
@natiiix существует вероятность того, что кэширование valgrindсделало так, чтобы libcпри извлечении кэша зависимость не устанавливалась. Сейчас я не рядом с монитором, но я посмотрел вашу ошибку, и похоже, что это ошибка в valgrind. Вы также можете попробовать установить libc версии 6 и посмотреть, поможет ли это. Я
обновлю
Да, похоже так. Если я добавлю sudo apt-get install -y libc6-dbg, то все будет работать нормально, но я тоже с того, что начал, потому что установка этого пакета занимает еще 30 секунд.
natiiix
@natiiix Кажется, что кэширование valgrind может оказаться более трудоемким, чем ожидалось, но, по крайней мере, это показывает, как кэширование может выполняться в Ubuntu. Глядя на зависимости valgrind, есть как минимум 6 зависимостей, и я думаю, что, вероятно, все они должны быть кэшированы, чтобы это работало.
smac89
4

Вы можете создать образ докера с valgrind предустановленным и запустить рабочий процесс на этом.

Создайте Dockerfileчто-то вроде:

FROM ubuntu

RUN apt-get install -y valgrind

Постройте его и отправьте в dockerhub:

docker build -t natiiix/valgrind .
docker push natiiix/valgrind

Затем используйте что-то вроде следующего в качестве рабочего процесса:

name: C Workflow

on: [push, pull_request]

jobs:
  build:
    container: natiiix/valgrind

    steps:
    - uses: actions/checkout@v1

    - name: make
      run: make

    - name: valgrind
      run: valgrind -v --leak-check=full --show-leak-kinds=all ./bin

Полностью не проверено, но вы поняли идею.

Дейвид
источник
Это очень интересная идея, но она как бы подрывает весь принцип, позволяющий GitHub Actions кэшировать среду / артефакты для будущих запусков, и вместо этого требует дополнительных усилий с моей стороны. С другой стороны, однажды сделанный, это, вероятно, может быть использовано довольно легко.
natiiix
1
Вы сами решаете, что лучше всего подходит для вас, или что требует наибольшего отклонения от вашей стороны ¯_ (ツ) _ / ¯
deivid