Table of contents
展开目录
原理
基于 Nginx Ingress Controller
使用 canary-*
注解完成前端基线与灰度的流量转发:
- 一部分用户继续使用老版本的服务,
- 将一部分用户的流量切换到新版本,
- 如果新版本运行稳定,则逐步将所有用户迁移到新版本。
nginx.ingress.kubernetes.io/canary-by-cookie
- 👍
canary-* Annotation
也是社区官方实现的灰度发布方式。
- 表示基于 Cookie 进行灰度发布。
- Cookie 名称的特殊取值:
- always:无论什么情况下,流量均会进入灰度服务。
- never:无论什么情况下,流量均不会进入灰度服务。
- 只要存在该 Cookie 名称,都会进行流量转发。
容器化
前端需要 dockerized
,这样才能变成服务,而后让 ingress
将流量打入前端的 Service
。
⚡ 额外小心
前端容器化后,每次发布新版本会变成全量发布,而不是以往的增量发布。
现在的 SPA
项目,打包构建后,
为了加快首屏的展示速度,都会将路由组件打包成数个 module.chunk.js
,
由统一的主入口 bundle.chunk.js
来控制加载当前路由的 chunk.js
。
上次发版的构建产物
本次发版的构建产物
由于index.html
文件名没有发生变化,发版成功后,
客户端访问时,会使用缓存,即上个版本缓存的 index.html
,此时仍然会加载 bundle.old.js
,
路由匹配后,bundle.old.js
会动态添加 <script src="module.old.js" />
。
这也是某些场景,前端发布后新功能没有生效的原因。
当容器化发布后,旧的文件会被全部移除,
module.old.js
已经不存在,但又要加载它,浏览器会白屏,控制台会报错。
缓存的处理
为了避免上述 SPA
应用增量发布的问题,只需要做一件事情:HTML 文件不缓存,缓存其他静态文件
html
不缓存
静态资源文件 缓存 30 天
HTML 文件非常小,通常只有 1~2kb,每次请求并吞吐最新的文件也不会太消耗带宽。
<meta />
标签控制缓存
仅仅通过 <meta />
标签仍然是不够的,还需要完善 nginx.conf
:
-
no-store
: 不要在浏览器中缓存/存储任何响应。
-
no-cache
: 每次(每个请求)都向服务器询问“我可以向用户显示我拥有的缓存内容吗?”
-
must-revalidate
: 一旦缓存过期,就不再提供旧的资源,询问服务器并重新验证。
Dockerfile
选用 *-alpine
版本的镜像,可以极大缩小镜像体积
本地调试,创建容器并运行项目
基线与灰度
工作流
master
分支用于发布基线
master-gray
分支用于发布灰度
master-gray
≥ master
- Jenkins 创建
prod job
与 prod-gray job
环境切换
一部分用户继续使用老版本的服务(基线),一部分用户的流量切换到新版本(灰度)
灰度要精确到用户级别,那么最好的方式便是提供一个 API 让前端调用,
静态资源层 通过 cookie: env-gray=always
,由 ingress
将流量转发至 prod
或 prod-gray
。
cookie 不存在灰度标识,流量转发至基线:
cookie 存在灰度标识,流量转发至灰度:
API 层 通过请求头增加灰度标识,来告知 API 按 prod
还是 prod-gray
处理。
后端打通基线与灰度,比前端复杂更多,阿波罗配置、字典表、权限等等一系列的配置或业务需要做处理,
除了在请求头中增加 API 的灰度标识,也可以结合自身项目实际场景替换。