要搞这玩意儿的主要原因是因为项目需求,频繁新版本,一发新版本,程序崩了,用户炸了,领导火了。
虽然这个锅主要是开发和测试来背,不过如果搞的次数多了,运维也要被牵连进去的。
毕竟,项目顺利才是所有人所希望看到的。
有人说,这应该从流程上去堵住这种漏洞。嗯,说的很对!(省略5w 字吐槽)
就这样,找了几种解决方案,最终找到了istio。
istio 可以用来干很多事情,不过其他的功能我们暂时用不到。
https://istio.io/latest/docs
请查看官网或者百度。。。
首先,我们的目标就是如果我们发布了新版本,那么就让一小部分的人先用用,如果小部分的人用的没问题,那就大规模推广。(嗯,很符合互联网的套路阿!)
原理性的东西太枯燥,大家感兴趣的可以去翻源码和官方文档。
这里我讲讲自己的理解。
我拿 nginx
做一个类比。配置istio
就像配置nginx
一样,需要配置匹配的uri
,不同的是,它可以通过解析http
包,拥有了更丰富的规则来实现路由重定向。
一个典型的配置如下:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: pos-istio
spec:
gateways:
- prod-gateway
hosts:
- '*'
http:
- match:
- headers:
deptCode:
exact: 30080
uri:
prefix: /pos
route:
- destination:
host: pos-istio
subset: master
- match:
- uri:
prefix: /pos
route:
- destination:
host: pos-istio
subset: canary
这里的 http match
就是istio
比nginx
新增的功能点了。
http header
中的deptCode
等于30080
且访问路径是/pos
那么就访问某个后端服务,这里叫master
/pos
那么就访问某个后端服务,这里叫canary
翻译成nginx
配置就类似
location /pos {
proxypass: master
}
# 当然,这里没有经过特殊处理的 nginx 是无法通过解析 http 请求头来完成对应规则的匹配的。
location /pos {
proxypass: canary
}
有了大概的了解之后,我们再看看下面几个概念,了解这些概念之后,基本上配置istio
就没什么问题了。
这里的
k8s-service
就是K8S
内的service
的概念,因为要和istio
内的virtual-service
的概念做区分。
ISTIO
也支持在其他平台内运行,但是最匹配的还是在K8S
环境内运行。
既然是在K8S
的环境内运行,istio
就避免不了要和K8S
相关的概念打交道。
我们是使用helm3
来部署应用的,部署的方式都是deploymnets
。当我们需要上istio
的时候,我们就需要两个charts
,我们分别称之为 pos-master
和pos-canary
。
使用默认的charts
会自动生成对应的文件夹名字的k8s service
。每个service
的选择器都会自动选择该depoyment
内的pod
。
因为我们要通过
ISTIO
定位到两个版本的部署,ISTIO
定义app
是以K8S Service
作为选择标准,所以,我们需要一个K8S Service
,而它的选择器是能够同时选择两个不同的版本。
因此,我们在helm charts
中的deployment.yml
文件中添加两个标签label
appName
version
其中appName
用它来作为新建的K8S Service
选择器的标签,version
作为DestnationRule
中区分不同版本的参考值。
这里的pos-istio
就表示的是VR
。它指向两个部署,这两个部署的含义是在 DR
中定义。
典型的配置如下,含义在上文已经解释过。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: pos-istio
spec:
gateways:
- prod-gateway
hosts:
- '*'
http:
- match:
- headers:
deptCode:
exact: 30080
uri:
prefix: /pos
route:
- destination:
host: pos-istio
subset: master
- match:
- uri:
prefix: /pos
route:
- destination:
host: pos-istio
subset: canary
这个文件的含义就是将K8S Service
中label
为version=2020.08.27.001
的部署命名为master
版本,另外那个命名为canary
这些命名
master
canary
最终在VR
文件中被引用。
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: pos-istio
spec:
host: pos-istio
subsets:
- name: master
labels:
version: 2020.08.27.001
- name: canary
labels:
version: 2020.08.27.002
如果没有域名的话,一个集群只能有一个Gateway
,它的典型配置如下:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: sinopec-gateway
spec:
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
如果有域名,hosts
中的*
可以改为域名地址,可以多个,类似nginx
中的ServiceName
。
以pos
为例,首次发布的流程如下:
2
个文件夹,分别是pos
pos-canary
。value.yml
添加参数appNameForIstio
。deployment.yml
添加 appName
和 version
的labels
,使用helm install
部署两个版本。k8s service
供后续的istio
使用,selector
选择器就是前面两个步骤定义的 appName
。dr
文件,selector
选择器是刚刚手工创建的k8s service
,通过第三步设定的version
命名两个版本,一个是master
版本,一个是canary
版本。vr
文件,设定两个策略,匹配我们自定义的http header
就走canary
版本,否则走master
版本。Andorid
应用设定的api
地址,需要是istio-ingress-controller
网关的地址。(kubectl get svc -n istio-system
得到的istio-ingressgateway
的网关端口)。vr
文件,把原来需要导入到canary
版本的流量,全部导入master
版本。(如:原来的规则是 deptCode=30080
走canary
,把条件改成deptCode=xxxxx
,因为条件不匹配,所以所有的流量全部都会走master
。)dr
文件中canary
版本的版本号信息为需要更新的最新版本。canary
的charts
中的values.yml
文件的image tag
值,upgrade
该应用。canary
部署成功后,将vr
中的规则改回正确的规则,特定的用户将使用最新的canary
版本。canary
版本发布2
天后,如果没有重大漏洞,周四
修改master
版本charts
中的values.yml
文件的image tag
值,upgrade
该应用。欢迎大家留言交流!