上篇文章测试了开源版Higress暂不支持全链路灰度发布的功能,但是基本的灰度发布还是支持的,下面就实际测试一下。
金丝雀发布
部署demo
官方文档:https://higress.cn/docs/latest/user/kruise-rollout/
示例中的镜像registry.cn-hangzhou.aliyuncs.com/mse-ingress/version:v1
已经下载不到了,我重新写了一个,程序运行在80端口,访问/version
路径会返回version: v1
。
cat main.go
package main
import (
"fmt"
"log"
"net/http"
)
func versionHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "version: v1")
}
func main() {
http.HandleFunc("/version", versionHandler)
log.Println("Starting server on port 80")
log.Fatal(http.ListenAndServe(":80", nil))
}
编写Dockerfile。
cat Dockerfile
FROM golang:1.18 as builder
WORKDIR /app
COPY go.mod ./
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/main .
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 80
CMD ["./main"]
构建镜像。
docker build -t version:v1 .
创建服务。
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
spec:
replicas: 3
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
containers:
- name: main
image: version:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: demo
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: demo
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: higress
rules:
- http:
paths:
- backend:
service:
name: demo
port:
number: 80
path: /version
pathType: Exact
host: demo.com
创建rollout
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollouts-demo
spec:
objectRef:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: demo
strategy:
canary:
steps:
- weight: 10
pause: {}
replicas: 1
- weight: 30
pause: {}
replicas: 2
trafficRoutings:
- service: demo
ingress:
classType: higress
name: demo
- 其中
workloadRef
旁路式的选择需要 Rollout 的 Workload,此处为 Deployment,支持其他 Workload(如CloneSet、DaemonSet)。 - 其中
canary.Steps
定义了整个 Rollout 过程一共分为3批,其中第一批只灰度一个新版本 Pod,并且 routing 10% 流量到新版本 Pod,并且需要人工确认是否继续发布;第二批只灰度两个新版本 Pod,并且 routing 30%流量到新版本 Pod,并且需要人工确认是否继续发布;最后一批,无需定义,即全量发布。 - 其中
trafficRoutings
指向了需要感知流量规则的资源,kruise rollout会自动更新相关资源,实时反射目标流量规则。
修改镜像
修改上面的main.go,把version: v1
换成version: v2
,重新构建镜像版本为version:v2
。
当前执行完第一批发布,并且出于暂停状态,需要人工确认才能继续下一批次发布。并且创建了一个新的deployment demo-ggplk
。
测试流量。
for i in {1..10}; do curl http://nodeip:31779/version -H "host: demo.com"; done
有10%流量访问v2版本。
继续发布
kubectl-kruise rollout approve rollout/rollouts-demo
创建了2个新版本pod。
测试流量。
全量发布
在新版本pod全部启动后,再删除deployment demo-ggplk
,完成发布。
流量全部转发至新版本。
A/B Test
只有匹配特定规则的请求才会被引流到新版本,常见的做法包括基于Http Header和Cookie。
回滚环境
删除上面的rollout,把上面的v2版本回滚到v1版本。
创建rollout
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollouts-header
spec:
objectRef:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: demo
strategy:
canary:
steps:
- matches:
- headers:
- name: user-agent
value: android
pause: {}
replicas: 1
trafficRoutings:
- service: demo
ingress:
classType: higress
name: demo
其中 canary.Steps
定义了整个 Rollout 过程一共分为2批,其中第一批只灰度一个新版本 Pod,并且将带有 HTTP Header user-agent: android
(即安卓用户)的流量 routing 到新版本 Pod,并且需要人工确认是否继续发布;最后一批,无需定义,即全量发布。
修改镜像
修改镜像版本为v2。
测试流量
curl http://nodeip:31779/version -H "host: demo.com" -H "user-agent: android"
来自安卓的流量路由到v2版本,非安卓的流量路由到v1版本。