基于istio实现个人门户的双版本发布策略
目标
本文所述的方案旨在将我的个人门户由原来的单一版本发布策略改为包含一个预览版本和一个稳定版本的发布策略,以实现对于门户的修改,可以先发布为预览版,仅特定用户可以看到并进行测试。待到测试无误后,再作为稳定版本发布以供所有用户使用。
原本的发布方式:门户基于flutter构建,打包成docker镜像,以helm chart方式部署于k8s集群中,负载仅包含一个deployment。每次发布,更新该deployment的镜像tag,实现新版本的上线和旧版本的下线。
该方式的问题是如果新版本包含了未在开发阶段测试出的bug,将导致门户不可用。此时需要我尽快完成集群deployment的回滚,完成回滚前的时间将成为我的门户的不可用时间,可能影响用户体验。
方案
前提:istio部署完成,对门户微服务的上游服务开启了注入:由于我的门户服务使用了frp作为内网穿透工具,所以门户服务的直接客户端其实是frpc,因此本文并不会涉及到istio的gateway,只需要对门户服务本身和frpc开启了注入即可。
增加负载版本
在原本的发布方式中,同一时间线上仅包含一个deployment。现在需要增加一个deployment。二者一个作为稳定版,另一个作为预览版。此处的关键点在于两个deployment的pod标签选择器的设置:共享同一个app,但是使用不同的version
selector:
matchLabels:
app: "{{ .Chart.Name }}"
version: "{{ .Values.canaryVersion }}"
selector:
matchLabels:
app: "{{ .Chart.Name }}"
version: "{{ .Values.stableVersion }}"
istio相关CR
DestinationRule:和上一步的两个deployment的标签相匹配,定义两个destination
subsets:
- name: canary
labels:
version: {{ .Values.canaryVersion }}
- name: stable
labels:
version: {{ .Values.stableVersion }}
VirtualService:根据header选择路由到哪个destination
spec:
hosts:
- {{ .Values.host }}
http:
- match:
- headers:
version:
exact: canary
route:
- destination:
host: portal
subset: canary
- route:
- destination:
host: portal
subset: stable
Makefile
完成上述的helm template资源对象定义后,需要用makefile将上线的流程固定,以后即可无脑make实现两个版本的分别发布。
发布稳定版本:先对目标commit打tag,然后makefile会使用最新的tag作为稳定版本代码来源,基于该tag完成flutter构建、docker image构建、chart渲染、helm upgrade;类似的,发布预览版本时,以当前commit作为代码来源,由于此时稳定版本的tag并未改变,所以最后的helm upgrade仅更新了canary版本的imageVersion,不会影响稳定版本的服务。
canaryCommit:=$(shell git rev-parse --short main)
time:=$(shell date +"%Y%m%d-%H%M%S")
canaryTag=$(canaryCommit)-$(time)
stableTag=$(shell git describe --abbrev=0 --tags)
checkout_stable:
git checkout $(stableTag)
checkout_canary:
git checkout $(canaryCommit)
# flutter构建、docker镜像构建略
install_web:
helm upgrade -i --create-namespace -n $(namespace) portal \
--set registry=$(registry) \
--set stableVersion=$(stableTag) \
--set canaryVersion=$(canaryTag) \
./chart
效果
使用link1st/go-stress-testing: go (github.com)压测工具访问门户,观察kiali可以看到流量仅能走到稳定版本
在浏览器中安装header editor插件后为门户的域名增加VirtualService里配置的header:version=canary
后,可以看到流量全部走到了预览版
两种流量混合时的图如下
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。