基于 s3 的单页应用的一种纯前端灰度发布实现
为什么要做这个功能:
- 不用借助外部(native) 来修改入口 url, 整个灰度控制完全前端控制
- 控制线上发布风险
如何实现
去掉打包输出文件 index.html 上面的包含当前打包代码的静态 script 和 style 标签,改成动态读取远程配置文件,然后根据配置结果具体选择加载哪个版本.
具体实现细节
网页灰度整个过程分成三个步骤: 打包阶段,部署阶段和运行阶段.
打包阶段
为了给外部留有足够的迁移时间,项目同时保留了支持灰度发布的运行在 s3 上的新编译方式,以及传统的基于 k8s+ngnix 反向代理的老编译方式.
原来项目的打包输出目录如下:
新的打包输出目录
主要区别包含如下几点:
- 原来的
static
目录名称变更为根据当前 git 的 commit id 决定. - 新增 version.json 字段,其内容如下:
其中最重要的两个字段是rate
和 comment
, 这两个字段的用处将在后面的’运行阶段’详细说明.
- 原来 index.html 的 body 包含当前编译的打包代码:
这部分代码在新的 index.html 将不复存在,取而代之的是多出了一段 运行代码(后面运行阶段说明)
,以及在 commit id 文件夹下面多出来的 meta.json
文件. meta.json
文件如下:
也就是说原来内嵌在 index.html 里面的内容被移到了 meta.json
里面.
以上新编译的所有配置,均是通过修改 webpack 配置实现的. 由于当前项目使用了 create-react-app
模板,并且不建议 eject
项目避免后期维护困难.所以项目借助了 customize-cra
项目拓展 webpack 配置.
以下代码实现了修改 webpack 配置:
这里的 DEPLOY_TYPE
为 k8s 时表示老模式,s3 时表示新模式. 到这里说明了如何修改 webpack 配置输出新的编译目录. 接下来说明如何部署
部署阶段
因为当前项目是静态单页应用,所以部署到亚马逊 s3 相比如之前的 k8s,省去了 ngnix 反向代理. 而且用 s3 部署比 k8s 更加节约成本. 大致做法就是利用 aws-sdk 上传代码.
利用 s3 的存储方式后,网页的访问入口发生了变化. 而且由于缺少反向代理,前端必须使用 hash 路由
下面说明具体步骤:
- 下载远程的 version.json 内容并合并到本地的 version.json
- 为了防止灰度选择版本失败,线上部署始终会保留一份 latest 文件夹.方便当取不到 git comit 时能够安全回退
- 覆盖上传
运行阶段
运行代码的主要作用是读取远程的 version.json 文件,然后根据里面的 rate 字段在 [0-1]区间分配比例,之后通过 random 函数取一个随机值,看这个值最终落在哪个区间,之后读取选定的 version 里面的 meta.json 信息,动态拼接到 index.html 上面即可实现动态选择版本.
- 默认情况下灰度发布不生效,全部使用 latest 版本,这也是第一个步骤生成的 version.json 里面 rate 是 0 的原因(主要懒得配置..)
以下代码是直接写在项目 public 的 index.html 模板文件里面的,之后 html-webpack-plugin
插件会把里面的 PUBLIC_URL
和 DEPLOY_TYPE
替换为真实值.
好了,一篇流水账完成..