目录

使用 GitHub Actions Cache 加快 Workflow

简单讲讲 GitHub Actions 的 Cache 功能,使用方式,以及探讨浅层的设计思想。

虽然本文是我博客中为数不多的「教程」类文章,但我还是会侧重逻辑与思考的角度来讲述。详细教程请查看,GitHub Actions Cache 官方文档

什么是 GitHub Actions Cache

缓存被广泛运用于计算机的各个领域,核心都是 用某种方式,替换了某个高耗时的原行为

而 GitHub Actions 也推出了 Cache 功能,用了「缓存特定文件」的方式,解决了「重复下载依赖」的高耗时问题。同时这个「依赖」也是抽象的,除了狭义上的依赖,还可以是任何需要缓存的文件。(毕竟 Linux 一切皆文件,笑,那是不是能缓存一切哈哈哈)。

GitHub Actions 的 Cache 的核心用法(抽象层面)

前面提到,本质上就是「缓存特定文件」。所以 GitHub Actions 本质上就是:

  • 使用 key 来标识缓存的唯一性
  • 使用 path 来标识要被缓存/已经被缓存的文件

大道至简。也正是因为足够简单,所以才能适应各种场景。

我们可以再稍微具体一点,GitHub Actions Cache 的 actions 名字叫 actions/cache@v3,当我们在 workflowuseactions/cache@v3 时,我们大概需要提供两个参数:

  • key
  • path

当 GitHub Actions 执行到这一步时,一共有两种情况:

  • (缓存命中)发现 Actions 系统内已经有了 key 对应的缓存,就直接将缓存文件下载到 path 对应的目录下
  • (缓存未命中)当工作流结束时,将 path 对应的目录下的文件打包上传到 Actions 系统内,以 key 为名字进行缓存

GitHub Actions 的 Cache 的核心用法(具体层面)

这是一个官方的例子:

- name: Cache node modules
  id: cache-npm
  uses: actions/cache@v3
  env:
    cache-name: cache-node-modules
  with:
    # npm cache files are stored in `~/.npm` on Linux/macOS
    path: ~/.npm
    key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-build-${{ env.cache-name }}-
      ${{ runner.os }}-build-
      ${{ runner.os }}-      

上面的代码实现了对 Node 依赖的缓存。

相信读者基本都能猜个八九不离十,我只讲一些细节:

  1. key 本身是一个变量,基于系统的架构,以及 package-lock.json 文件的 hash 值,来保证缓存的唯一性
  2. restore-keys 是一个数组,当缓存未命中时,会依次尝试这些 key,直到找到一个命中的缓存,或者全部尝试完毕。示例代码中这么写,能够尽可能地复用相似的缓存。

Setup-* 系列

读者可能迫不及待地想修改自己的 GitHub Actions 了,毕竟几乎所有的 CI 第一步都是装编译环境与依赖。

不要急哈哈哈, 官方最新的 setup-* 系列,已经默认开启了 cache,比如 setup-go@v4,使用 go.sum hash 作为 key 的一部分。

我们只要确保 setup-* 的大版本号是最新的即可,不需要手动去实现。已支持的包管理器的 Actions 列表

依赖存在与否/是否需要执行相关代码的判断

我们可以发现,GitHub Actions Cache 做的只是,将相关的依赖下载到对应目录(比直接从网络下载快很多),即使缓存命中了,它也并不会使你的 npm install 命令直接跳过。而是由 npm install 命令本身,在执行时发现相关依赖已经存在,不需要再下载。

(当然,我们也可以做得更极端。actions/cache 有一个 output 会标识缓存是否命中,我们可以结合 actionsif 语法,来判断是否需要执行相关代码。官方示例)

缓存其他依赖项

有的时候,我们运行 CI 会需要一些额外的二进制文件。一种方法是打成一个 Docker 镜像,另外一种方法就是使用 GitHub Actions Cache,效率会更高。

我们可以建一个 cache 目录,将需要的二进制文件放在里面,然后使用 actions/cache 缓存这个目录即可。对于 key 的设置,可以把安装命令放在同一个文件中,然后使用 hashFiles 来计算 key

对 GitHub Actions Cache 设计的浅层思考

其实前面已经说了:

  1. GitHub Actions Cache 的核心就是「缓存特定文件」,来取代原先的复杂的分析、外部网络下载、编译带来的高耗时。
  2. GitHub Actions Cache 并没有通过「缓存命中」来直接跳过相关代码,而是简单地通过 key 来标识缓存的唯一性。后续代码是否执行,交由特定的命令自行判断。同时也提供了 output 来判断缓存是否命中。
  3. 提供了基于 restore-keys 的缓存回退机制,在发生了微小变更时,也能尽可能地去使用旧的缓存。

GitHub Actions Cache 的一些限制与细节

关于分支的限制,UI 操作(查看、删除已有缓存等),回收策略,其他细节等,请看官方文档

(本文贴的官方文档都是英文,官方文档右上角能切换成中文。但是中文版写得太烂了,所以我才写了个相对来说更「说人话」的小教程。)