如何在GitHub操作中缓存步骤?

时间:2019-03-11 21:32:03

标签: github github-actions

说我有一个包含两个步骤的GitHub动作工作流。

  1. 下载并编译应用程序的依赖项。
  2. 编译并测试我的应用程序

我的依赖项很少更改,并且可以安全地缓存已编译的依赖项,直到下次更改指定其版本的锁定文件为止。

是否可以保存第一步的结果,以便将来的工作流可以跳过该步骤?

8 个答案:

答案 0 :(得分:20)

现在通过cache action本地支持缓存。它可以跨存储库中的作业和工作流工作。另请参阅:https://help.github.com/en/actions/automating-your-workflow-with-github-actions/caching-dependencies-to-speed-up-workflows

考虑following example

name: GitHub Actions Workflow with NPM cache

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Use Node.js 8
      uses: actions/setup-node@v1
      with:
        node-version: 8.x
    - name: Cache NPM dependencies
      uses: actions/cache@v1
      with:
        path: node_modules
        key: ${{ runner.OS }}-npm-cache-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.OS }}-npm-cache-
    - name: Install NPM dependencies
      run: npm install

path操作的keycache参数用于标识缓存。

可选的restore-keys用于可能的回退到部分匹配(即,如果package-lock.json更改,将使用以前的缓存)。

在使用npm-cache后备并且存在多个不同的缓存(例如JS程序包和系统程序包)的情况下,使用某些ID(在此示例中为restore-keys)前缀键非常有用。否则,一个缓存可能会退回到另一个不相关的缓存。同样,使用操作系统前缀在使用矩阵构建时很有用,这样就不会混淆不同系统的缓存。


旧答案:

当前无法进行本地缓存,expected to be implemented by mid-November 2019

您可以使用工件(12)按照GH Community board的建议在作业之间(在1个工作流程中)移动目录。但是,这是doesn't work across workflows

答案 1 :(得分:5)

在当前GitHub Actions版本(2019年8月23日)上无法使用缓存文件。在circleCi上是可能的。

以下是我的测试:

在作业上写文件,尝试在下一个继续阅读

使用了test file

1)GITHUB_WORKSPACE上写
我的路径:/ home / runner / work / github-actions-test / github-actions-test)
结果:第一份工作可写且可读,但第二份工作为空 Action link

2)写在/github/home
我的路径:/ github / home
结果:cannot access '/github/home/ Action link

3)/home上写
我的路径:/ home
结果:touch: cannot touch '/home/myFile.txt': Permission denied
Action link

结论

不能在任何文件夹的作业之间持久保存文件

答案 2 :(得分:2)

  

我的依存关系很少更改,可以安全地缓存已编译的依存关系,直到我下次更改指定其版本的锁文件为止。是否可以保存第一步的结果,以便将来的工作流可以跳过该步?

第一步是:

  

下载并编译我的应用程序的依赖项。

GitHub Actions本身不会为您执行此操作。我能给您的唯一建议是您遵守Docker最佳实践,以确保如果Actions确实利用了docker缓存,图像可以重新使用而不是重新构建。参见:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache

  

构建映像时,Docker逐步执行Dockerfile中的指令,并按指定的顺序执行每个指令。在检查每条指令时,Docker会在其缓存中寻找一个可以重用的现有映像,而不是创建一个新的(重复的)映像。

这还意味着GitHub Actions的底层系统可以/将利用Docker缓存。

但是,诸如编译之类的事情,Docker将无法使用缓存机制,因此,如果您急需此内容,我建议您考虑得很好。另一种方法是从工件存储(Nexus,NPM,MavenCentral)下载编译/处理的文件,以跳过该步骤。您必须权衡在此基础上增加的收益与复杂性之间的关系。

答案 3 :(得分:2)

actions/cache现在可以进行缓存了。请参见存储库以获取full list of examples

例如节点-npm

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

还有关于缓存限制的说明。

  

单个缓存限制为400MB,存储库最多可以包含2GB缓存。达到2GB限制后,将根据上次访问缓存的时间驱逐较早的缓存。上周未访问的缓存也将被驱逐。

答案 4 :(得分:2)

答案 5 :(得分:2)

cache操作只能缓存文件夹的内容。因此,如果有这样的文件夹,则可以通过缓存它来赢得一些时间。

例如,如果您使用一些虚构的package-installer(例如Python的pipvirtualenv,或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. 稍后,我们使用该名称进行条件执行:ifsteps.cache-packages.outputs.cache-hit != 'true'
  3. 为缓存操作提供要缓存的文件夹的路径:./packages/
  4. 缓存键:取决于输入文件的哈希值。也就是说,如果packages.txt文件有任何更改,则将重建缓存。
  5. 第二步,程序包安装程序,仅在没有缓存的情况下运行

对于virtualenv的用户:如果需要激活某些Shell环境,则必须在每个步骤中都进行此操作。像这样:

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

答案 6 :(得分:1)

如果您在http://caniuse.com/中使用Docker在WorkFlows中使用,则GitHub现在支持通过@peterevans answered操作进行缓存,但这有其局限性。

因此,您可能会发现有用的cache绕过GitHub的操作限制。 this action中的更多信息。

  

免责声明:我在GitHub正式创建缓存之前就创建了支持缓存的操作,但由于其简单性和灵活性,我仍然使用它。

答案 7 :(得分:0)

我将总结两个选项:

  1. 缓存
  2. Docker

缓存

您可以在工作流程中添加命令以缓存目录。到达该步骤后,它将检查您指定的目录是否先前已保存。如果是这样,它将抓住它。如果没有,它不会。然后在进一步的步骤中,编写检查以查看是否存在缓存的数据。例如,假设您正在编译一些很大的并没有太大变化的依赖项。您可以在工作流程的开始添加一个缓存步骤,然后在目录内容不存在的情况下添加一个步骤。第一次运行时,找不到文件,但随后会找到文件,因此您的工作流程将运行得更快。

在后台,GitHub将目录的zip上传到github自己的AWS存储中。他们会清除超过一周的旧内容,或者清除2GB以上的内容。

此技术的一些缺点是它仅保存目录。因此,如果您安装到/ usr / bin,则必须对其进行缓存!那会很尴尬。相反,您应该安装到$ home / .local中,并使用echo set-env将其添加到您的路径中。

Docker

Docker稍微复杂一点,这意味着您必须拥有一个dockerhub帐户并立即管理两件事。但是它功能更强大。您不仅可以保存目录,还可以保存整个计算机!您要做的就是制作一个Dockerfile,其中将包含您的所有依赖项,例如apt-get和python pip行,甚至是长时间编译。然后,您将构建该docker映像并将其发布在dockerhub上。最后,将测试设置为在该新docker映像上运行,而不是在ubuntu-latest上运行。从现在开始,无需安装依赖项,而只需下载映像即可。

您可以通过将该Dockerfile与该项目存储在同一GitHub存储库中进一步自动化操作,然后编写包含以下步骤的作业,该步骤将下载最新的Docker映像,必要时仅重建更改的步骤,然后上载到dockerhub。然后是一项“需要”该工作并使用图像的工作。这样,您的工作流将既可以根据需要更新docker映像,也可以使用它。

缺点是您的部门将放在一个文件,Dockerfile和工作流程中的测试中,因此它们并没有在一起。另外,如果下载映像的时间大于建立依赖项的时间,那么这是一个糟糕的选择。


我认为每个人都有其优点和缺点。缓存仅适用于非常简单的内容,例如编译为.local。如果您需要更广泛的功能,则Docker是最强大的。