此页面需要javascript支持,请在浏览器中启用javascript

使用 Github Actions 对 Serverless Framework 进行持续化集成

serverless
jamstack
阅读 

前言

不熟悉 jamstack 的朋友可以先看一下这篇文章 什么是jamstack

笔者本来想写一篇 Jamstack 实战,技术上主要是以 SSG + COS + CDN + Serverless Framework + GitHub Actions 来实现的

然而发现内容有点多,主要分为以下几块:

  • 前端的框架预渲染和静态生成
  • 对象存储源站和内容分发网络
  • Serverless Components website 组件与 其他的后台服务组件
  • 使用 GitHub Actions 做持续集成

感觉每一个都可以好好的讲讲,都写在一篇文章里,就像蜻蜓点水

故此篇文章,主要介绍的是其中的 CI/CD 部分,即 Serverless Framework 如何使用 GitHub Actions 进行持续化集成

技术栈介绍

  • SSG: 任意的静态网站生成框架 or Raw Html 都可以,笔者在此使用的是 Nuxt.js ,当然 Next.js , Gatsby 都是非常优秀的选择,不需要灵活做自定义的,也可以去选择像 HexoVuePress 这类的框架

  • COS: 静态网站的源站,腾讯云对象存储

  • CDN: 腾讯云的内容分发网络

  • Serverless Framework: 在国内可以直接使用 tencent-website 组件,去快速部署和管理我们的 spa/ssg 网站,它也能够对我们的 COSCDN 进行管理。 后台服务也可以使用其他的组件进行部署和管理。

  • GitHub Actions: 功能强大,在这里暂且让它负责 CI/CD 的工作

思路

首先,从普通部署的视角看起

本地的前端静态网站是如何进行部署的呢?

我们把步骤拆解一下:

  • ①: 首先先去 生成静态网站
  • ②: 上传我们的 静态网站 代码到 COS 并设置为静态网站,同时指定它的 history fallback
  • ③: 设置 CDN 加速域名,假如已经设置完成,则再次部署时需要去刷新节点,让变更的资源强制过期

这几步,映射到我们技术栈的代码中,实际上就做 2 件事

nuxt generateserverless deploy

实践

接下来顺着刚刚的思路,开始想象一个 干净的 的 linux docker 容器中,需要哪些前置条件来支撑部署这个行为呢?

显然,nodejs 环境是必须安装的,serverless framework 也是需要的, 而 yarn 就看个人喜好了

笔者个人比较喜欢使用 yarn.lock 的 文件 hash 值作为 cache key 的一部分,于是 yarn 在此处我也安装了

于是就很容易写出以下的流程:

setup-node
// 限定一下 yarn 的版本
npm install -g yarn@^1.x
// 安装依赖包 npm ci 同理
yarn --prod
yarn add -D @serverless/components
// 生成与部署 npx 同理
yarn generate
yarn components deploy

这里为什么安装了 @serverless/components 可以见 @serverless/components 代码简析 这篇文章

然而 , 按照这个流程写 Github Actions 的 Yaml 还是行不通的

因为容器内的 serverless framework ,缺少云厂商的授权

此时呢,就可以把我们的 TENCENT_SECRET_IDTENCENT_SECRET_KEY 写入项目仓库中的 Actions secrets

具体操作可以使用,仓库的 Settings > Secrets > New repository secret 菜单

这种方式可以保护我们的秘钥, 见 详细文档
重要:一定要保护好我们的秘钥!!! 不要显示在 action 的输出里 !!!

因为从本质上来说使用 Serverless Framework .env 的部署方式,其实就是环境变量的部署方式

所以我们给 action 中的 env 直接赋值也是可以的,即

      - name: Serverless deploy
        shell: bash
        env:
          TENCENT_SECRET_ID: ${{ secrets.TENCENT_SECRET_ID }}
          TENCENT_SECRET_KEY: ${{ secrets.TENCENT_SECRET_KEY }}
        run: yarn components deploy
          

部署失败?

然而此时,会发现 去执行 yarn components deploy 部署,还是会部署失败,还提醒我们,需要 serverless login , 难道我们授权的腾讯云凭证不起作用?

其实并非如此,因为之前做 源码简析 的时候,也说过,国内国外跑的是不同的命令,且请求的也是不同的域名,判断的方式,在部署的时候,主要依靠 isChinaUser 这个方法来区分

我们来看看这个方法都做了什么?

const isChinaUser = () => {
  let result;
  if (
    process.env.SERVERLESS_PLATFORM_VENDOR === 'tencent' ||
    process.env.SLS_GEO_LOCATION === 'cn'
  ) {
    result = true;
  } else if (process.env.SERVERLESS_PLATFORM_VENDOR === 'aws') {
    result = false;
  } else {
    result = new Intl.DateTimeFormat('en', { timeZoneName: 'long' })
      .format()
      .includes('China Standard Time');
  }
  return result;
};

从代码可知,我们可以注入环境变量的方式 , 来改变 isChinaUser 的判断逻辑结果,而且因为Github 的容器啊,默认时区其实都是UTC,所以会导致Intl.DateTimeFormat这种判断失败。

那么就简单了,我们只需要部署时,在 env 中加一行 SERVERLESS_PLATFORM_VENDOR: tencent

        env:
          TENCENT_SECRET_ID: ${{ secrets.TENCENT_SECRET_ID }}
          TENCENT_SECRET_KEY: ${{ secrets.TENCENT_SECRET_KEY }}
          SERVERLESS_PLATFORM_VENDOR: tencent

就可以顺利的部署了成功了

demo在此

进阶

缓存

我们可以利用 actions/cache@v2yarn cache dir 中的包给缓存起来

这样能够大大加速 yarn 安装包的一个时间

缓存的 key,可以利用提交的 yarn.lock 文件的 hash 值组合而成的一个键, package-lock.json 同理

具体配置项见 actions/cache

时区

由于 容器默认时区是 UTC, 而中国属于 东八区 UTC+8,也就是 Asia/Shanghai , 假如我们不预先设置为这个时区,就会导致在构建打包时,nodejs的时间产生问题, 进而影响到我们打包工具。

这里就可以使用 szenius/set-timezone@v1.0 这个 Action

只需要把 runner os 的时区设置为 Asia/Shanghai, 打包时时区问题就解决了

样例

样例在此

总结

其实所有的 Serverless Framework 的组件,都可以通过这种方式,进行持续化集成。

这块我这篇文章,写的还是比较入门的,项目场景也很简单。

如果有其他更好的解决方案,也欢迎一起进行探讨交流。

© 2021 icebreaker 苏ICP备19002675号-2
version:1.2.2