灰度发布介绍
灰度发布,又名金丝雀发布(canary release、canary launch 或 canary deployment ),是指在黑与白之间,能够平滑过渡的一种发布方式。是指在发布新版本的服务时,将部分流量引入新版本,如果新版本没有问题,再逐步将流量引入新版本,直至全部流量引入新版本。A/B 测试:灰度发布方法中的一种,将用户分为 AB 两组,然后收集他们的反馈效果,在 istio 中可以很方便的实现 A/B 测试。
部署测试应用
本地使用的 k3s 安装的 kubernetes 集群,使用 istioctl 安装的 istio:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
root@dev:~/istio-1.17.2# istioctl install --set profile=demo -y
root@dev:~/istio-1.17.2# kubectl label namespace default istio-injection=enabled
root@dev:~/istio-1.17.2# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
// reviews 服务有三个版本
root@dev:~/istio-1.17.2# kubectl get pods
NAME READY STATUS RESTARTS AGE
ratings-v1-b8f8fcf49-wkkx8 2/2 Running 0 96s
productpage-v1-d4f8dfd97-k5798 2/2 Running 0 96s
details-v1-6997d94bb9-5w7ns 2/2 Running 0 96s
reviews-v1-5896f547f5-ngqr4 2/2 Running 0 96s
reviews-v2-5d99885bc9-ncw2j 2/2 Running 0 96s
reviews-v3-589cb4d56c-59v4h 2/2 Running 0 96s
root@dev:~/istio-1.17.2# kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
root@dev:~/istio-1.17.2# kubectl get gateway
NAME AGE
bookinfo-gateway 4m8s
// 获取 host
root@dev:~# kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}'
172.19.52.61
// 获取 nodeport
root@dev:~# kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'
30871
|
通过测试访问“http://172.19.52.61:30871/productpage”可以看到服务正常运行了,并且多次刷新时,可以看到“Book Reviews”下面有不同的显示:
- v1 版本不会调用 ratings 服务。
- v2 版本会调用 ratings 服务,并使用 1 到 5 个黑色星形图标来显示评分信息。
- v3 版本会调用 ratings 服务,并使用 1 到 5 个红色星形图标来显示评分信息。
为 reviews 服务定义不同的版本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
|
路由到版本 1
要仅路由到 v1 版本的 review 服务,需要设置如下的 VirtualService:
1
2
3
4
5
6
7
8
9
10
11
12
|
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
|
此时访问页面,多次刷新可以看到“Book Reviews”只有 v1 版本的显示,查看 envoy 相关配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// gateway svc 中将 80 端口请求转发到 gateway pod 的 8080 端口,然后会转发到 productpage 服务 9080 端口
root@dev:~# istioctl pc route istio-ingressgateway-85c59bdcd9-wfb68.istio-system
NAME DOMAINS MATCH VIRTUAL SERVICE
http.8080 * /productpage bookinfo.default
// productpage 监听 9080
root@dev:~# istioctl pc listener productpage-v1-d4f8dfd97-k5798 --port 9080
ADDRESS PORT MATCH DESTINATION
0.0.0.0 9080 Trans: raw_buffer; App: http/1.1,h2c Route: 9080
// productpage 路由到 "outbound|9080|v1|reviews.default.svc.cluster.local"
root@dev:~# istioctl pc route productpage-v1-d4f8dfd97-k5798 --name 9080
NAME DOMAINS MATCH VIRTUAL SERVICE
9080 reviews, reviews.default + 1 more... /* reviews.default
// cluster 对应的 endpoints "10.42.0.14"即为 v1 版本的 review 服务的 pods
root@dev:~# istioctl pc endpoints productpage-v1-d4f8dfd97-k5798 --cluster "outbound|9080|v1|reviews.default.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.42.0.14:9080 HEALTHY OK outbound|9080|v1|reviews.default.svc.cluster.local
|
基于用户身份的路由
路由配置中,可以将特定用户的所有流量路由到特定服务版本。下面的例子,将来自名为 Jason 的用户的流量将被路由到服务 reviews:v2。
因为 productpage 在到 reviews 服务的 HTTP 请求中都增加了一个 end-user 请求头,因此以用户 Jason 登录时,将会展示黑色星形图标的评分信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
|
流量转移
在 VirtualService 通过设置不同 subset 的权重大小,可以控制流量路由比例,实现流量从微服务的一个版本逐步迁移到另一个版本。下面例子中,会把 50% 的流量发送到 reviews:v1,50% 的流量发送到 reviews:v3:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 50
- destination:
host: reviews
subset: v3
weight: 50
|
灰度发布配置说明
主要涉及到 VirtualService 中的 HTTPRoute、HTTPMatchRequest、HTTPRouteDestination 字段,HTTPRoute 中重点字段说明:
字段 |
类型 |
说明 |
必填 |
name |
string |
路由名称,用于调试 |
否 |
match |
HTTPMatchRequest[] |
匹配的条件,单个匹配块里面是与的关系,多个匹配块列表是或的关系 |
否 |
route |
HTTPRouteDestination[] |
要么返回直接响应,要么返回重定向。转发到服务的某个版本,权重决定了流量的比例 |
否 |
HTTPMatchRequest 重点字段说明如下,其中 uri、scheme、method、authority 都是大小写敏感,格式可以是全路径、前缀、正则方式:
字段 |
类型 |
说明 |
必填 |
uri |
StringMatch |
匹配的 url, |
否 |
scheme |
StringMatch |
匹配的 url scheme |
否 |
method |
StringMatch |
匹配的 url method |
否 |
authority |
StringMatch |
匹配的 url,说明见 彻底了解 URL |
否 |
headers |
map<string, StringMatch> |
必须小写,用连字符作为分隔符,如果只指定了头的名称,但值为空,那么将检查头是否存在 |
否 |
port |
uint32 |
指定被寻址的主机上的端口 |
否 |
queryParams |
map<string, StringMatch> |
匹配的查询参数 |
否 |
withoutHeaders |
map<string, StringMatch> |
跟 headers 相反,匹配没有某些 header |
否 |
HTTPRouteDestination 字段说明如下:
字段 |
类型 |
说明 |
必填 |
destination |
Destination |
转发的目的服务 |
是 |
weight |
int32 |
转发流量权重 |
否 |
headers |
StringMatch |
匹配的 url, |
否 |
headers |
Headers |
header 处理规则,用于请求和响应时增加或者删除某个 header 字段 |
否 |
参考